~cjwatson/launchpad-buildd/extended-snap-status

« back to all changes in this revision

Viewing changes to sbuild

  • Committer: Adam Conrad
  • Date: 2013-10-10 15:02:24 UTC
  • Revision ID: adconrad@0c3.net-20131010150224-5myle0putd2tcstp
Mount /dev/pts with -o gid=5,mode=620 to avoid needing pt_chown.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#! /usr/bin/perl
 
2
#
 
3
# sbuild: build packages, obeying source dependencies
 
4
# Copyright (C) 1998-2000 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
 
5
#
 
6
# This program is free software; you can redistribute it and/or
 
7
# modify it under the terms of the GNU General Public License as
 
8
# published by the Free Software Foundation; either version 2 of the
 
9
# License, or (at your option) any later version.
 
10
#
 
11
# This program is distributed in the hope that it will be useful, but
 
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
# General Public License for more details.
 
15
#
 
16
# You should have received a copy of the GNU General Public License
 
17
# along with this program; if not, write to the Free Software
 
18
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
19
#
 
20
# $Id: sbuild,v 1.170 2002/10/10 18:50:44 rnhodek Exp $
 
21
#
 
22
# $Log: sbuild,v $
 
23
# Revision 1.170  2002/10/10 18:50:44  rnhodek
 
24
# Security/accepted autobuilding patch by Ryan.
 
25
#
 
26
# Revision 1.169  2002/03/11 09:49:55  rnhodek
 
27
# chroot_apt_options: don't just set Dir::Etc::sourcelist, but whole
 
28
# Dir::Etc, to avoid new preferences.
 
29
#
 
30
# Revision 1.168  2002/02/07 09:12:25  rnhodek
 
31
# Fixed sudo call for running scripts.
 
32
#
 
33
# Revision 1.167  2002/01/22 08:53:10  rnhodek
 
34
# Use capitalized "Noninteractive" das DEBIAN_FRONTENT.
 
35
#
 
36
# Revision 1.166  2001/11/08 09:32:10  rnhodek
 
37
# fetch_source_file: in case of apt, need to pass up a $dscfile with
 
38
# epoch stripped.
 
39
#
 
40
# Revision 1.165  2001/11/07 18:04:31  rnhodek
 
41
# Argl.. I should learn perl first :)
 
42
#
 
43
# Revision 1.164  2001/11/07 09:25:59  rnhodek
 
44
# fetch_source_files: after apt-get, fix $dscfile not to contain epoch.
 
45
#
 
46
# Revision 1.163  2001/11/06 15:11:24  rnhodek
 
47
# fetch_source_files: don't touch symlinks generated by apt-get.
 
48
#
 
49
# Revision 1.162  2001/11/06 12:29:22  rnhodek
 
50
# New config var $use_FetchFile (default 0).
 
51
# Integrated patches for using apt-get to download sources; modified so
 
52
#   that old code (using FetchFile.pm) still present.
 
53
# run_apt: Fix parsing error of apt-output (\s matched ^M printed by
 
54
#   pre-configuring).
 
55
#
 
56
# Revision 1.161  2001/10/29 12:20:41  rnhodek
 
57
# Added $fakeroot var.
 
58
#
 
59
# Revision 1.160  2001/10/29 08:27:53  rnhodek
 
60
# Fix typo in message.
 
61
#
 
62
# Revision 1.159  2001/06/18 09:57:55  rnhodek
 
63
# Use --database option when wanna_build_dbbase set in config.
 
64
#
 
65
# Revision 1.158  2001/06/01 09:54:36  rnhodek
 
66
# Fix two typos.
 
67
#
 
68
# Revision 1.157  2001/05/31 08:08:08  rnhodek
 
69
# Fixed thinko in conflicts checking (tnx James)
 
70
#
 
71
# Revision 1.156  2001/05/30 08:20:05  rnhodek
 
72
# Use /var/lib/apt as Dir::State if exists (newer apt versions use that)
 
73
# (tnx to Ryan Murray).
 
74
#
 
75
# Revision 1.155  2001/05/30 08:17:01  rnhodek
 
76
# Print also architecture at start of log.
 
77
#
 
78
# Revision 1.154  2001/05/29 07:33:54  rnhodek
 
79
# Also handle versioned Build-Conflicts.
 
80
#   (Tnx to David Schleef <ds@schleef.org>)
 
81
#
 
82
# Revision 1.153  2001/03/13 08:45:17  rnhodek
 
83
# Run chmod -R on source tree only after unpacking.
 
84
#
 
85
# Revision 1.152  2001/02/19 09:23:24  rnhodek
 
86
# Fix typo.
 
87
#
 
88
# Revision 1.151  2001/02/19 08:43:22  rnhodek
 
89
# Fix wrong arch logic.
 
90
#
 
91
# Revision 1.150  2001/01/22 12:56:16  rnhodek
 
92
# Fix handling of arch-restricted build-deps (tnx to Ryan Murray).
 
93
#
 
94
# Revision 1.149  2001/01/15 11:17:36  rnhodek
 
95
# Fixed typo.
 
96
#
 
97
# Revision 1.148  2001/01/15 10:59:18  rnhodek
 
98
# Shortcut when looking for non-dsc files: first try to fetch from same
 
99
# dir as .dsc and FF_search only if that fails.
 
100
#
 
101
# Revision 1.147  2001/01/10 16:16:48  rnhodek
 
102
# Move all built files from chroot dir, not only *.deb.
 
103
#
 
104
# Revision 1.146  2000/10/23 10:39:24  rnhodek
 
105
# Before doing chmod on /etc/ld.so.conf, test if it exists at all.
 
106
#
 
107
# Revision 1.145  2000/10/19 09:08:35  rnhodek
 
108
# A couple of little fixes from Ben.
 
109
# Checks and assures that /etc/ld.so.conf is readable.
 
110
# Support for local overrides with $conf::srcdep_over.
 
111
#
 
112
# Revision 1.144  2000/06/27 12:34:00  rnhodek
 
113
# Implemented new 'prepre' and 'unpack' sections for special targets;
 
114
# the first is a script run before package installation, and the latter
 
115
# can list source packages that should be unpacked in the build dir.
 
116
#
 
117
# Revision 1.143  2000/06/20 14:39:59  rnhodek
 
118
# Call apt-get with some options for relocating various files instead of
 
119
# chrooting it; this avoids that the archive must be available in chroot
 
120
# environment; same is true for dpkg and apt-cache calls.
 
121
# If chrooted, call dpkg with the chroot dir as cwd to avoid "cannot get
 
122
# current directory" errors; same for apt option DPkg::Run-Directory.
 
123
#
 
124
# Revision 1.142  2000/06/19 14:09:00  rnhodek
 
125
# Fix syntax error.
 
126
#
 
127
# Revision 1.141  2000/06/19 14:05:38  rnhodek
 
128
# Call buildd-addpkg with --chroot=DIR options for each dist that is >=
 
129
# the one building for (to run apt-get update in the chroot
 
130
# environments).
 
131
#
 
132
# Revision 1.140  2000/06/19 09:10:24  rnhodek
 
133
# Obey new config var @ignore_watches_no_build_deps, i.e. don't flag
 
134
# watches that are listed there if the package doesn't have build deps.
 
135
# In check_watches(), strip $chroot_dir instead of $chroot_build_dir
 
136
# from pathname.
 
137
#
 
138
# Revision 1.139  2000/06/13 10:54:43  rnhodek
 
139
# Also execute special dependency scripts in chroot environment.
 
140
#
 
141
# Revision 1.138  2000/06/09 12:47:52  rnhodek
 
142
# File .dsc filename for rbuilder (with URL).
 
143
#
 
144
# Revision 1.137  2000/06/09 09:15:21  rnhodek
 
145
# Always install built package (if already) when building chroot; i.e.
 
146
# the $system_level test is not necessary when chrooted.
 
147
#
 
148
# Revision 1.136  2000/06/09 08:20:52  rnhodek
 
149
# Fixed su usage in sub build.
 
150
#
 
151
# Revision 1.135  2000/06/08 14:02:11  rnhodek
 
152
# After changing to chroot dir, change back to be the normal user again
 
153
# and start dpkg-buildpackage with -rsudo again; some packages require
 
154
# that the build target is executed as non-root.
 
155
#
 
156
# Revision 1.134  2000/06/08 13:01:54  rnhodek
 
157
# apt-cache calls need sudo, too, when using chroot.
 
158
#
 
159
# Revision 1.133  2000/06/08 09:13:31  rnhodek
 
160
# Implemented chroot builds; there are a few new global variables
 
161
# $main::chroot_*; major changes are in build, where the source tree is
 
162
# unpacked somewhere else, dpkg-buildpackage called under chroot and
 
163
# built packages are moved back again; also all apt-get and dpkg calls
 
164
# are chroot-ed and /var/lib/dpkg/status is accessed from the chroot
 
165
# environment; also watches are checked under the new root dir.
 
166
#
 
167
# Revision 1.132  2000/06/06 14:37:05  rnhodek
 
168
# New option --source (-s): Also build source package, i.e. don't pass
 
169
# -b or -B to dpkg-buildpackage.
 
170
#
 
171
# Revision 1.131  2000/05/30 15:41:34  rnhodek
 
172
# Call buildd-addpkg with --dist option.
 
173
# Install freshly built packages only if $conf::system_level >= $dist.
 
174
#
 
175
# Revision 1.130  2000/05/16 12:34:20  rnhodek
 
176
# Insert a chmod -R go+rX on the build tree to make files readable; it
 
177
# happens sometimes that files in a .orig.tar.gz have restrictive
 
178
# permissions and this can be inconvenient.
 
179
#
 
180
# Revision 1.129  2000/03/01 14:43:34  rnhodek
 
181
# Also match error message "dpkg: status database area is locked" from
 
182
# apt and retry call later.
 
183
#
 
184
# Revision 1.128  2000/02/16 15:21:33  rnhodek
 
185
# Fix a print message in merge_pkg_build_deps.
 
186
#
 
187
# Revision 1.127  2000/02/16 15:20:38  rnhodek
 
188
# Print version number of sbuild in package log.
 
189
#
 
190
# Revision 1.126  2000/02/16 15:15:15  rnhodek
 
191
# Fix regexp for finding !needs-no-XXX packages.
 
192
# Move !needs-no-XXX from central deps to $main::additional_deps so that
 
193
# they can be found by prepare_watches later.
 
194
#
 
195
# Revision 1.125  2000/02/15 14:40:35  rnhodek
 
196
# Remove forgotten debugging code.
 
197
#
 
198
# Revision 1.124  2000/02/15 11:12:43  rnhodek
 
199
# Expand virtual packages in package build dependencies for comparing
 
200
# with central deps.
 
201
#
 
202
# Revision 1.123  2000/02/11 11:17:07  rnhodek
 
203
# Do not activate watches for packages XXX if a negative dependency
 
204
# needs-no-XXX exists (used to be just a comment, now really processed
 
205
# by sbuild.)
 
206
# Also do not activate watches for dependencies of pkg build deps.
 
207
#
 
208
# Revision 1.122  2000/02/09 15:57:25  rnhodek
 
209
# In merge_pkg_build_deps, do not show warnings about missing
 
210
# !this-package-does-not-exist or !needs-no-xxx dependencies.
 
211
#
 
212
# Revision 1.121  2000/02/04 14:04:18  rnhodek
 
213
# Use --no-down-propagation.
 
214
#
 
215
# Revision 1.120  2000/02/01 12:05:56  rnhodek
 
216
# In binNMU mode, a '_' was missing in the job name.
 
217
#
 
218
# Revision 1.119  2000/01/28 14:54:43  rnhodek
 
219
# Accept abbrevs for distribution options (-ds, -df, -du) here, too.
 
220
# New option --make-binNMU=entry.
 
221
# New binNMU hack to modify debian/changelog; it will add a new entry
 
222
# for the NMU version.
 
223
# New helper function binNMU_version to generate a new version number.
 
224
#
 
225
# Revision 1.118  2000/01/13 14:32:30  rnhodek
 
226
# For compiling on slink systems, pass the --force-confold option to
 
227
# dpkg only for versions < 1.4.1.18 (that don't understand it yet).
 
228
#
 
229
# Revision 1.117  1999/12/17 13:49:50  rnhodek
 
230
# Improved output about missing central deps: build-essential (act.
 
231
# policy) and dependencies of pkg build deps are filtered out and
 
232
# printed separately.
 
233
# New functions cmp_dep_lists, read_build_essential,
 
234
# expand_dependencies, and get_dependencies for the above.
 
235
#
 
236
# Revision 1.116  1999/12/17 11:04:43  rnhodek
 
237
# When pkg build-deps were read from debian/sbuild-build-deps, a wrong
 
238
# package name was used.
 
239
#
 
240
# Revision 1.115  1999/12/09 09:54:42  rnhodek
 
241
# Again fixed a fatal typo...
 
242
#
 
243
# Revision 1.114  1999/12/08 12:33:16  rnhodek
 
244
# merge_pkg_build_deps: Fix printing of overrides.
 
245
#
 
246
# Revision 1.113  1999/12/08 12:25:34  rnhodek
 
247
# Special dependencies are implicitly overrides, i.e. are added to the
 
248
# package-provided build deps.
 
249
#
 
250
# Revision 1.112  1999/12/08 11:31:38  rnhodek
 
251
# get_dpkg_status: don't reset $res{$pkg}->{Installed} to 0 if $pkg is
 
252
# provided.
 
253
#
 
254
# Revision 1.111  1999/12/08 10:37:33  rnhodek
 
255
# Change parsing of .dsc file so that multi-line build dependencies are
 
256
# allowed.
 
257
# Make warning about missing central deps a bit bigger.
 
258
#
 
259
# Revision 1.110  1999/12/06 15:00:33  rnhodek
 
260
# Fix comparison with old deps (must copy them, not only the reference).
 
261
#
 
262
# Revision 1.109  1999/12/06 08:35:53  rnhodek
 
263
# Fixed typo.
 
264
#
 
265
# Revision 1.108  1999/12/03 09:58:16  rnhodek
 
266
# If a pkg has its own build deps, compare them with the central ones
 
267
# and report missing ones.
 
268
#
 
269
# Revision 1.107  1999/11/30 13:54:38  rnhodek
 
270
# Print a message if build deps from the .dsc are used (to avoid confusion).
 
271
# If a pkg has build deps, store them in debian/.sbuild-build-deps to
 
272
# have them available when rebuilding later (no .dsc anymore); also
 
273
# check for this file and read deps from it if building without a .dsc
 
274
# in unpacked source.
 
275
#
 
276
# Revision 1.106  1999/11/15 12:30:15  rnhodek
 
277
# merge_pkg_build_deps: added missing if $main::debug.
 
278
#
 
279
# Revision 1.105  1999/11/03 14:56:32  rnhodek
 
280
# When running apt, set env var DEBIAN_FRONTEND to noninteractive to
 
281
# stop debconf from asking questions or complaining that /dev/tty can't
 
282
# be opened.
 
283
#
 
284
# Revision 1.104  1999/11/02 16:43:51  rnhodek
 
285
# check_inst_packages: also upgrade dependencies of src-deps (if they're
 
286
# already installed); some -dev packages fail to correctly require an
 
287
# identical versioned shlib pkg, so in some cases only the -dev pkg was
 
288
# installed.
 
289
#
 
290
# Revision 1.103  1999/11/02 15:45:43  rnhodek
 
291
# build: Use epoch-stripped version number for the .changes file.
 
292
# check_inst_packages: forgot a if $main::debug.
 
293
#
 
294
# Revision 1.102  1999/10/29 13:07:49  rnhodek
 
295
# New option --stats-dir=DIR; if used, a "1" is appended to
 
296
# DIR/give-back each time a package is given back.
 
297
#
 
298
# Revision 1.101  1999/10/29 12:32:24  rnhodek
 
299
# If using an already unpacked source tree, check (with
 
300
# dpkg-parsechangelog) if it's really the requested version.
 
301
# Make apt-get run dpkg with --force-confold, as the </dev/null trick
 
302
# doesn't work anymore with dpkg >= 1.4.1.18.
 
303
#
 
304
# Revision 1.100  1999/10/25 12:12:21  rnhodek
 
305
# check_inst_packages: Add packages to @deps_inst only if they're not
 
306
# already to be installed.
 
307
#
 
308
# Revision 1.99  1999/10/22 09:01:36  rnhodek
 
309
# Minor changes to output of check_inst_packages.
 
310
#
 
311
# Revision 1.98  1999/10/21 14:21:57  rnhodek
 
312
# Oops... call check_inst_packages only if build was successful.
 
313
#
 
314
# Revision 1.97  1999/10/21 11:46:50  rnhodek
 
315
# Deleted RCS logs for < 1.50.
 
316
# New option --store-built-packages.
 
317
# Fix package name parsing: \w also matches '_' which is unwanted;
 
318
# replace by a-zA-Z.
 
319
# Read reverse sourcedeps of $main::store_built_packages.
 
320
# New sub check_inst_packages.
 
321
#
 
322
# Revision 1.96  1999/09/27 11:18:10  rnhodek
 
323
# Added a missing PLOG.
 
324
#
 
325
# Revision 1.95  1999/09/15 09:10:25  rnhodek
 
326
# Additionally print a warning if a special dep has a version relation.
 
327
#
 
328
# Revision 1.94  1999/09/15 09:08:12  rnhodek
 
329
# Changed parsing of dependencies a bit so that special deps can have
 
330
# arch restrictions, too.
 
331
#
 
332
# Revision 1.93  1999/08/30 09:44:35  rnhodek
 
333
# get_dpkg_status: don't exit too early if a pkg isn't in the arg list,
 
334
# as it might be provided only.
 
335
#
 
336
# Revision 1.92  1999/08/27 13:32:04  rnhodek
 
337
# --auto-give-back has a new optional argument, the user and hostname
 
338
# where to call wanna-build (like $conf::sshcmd); this is needed that
 
339
# sbuild can do give-backs when there's no local wanna-build.
 
340
#
 
341
# Revision 1.91  1999/08/23 12:53:02  rnhodek
 
342
# Support for alternatives.
 
343
# Support for [ARCH1 !ARCH2] arch restriction on dependencies.
 
344
# Parses only src-deps which are needed for packages to be built.
 
345
# Reads Build-{Depends,Conflicts}{,-Indep}: fields from .dsc if present;
 
346
# those override the central src-deps, except those marked as override
 
347
# (& prefix).
 
348
# Implemented abbrevs as kind of macros in src-deps.
 
349
# New option --add-depends (-a).
 
350
# New option --arch-all (-A).
 
351
#
 
352
# Revision 1.90  1999/08/11 15:28:11  rnhodek
 
353
# Insert missing wait call in run_script to get correct return value.
 
354
#
 
355
# Revision 1.89  1999/08/10 14:01:49  rnhodek
 
356
# Virtual packages as dependencies didn't work really yet -- the
 
357
# consistency check didn't see them (dpkg --status doesn't know them)
 
358
# and thus aborted the build; solution: get_dpkg_status now directly
 
359
# reads the status file (which should be a bit faster, too) and extracts
 
360
# Provides: fields of all installed packages and considers those virtual
 
361
# packages installed, too.
 
362
# Print "Source-dependencies not satisfied" message to package log, not
 
363
# to sbuild log.
 
364
# Same in run_apt for virtual package handling.
 
365
# Fix stdout/stderr redirecting when running scripts.
 
366
#
 
367
# Revision 1.88  1999/07/13 07:23:55  rnhodek
 
368
# Use GDBM for time/space databases, as perl-5.004 seems not to contain
 
369
# DB_File anymore.
 
370
#
 
371
# Revision 1.87  1999/06/21 12:52:00  rnhodek
 
372
# Seems apt has a new error message if a cached Packages file isn't
 
373
# up-to-date anymore -- recognize this msg, too, and reun apt-get update.
 
374
#
 
375
# Revision 1.86  1999/06/09 15:05:38  rnhodek
 
376
# Fix loop in apply_patches.
 
377
# Don't fail due to failed patch if a global patch.
 
378
# Global patches are no syntax error when parsing src-deps...
 
379
#
 
380
# Revision 1.85  1999/06/04 09:47:02  rnhodek
 
381
# Add support for global patches, which will be tried on any package;
 
382
# their names in source-dependencies start with "**".
 
383
#
 
384
# Revision 1.84  1999/06/04 08:17:17  rnhodek
 
385
# When calling wanna-build --give-back, don't forget the --dist argument!
 
386
# Added support for virtual packages as source dependencies: apt-get tells us
 
387
# which alternatives are possible, and one of these is selected either by
 
388
# %conf::alternatives or by random.
 
389
#
 
390
# Revision 1.83  1999/06/02 09:07:47  rnhodek
 
391
# With --batch, write each finished job to SBUILD-FINISHED; buildd can pick up
 
392
# this file if sbuild crashes and needs not rebuild already done stuff. The file
 
393
# is removed on normal exit and if sbuild dumps to REDO during a shutdown.
 
394
#
 
395
# Revision 1.82  1999/06/02 08:47:39  rnhodek
 
396
# Remove as many die's as possible -- the bad exit status can cause
 
397
# buildd to retry all packages of an sbuild run; better let this one
 
398
# package fail.
 
399
# Make sure that after build() we're in the correct directory: some
 
400
# chdir()s were missing; also don't chdir("..") because this can be
 
401
# wrong if we followed a symlink, use $main::cwd instead.
 
402
# If the package directory already exists as a symlink, abort the build.
 
403
#
 
404
# Revision 1.81  1999/05/31 12:59:41  rnhodek
 
405
# Run du after build under sudo, to avoid error messages about
 
406
# unreadable dirs.
 
407
#
 
408
# Revision 1.80  1999/05/27 13:28:04  rnhodek
 
409
# Oops, missed an epoch fix (when constructing the .changes file name).
 
410
#
 
411
# Revision 1.79  1999/05/26 11:34:11  rnhodek
 
412
# Ignore epochs for fetching files.
 
413
#
 
414
# Revision 1.78  1999/05/26 09:48:23  rnhodek
 
415
# If dpkg-source fails, remove .tmp-nest dir.
 
416
#
 
417
# Revision 1.77  1999/05/05 07:56:51  rnhodek
 
418
# Need to empty %main::this_watches before filling it for a new package;
 
419
# otherwise we have some spurious reports :-)
 
420
#
 
421
# Revision 1.76  1999/05/04 14:51:40  rnhodek
 
422
# Some more minor stuff for avg-build-space: Reset global
 
423
# $main::this_space to 0 before each build to avoid using the figure of
 
424
# the previous package in case of errors; don't write a 0 value into the
 
425
# database.
 
426
#
 
427
# Revision 1.75  1999/05/04 14:43:01  rnhodek
 
428
# Fix parsing of a single dependency: package name never should contain
 
429
# a '('.
 
430
#
 
431
# Revision 1.74  1999/05/04 14:29:51  rnhodek
 
432
# Determine how much space is required for a build (final build dir +
 
433
# generated .debs) after dpkg-buildpackage is finished; display figure
 
434
# in package log and also store it in $conf::avg_space_db (analogous to
 
435
# avg_time_db).
 
436
#
 
437
# Revision 1.73  1999/05/03 12:53:25  rnhodek
 
438
# After unpacking src dir, run "chmod -R g-s ." on it; some
 
439
# .orig.tar.gz's are packed with the setgid bit, which causes the debian
 
440
# dir and all subdirs to be created setgid, too, and later dpkg-deb
 
441
# --build complains about this.
 
442
#
 
443
# Revision 1.72  1999/04/22 14:16:25  rnhodek
 
444
# Don't kill tee process if verbose but --nolog set -- $pkg_tee_pid
 
445
# undefined then!
 
446
#
 
447
# Revision 1.71  1999/04/21 14:54:10  rnhodek
 
448
# Implemented watches if certain binaries have been used during a build
 
449
# without a source dependency.
 
450
#
 
451
# Revision 1.70  1999/03/12 10:29:32  rnhodek
 
452
# New option --force-depends (-f) to override src-deps of a package.
 
453
#
 
454
 
 
455
BEGIN {
 
456
        ($main::HOME = $ENV{'HOME'})
 
457
                or die "HOME not defined in environment!\n";
 
458
        push( @INC, "$main::HOME/lib" );
 
459
}
 
460
 
 
461
chomp( $main::HOSTNAME = `hostname` );
 
462
 
 
463
package conf;
 
464
$HOME = $main::HOME;
 
465
# defaults:
 
466
@dist_parts = qw(main contrib non-free);
 
467
$source_dependencies = "/etc/source-dependencies";
 
468
$mailprog = "/usr/sbin/sendmail";
 
469
$dpkg = "/usr/bin/dpkg";
 
470
$sudo = "/usr/bin/sudo";
 
471
$su = "/bin/su";
 
472
$fakeroot = "/usr/bin/fakeroot";
 
473
$apt_get = "/usr/bin/apt-get";
 
474
$apt_cache = "/usr/bin/apt-cache";
 
475
$dpkg_source = "/usr/bin/dpkg-source";
 
476
$build_env_cmnd = "";
 
477
$pgp_options = "-us -uc";
 
478
$log_dir = "$main::HOME/logs";
 
479
$mailto = "";
 
480
$purge_build_directory = "successful";
 
481
@toolchain_regex = ( 'binutils$', 'gcc-[\d.]+$', 'g\+\+-[\d.]+$', 'libstdc\+\+', 'libc[\d.]+-dev$', 'linux-kernel-headers$', 'dpkg-dev$', 'make$' );
 
482
$stalled_pkg_timeout = 90; # minutes
 
483
$srcdep_lock_wait = 1; # minutes
 
484
%individual_stalled_pkg_timeout = ();
 
485
$path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/X11R6/bin:/usr/games";
 
486
# read conf files
 
487
require "/etc/sbuild.conf" if -r "/etc/sbuild.conf";
 
488
require "$HOME/.sbuildrc" if -r "$HOME/.sbuildrc";
 
489
# some checks
 
490
#die "mailprog binary $conf::mailprog does not exist or isn't executable\n"
 
491
#       if !-x $conf::mailprog;
 
492
die "sudo binary $conf::sudo does not exist or isn't executable\n"
 
493
        if !-x $conf::sudo;
 
494
die "apt-get binary $conf::apt_get does not exist or isn't executable\n"
 
495
        if !-x $conf::apt_get;
 
496
die "apt-cache binary $conf::apt_cache does not exist or isn't executable\n"
 
497
        if !-x $conf::apt_cache;
 
498
die "dpkg-source binary $conf::dpkg_source does not exist or isn't executable\n"
 
499
        if !-x $conf::dpkg_source;
 
500
#die "$conf::log_dir is not a directory\n" if ! -d $conf::log_dir;
 
501
die "$conf::srcdep_lock_dir is not a directory\n" if ! -d $conf::srcdep_lock_dir;
 
502
die "conf::mailto not set\n" if !$conf::mailto;
 
503
package main;
 
504
 
 
505
use strict;
 
506
use GDBM_File;
 
507
use POSIX;
 
508
use FileHandle;
 
509
use Cwd;
 
510
 
 
511
# avoid intermixing of stdout and stderr
 
512
$| = 1;
 
513
 
 
514
# We should not ignore HUP for our children - it breaks test suites.
 
515
# in case the terminal disappears, the build should continue
 
516
#$SIG{'HUP'} = 'IGNORE';
 
517
 
 
518
$main::distribution = "";
 
519
$main::distribution = $conf::default_distribution if $conf::default_distribution;
 
520
 
 
521
chomp( $main::arch = `$conf::dpkg --print-architecture` );
 
522
$main::username = (getpwuid($<))[0] || $ENV{'LOGNAME'} || $ENV{'USER'};
 
523
$main::debug = 0;
 
524
$main::verbose = 0;
 
525
$main::batchmode = 0;
 
526
$main::auto_giveback = 0;
 
527
$main::nomail = 0;
 
528
$main::build_arch_all = 0;
 
529
$main::build_source = 0;
 
530
$main::jobs_file = cwd() . "/build-progress";
 
531
$main::max_lock_trys = 120;
 
532
$main::lock_interval = 5;
 
533
$main::cwd = cwd();
 
534
$main::ilock_file = "$conf::srcdep_lock_dir/install";
 
535
$main::srcdep_lock_cnt = 0;
 
536
$main::chroot_dir = "";
 
537
$main::chroot_build_dir = "";
 
538
$main::chroot_apt_options = "";
 
539
@main::toolchain_pkgs = ();
 
540
$main::component="";
 
541
$main::nr_processors = $ENV{'NR_PROCESSORS'} if $ENV{'NR_PROCESSORS'};
 
542
 
 
543
umask(022);
 
544
 
 
545
$main::new_dpkg = 0;
 
546
check_dpkg_version();
 
547
 
 
548
while( @ARGV && $ARGV[0] =~ /^-/ ) {
 
549
        $_ = shift @ARGV;
 
550
        if (/^-v$/ || /^--verbose$/) {
 
551
                $main::verbose++;
 
552
        }
 
553
        elsif (/^-D$/ || /^--debug$/) {
 
554
                $main::debug++;
 
555
        }
 
556
        elsif (/^-b$/ || /^--batch$/) {
 
557
                $main::batchmode = 1;
 
558
        }
 
559
        elsif (/^-n$/ || /^--nolog$/) {
 
560
                $main::nolog = 1;
 
561
        }
 
562
        elsif (/^-A$/ || /^--arch-all$/) {
 
563
                $main::build_arch_all++;
 
564
        }
 
565
        elsif (/^-s$/ || /^--source$/) {
 
566
                $main::build_source++;
 
567
                $conf::purge_build_directory = "never";
 
568
        }
 
569
        elsif (/^--architecture=(.)/) {
 
570
                $conf::arch=$1.$';
 
571
        }
 
572
        elsif (/^--archive=(.)/) {
 
573
                $main::archive=$1.$';
 
574
        }
 
575
        elsif (/^--comp=(.)/) {
 
576
                $main::component=$1.$';
 
577
        }
 
578
        elsif (/^--purpose=(.)/) {
 
579
                $main::purpose=$1.$';
 
580
        }
 
581
        elsif (/^--build-debug-symbols$/) {
 
582
                $main::build_debug_symbols = 1;
 
583
        }
 
584
        elsif (/^-d/ || /^--dist/) {
 
585
                if (/^-d(.)/ || /^--dist=(.)/) {
 
586
                        $main::distribution = $1.$';
 
587
                }
 
588
                elsif (!@ARGV) {
 
589
                        die "$_ option missing argument\n";
 
590
                }
 
591
                else {
 
592
                        $main::distribution = shift @ARGV;
 
593
                }
 
594
                $main::distribution = "stable"   if $main::distribution eq "s";
 
595
                $main::distribution = "testing"  if $main::distribution eq "t";
 
596
                $main::distribution = "unstable" if $main::distribution eq "u";
 
597
        }
 
598
        elsif (/^-p/ || /^--purge/) {
 
599
                if (/^-p(.)/ || /^--purge=(.)/) {
 
600
                        $conf::purge_build_directory = $1.$';
 
601
                }
 
602
                elsif (!@ARGV) {
 
603
                        die "$_ option missing argument\n";
 
604
                }
 
605
                else {
 
606
                        $conf::purge_build_directory = shift @ARGV;
 
607
                }
 
608
                die "Bad purge mode\n"
 
609
                        if !isin($conf::purge_build_directory, qw(always successful never));
 
610
        }
 
611
        elsif (/^-m/ || /^--maintainer/) {
 
612
                if (/^-m(.)/ || /^--maintainer=(.)/) {
 
613
                        $conf::maintainer_name = $1.$';
 
614
                }
 
615
                elsif (!@ARGV) {
 
616
                        die "$_ option missing argument\n";
 
617
                }
 
618
                else {
 
619
                        $conf::maintainer_name = shift @ARGV;
 
620
                }
 
621
        }
 
622
        elsif (/^-f/ || /^--force-depends/) {
 
623
                if (/^-f(.)/ || /^--force-depends=(.)/) {
 
624
                        push( @main::manual_srcdeps, "f".$1.$' );
 
625
                }
 
626
                elsif (!@ARGV) {
 
627
                        die "$_ option missing argument\n";
 
628
                }
 
629
                else {
 
630
                        push( @main::manual_srcdeps, "f".(shift @ARGV) );
 
631
                }
 
632
        }
 
633
        elsif (/^-a/ || /^--add-depends/) {
 
634
                if (/^-a(.)/ || /^--add-depends=(.)/) {
 
635
                        push( @main::manual_srcdeps, "a".$1.$' );
 
636
                }
 
637
                elsif (!@ARGV) {
 
638
                        die "$_ option missing argument\n";
 
639
                }
 
640
                else {
 
641
                        push( @main::manual_srcdeps, "a".(shift @ARGV) );
 
642
                }
 
643
        }
 
644
        elsif (/^--auto-give-back(=(.*))?$/) {
 
645
                $main::auto_giveback = 1;
 
646
                if ($2) {
 
647
                        my @parts = split( '@', $2 );
 
648
                        $main::auto_giveback_socket  = "$main::HOME/build" if @parts > 3;
 
649
                        $main::auto_giveback_socket .= $parts[$#parts-3] if @parts > 3;
 
650
                        $main::auto_giveback_wb_user = $parts[$#parts-2] if @parts > 2;
 
651
                        $main::auto_giveback_user    = $parts[$#parts-1] if @parts > 1;
 
652
                        $main::auto_giveback_host    = $parts[$#parts];
 
653
                }
 
654
        }
 
655
        elsif (/^--database=(.+)$/) {
 
656
                $main::database = $1;
 
657
        }
 
658
        elsif (/^--stats-dir=(.+)$/) {
 
659
                $main::stats_dir = $1;
 
660
        }
 
661
        elsif (/^--make-binNMU=(.+)$/) {
 
662
                $main::binNMU = $1;
 
663
                $main::binNMUver ||= 1;
 
664
        }
 
665
        elsif (/^--binNMU=(\d+)$/) {
 
666
                $main::binNMUver = $1;
 
667
        }
 
668
        elsif (/^--use-snapshot$/) {
 
669
                $main::useSNAP = 1;
 
670
                $main::ld_library_path = "/usr/lib/gcc-snapshot/lib";
 
671
                $conf::path = "/usr/lib/gcc-snapshot/bin:$conf::path";
 
672
        }
 
673
        else {
 
674
                die "Unknown option: $_\n";
 
675
        }
 
676
}
 
677
 
 
678
die "Need distribution\n" if $main::distribution eq "";
 
679
 
 
680
$conf::mailto = $conf::mailto{$main::distribution}
 
681
        if $conf::mailto{$main::distribution};
 
682
 
 
683
$main::arch = $conf::arch if $conf::arch;
 
684
 
 
685
# variables for scripts:
 
686
open_log();
 
687
$SIG{'INT'} = \&shutdown;
 
688
$SIG{'TERM'} = \&shutdown;
 
689
$SIG{'ALRM'} = \&shutdown;
 
690
$SIG{'PIPE'} = \&shutdown;
 
691
read_deps( map { m,(?:.*/)?([^_/]+)[^/]*, } @ARGV );
 
692
if (-d "chroot-autobuild") {
 
693
        $main::chroot_dir = "chroot-autobuild";
 
694
        $main::chroot_build_dir = "$main::chroot_dir/build/$main::username/";
 
695
        $conf::srcdep_lock_dir = "$main::chroot_dir/var/debbuild/srcdep-lock";
 
696
        $main::ilock_file = "$conf::srcdep_lock_dir/install";
 
697
        my $absroot = "$main::cwd/$main::chroot_dir";
 
698
        $main::chroot_apt_options =
 
699
                "-o APT::Architecture=$main::arch ".
 
700
                "-o Dir::State=$absroot/var/".
 
701
                        (-d "$absroot/var/lib/apt" ? "lib":"state")."/apt ".
 
702
                "-o Dir::State::status=$absroot/var/lib/dpkg/status ".
 
703
                "-o Dir::Cache=$absroot/var/cache/apt ".
 
704
                "-o Dir::Etc=$absroot/etc/apt ".
 
705
                "-o DPkg::Options::=--root=$absroot ".
 
706
                "-o DPkg::Options::=--force-architecture ".
 
707
                "-o DPkg::Run-Directory=$absroot";
 
708
        $main::chroot_apt_op = '$CHROOT_OPTIONS';
 
709
}
 
710
write_jobs_file();
 
711
 
 
712
my( $pkgv, $pkg );
 
713
foreach $pkgv (@ARGV) {
 
714
        my $urlbase;
 
715
 
 
716
        
 
717
        ($urlbase, $pkgv) = ($1, $3) if $pkgv =~ m,^(\w+://(\S+/)?)([^/]+)$,;
 
718
        $pkgv =~ s/\.dsc$//;
 
719
        next if !open_pkg_log( $pkgv );
 
720
        (my $pkg = $pkgv) =~ s/_.*$//;
 
721
        $main::pkg_start_time = time;
 
722
        $main::this_space = 0;
 
723
        $main::pkg_status = "failed"; # assume for now
 
724
        $main::current_job = $main::binNMU_name || $pkgv;
 
725
        $main::additional_deps = [];
 
726
        write_jobs_file( "currently building" );
 
727
        if (should_skip( $pkgv )) {
 
728
                $main::pkg_status = "skipped";
 
729
                goto cleanup_close;
 
730
        }
 
731
        my $dscfile = $pkgv.".dsc";
 
732
        $main::pkg_fail_stage = "fetch-src";
 
733
        my @files_to_rm = fetch_source_files( \$dscfile );
 
734
        if (@files_to_rm && $files_to_rm[0] eq "ERROR") {
 
735
                shift @files_to_rm;
 
736
                goto cleanup_symlinks;
 
737
        }
 
738
                
 
739
        $main::pkg_fail_stage = "install-deps";
 
740
        if (!install_deps( $pkg )) {
 
741
                print PLOG "Source-dependencies not satisfied; skipping $pkg\n";
 
742
                goto cleanup_packages;
 
743
        }
 
744
 
 
745
        my $dscbase = basename( $dscfile );
 
746
        $main::pkg_status = "successful" if build( $dscbase, $pkgv );
 
747
        chdir( $main::cwd );
 
748
        write_jobs_file( $main::pkg_status );
 
749
        append_to_FINISHED( $main::current_job );
 
750
 
 
751
  cleanup_packages:
 
752
        undo_specials();
 
753
        #uninstall_deps();
 
754
        remove_srcdep_lock_file();
 
755
  cleanup_symlinks:
 
756
        remove_files( @files_to_rm );
 
757
  cleanup_close:
 
758
        analyze_fail_stage( $pkgv );
 
759
        if( $main::pkg_status eq 'failed' ) {
 
760
                $main::pkg_status = 'failed ' . $main::pkg_fail_stage;
 
761
        }
 
762
        write_jobs_file( $main::pkg_status );
 
763
        close_pkg_log( $pkgv );
 
764
        $main::current_job = "";
 
765
        if ( $main::batchmode and (-f "$main::HOME/EXIT-DAEMON-PLEASE") ) {
 
766
            main::shutdown("NONE (flag file exit)");
 
767
        }
 
768
}
 
769
write_jobs_file();
 
770
 
 
771
close_log();
 
772
#unlink( $main::jobs_file ) if $main::batchmode;
 
773
unlink( "SBUILD-FINISHED" ) if $main::batchmode;
 
774
exit 0;
 
775
 
 
776
sub fetch_source_files {
 
777
        my $dscfile_ref = shift;
 
778
        my $dscfile = $$dscfile_ref;
 
779
        my ($dir, $dscbase, $files, @other_files, $dscarchs, @made);
 
780
        my ($build_depends, $build_depends_indep, $build_conflicts,
 
781
                $build_conflicts_indep);
 
782
        local( *F );
 
783
 
 
784
        $dscfile =~ m,^(.*)/([^/]+)$,;
 
785
        ($dir, $dscbase) = ($1, $2);
 
786
        my $urlbase;
 
787
        $urlbase = $1 if $dscfile =~ m,^(\w+://(\S+/)?)([^/]+)$,;
 
788
        (my $pkgv = $dscfile) =~ s,^(.*/)?([^/]+)\.dsc$,$2,;
 
789
        my ($pkg, $version) = split /_/, $pkgv;
 
790
        @main::have_dsc_build_deps = ();
 
791
 
 
792
        if (-d $dscfile) {
 
793
                if (-f "$dscfile/debian/.sbuild-build-deps") {
 
794
                        open( F, "<$dscfile/debian/.sbuild-build-deps" );
 
795
                        my $pkg;
 
796
                        while( <F> ) {
 
797
                                /^Package:\s*(.*)\s*$/i and $pkg = $1;
 
798
                                /^Build-Depends:\s*(.*)\s*$/i and $build_depends = $1;
 
799
                                /^Build-Depends-Indep:\s*(.*)\s*$/i and $build_depends_indep = $1;
 
800
                                /^Build-Conflicts:\s*(.*)\s*$/i and $build_conflicts = $1;
 
801
                                /^Build-Conflicts-Indep:\s*(.*)\s*$/i and $build_conflicts_indep = $1;
 
802
                        }
 
803
                        close( F );
 
804
                        if ($build_depends || $build_depends_indep || $build_conflicts ||
 
805
                                $build_conflicts_indep) {
 
806
                                merge_pkg_build_deps( $pkg, $build_depends,
 
807
                                                                          $build_depends_indep, $build_conflicts,
 
808
                                                                          $build_conflicts_indep );
 
809
                        }
 
810
                }
 
811
                return;
 
812
        }
 
813
 
 
814
        if ($dir ne ".") {
 
815
                {
 
816
                        if (-f "${pkgv}.dsc") {
 
817
                                print PLOG "${pkgv}.dsc exists in cwd\n";
 
818
                        }
 
819
                        else {
 
820
                                my %entries;
 
821
                                my $retried = 0;
 
822
 
 
823
                          retry:
 
824
                                print PLOG "Checking available source versions...\n";
 
825
                                if (!open( PIPE, "$conf::sudo /usr/sbin/chroot ".
 
826
                                                   "$main::chroot_dir $conf::apt_cache ".
 
827
                                                   "-q showsrc $pkg 2>&1 </dev/null |" )) {
 
828
                                        print PLOG "Can't open pipe to apt-cache: $!\n";
 
829
                                        return ("ERROR");
 
830
                                }
 
831
                                { local($/) = "";
 
832
                                  while( <PIPE> ) {
 
833
                                          my $ver = $1 if /^Version:\s+(\S+)\s*$/mi;
 
834
                                          my $tfile = $1 if /^Files:\s*\n((\s+.*\s*\n)+)/mi;
 
835
                                          @{$entries{$ver}} = map { (split( /\s+/, $_ ))[3] }
 
836
                                                  split( "\n", $tfile );
 
837
                                  }
 
838
                            }
 
839
                                close( PIPE );
 
840
                                if ($?) {
 
841
                                        print PLOG "$conf::apt_cache failed\n";
 
842
                                        return ("ERROR");
 
843
                                }
 
844
                                
 
845
                                if (!defined($entries{$version})) {
 
846
                                        if (!$retried) {
 
847
                                                # try to update apt's cache if nothing found
 
848
                                                system "$conf::sudo /usr/sbin/chroot ".
 
849
                                                           "$main::chroot_dir $conf::apt_get ".
 
850
                                                           "update >/dev/null";
 
851
                                                $retried = 1;
 
852
                                                goto retry;
 
853
                                        }
 
854
                                        print PLOG "Can't find source for $pkgv\n";
 
855
                                        print PLOG "(only different version(s) ",
 
856
                                                           join( ", ", sort keys %entries), " found)\n"
 
857
                                                if %entries;
 
858
                                        return( "ERROR" );
 
859
                                }
 
860
 
 
861
                                print PLOG "Fetching source files...\n";
 
862
                                @made = @{$entries{$version}};
 
863
                                if (!open( PIPE, "$conf::apt_get $main::chroot_apt_options ".
 
864
                                                   "--only-source -q -d source $pkg=$version 2>&1 </dev/null |" )) {
 
865
                                        print PLOG "Can't open pipe to $conf::apt_get: $!\n";
 
866
                                        return ("ERROR", @made);
 
867
                                }
 
868
                                while( <PIPE> ) {
 
869
                                        print PLOG $_;
 
870
                                }
 
871
                                close( PIPE );
 
872
                                if ($?) {
 
873
                                        print PLOG "$conf::apt_get for sources failed\n";
 
874
                                        return( "ERROR", @made );
 
875
                                }
 
876
                                # touch the downloaded files, otherwise buildd-watcher
 
877
                                # will complain that they're old :)
 
878
                                $$dscfile_ref = $dscfile = (grep { /\.dsc$/ } @made)[0];
 
879
                        }
 
880
                }
 
881
        }
 
882
        
 
883
        if (!open( F, "<$dscfile" )) {
 
884
                print PLOG "Can't open $dscfile: $!\n";
 
885
                return( "ERROR", @made );
 
886
        }
 
887
        my $dsctext;
 
888
        { local($/); $dsctext = <F>; }
 
889
        close( F );
 
890
 
 
891
        $dsctext =~ /^Build-Depends:\s*((.|\n\s+)*)\s*$/mi
 
892
                and $build_depends = $1;
 
893
        $dsctext =~ /^Build-Depends-Indep:\s*((.|\n\s+)*)\s*$/mi
 
894
                and $build_depends_indep = $1;
 
895
        $dsctext =~ /^Build-Conflicts:\s*((.|\n\s+)*)\s*$/mi
 
896
                and $build_conflicts = $1;
 
897
        $dsctext =~ /^Build-Conflicts-Indep:\s*((.|\n\s+)*)\s*$/mi
 
898
                and $build_conflicts_indep = $1;
 
899
        $build_depends =~ s/\n\s+/ /g if defined $build_depends;
 
900
        $build_depends_indep =~ s/\n\s+/ /g if defined $build_depends_indep;
 
901
        $build_conflicts =~ s/\n\s+/ /g if defined $build_conflicts;
 
902
        $build_conflicts_indep =~ s/\n\s+/ /g if defined $build_conflicts_indep;
 
903
 
 
904
        $dsctext =~ /^Architecture:\s*(.*)$/mi and $dscarchs = $1;
 
905
 
 
906
        $dsctext =~ /^Files:\s*\n((\s+.*\s*\n)+)/mi and $files = $1;
 
907
        @other_files = map { (split( /\s+/, $_ ))[3] } split( "\n", $files );
 
908
 
 
909
        if (!$dscarchs) {
 
910
                print PLOG "$dscbase has no Architecture: field -- skipping arch check!\n";
 
911
        }
 
912
        else {
 
913
                my $valid_arch;
 
914
                for my $a (split(/\s+/, $dscarchs)) {
 
915
                        if (system("$conf::sudo", "/usr/sbin/chroot",
 
916
                            "$main::cwd/$main::chroot_dir", 
 
917
                            "dpkg-architecture", "-a".$main::arch, "-i".$a) eq 0) {
 
918
                                $valid_arch = 1;
 
919
                                last;
 
920
                        }
 
921
                }
 
922
                if ($dscarchs ne "any" && !($valid_arch) &&
 
923
                    !($dscarchs eq "all" && $main::build_arch_all) ) {
 
924
                        my $msg = "$dscbase: $main::arch not in arch list or does not match any arch ";
 
925
                        $msg .= "wildcards: $dscarchs -- skipping\n";
 
926
                        print PLOG $msg;
 
927
                        $main::pkg_fail_stage = "arch-check";
 
928
                        return( "ERROR", @made );
 
929
                }
 
930
        }
 
931
        print "Arch check ok ($main::arch included in $dscarchs)\n"
 
932
                if $main::debug;
 
933
 
 
934
        if ($build_depends || $build_depends_indep || $build_conflicts ||
 
935
                $build_conflicts_indep) {
 
936
                @main::have_dsc_build_deps = ($build_depends, $build_depends_indep,
 
937
                                                                          $build_conflicts,$build_conflicts_indep);
 
938
                merge_pkg_build_deps( $pkg, $build_depends, $build_depends_indep,
 
939
                                                          $build_conflicts, $build_conflicts_indep );
 
940
        }
 
941
 
 
942
        return @made;
 
943
}
 
944
 
 
945
sub build {
 
946
        my $dsc = shift;
 
947
        my $pkgv = shift;
 
948
        my( $dir, $rv, $changes );
 
949
        my $do_apply_patches = 1;
 
950
        local( *PIPE, *F, *F2 );
 
951
 
 
952
        fixup_pkgv( \$pkgv );
 
953
        print PLOG "-"x78, "\n";
 
954
        # count build time from now, ignoring the installation of source deps
 
955
        $main::pkg_start_time = time;
 
956
        $main::this_space = 0;
 
957
        $pkgv =~ /^([a-zA-Z\d.+-]+)_([a-zA-Z\d:.+~-]+)/;
 
958
        my ($pkg, $version) = ($1,$2);
 
959
        (my $sversion = $version) =~ s/^\d+://;
 
960
        my $tmpunpackdir = $dsc;
 
961
        $tmpunpackdir =~ s/-.*$/.orig.tmp-nest/;
 
962
        $tmpunpackdir =~ s/_/-/;
 
963
        $tmpunpackdir = "$main::chroot_build_dir$tmpunpackdir";
 
964
        
 
965
        if (-d "$main::chroot_build_dir$dsc" && -l "$main::chroot_build_dir$dsc") {
 
966
                # if the package dir already exists but is a symlink, complain
 
967
                print PLOG "Cannot unpack source: a symlink to a directory with the\n",
 
968
                                   "same name already exists.\n";
 
969
                return 0;
 
970
        }
 
971
        if (! -d "$main::chroot_build_dir$dsc") {
 
972
                $main::pkg_fail_stage = "unpack";
 
973
                # dpkg-source refuses to remove the remanants of an
 
974
                # aborted dpkg-source extraction, so we will if necessary.
 
975
                if (-d $tmpunpackdir) {
 
976
                    system ("rm -fr $tmpunpackdir");
 
977
                }
 
978
                $main::sub_pid = open( PIPE, "-|" );
 
979
                if (!defined $main::sub_pid) {
 
980
                        print PLOG "Can't spawn dpkg-source: $!\n";
 
981
                        return 0;
 
982
                }
 
983
                if ($main::sub_pid == 0) {
 
984
                        setpgrp( 0, $$ );
 
985
                        if ($main::chroot_build_dir && !chdir( $main::chroot_build_dir )) {
 
986
                                print PLOG "Couldn't cd to $main::chroot_build_dir: $!\n";
 
987
                                system ("rm -fr $tmpunpackdir") if -d $tmpunpackdir;
 
988
                                exit 1;
 
989
                        }
 
990
 
 
991
                        my @files;
 
992
                        push( @files, $dsc );
 
993
                        if (!open( F, "<$main::cwd/$dsc" )) {
 
994
                                print PLOG "Can't open $main::cwd/$dsc: $!\n";
 
995
                                return 0;
 
996
                        }
 
997
                        my $dsctext;
 
998
                        { local($/); $dsctext = <F>; }
 
999
                        close( F );
 
1000
                        my $files;
 
1001
                        $dsctext =~ /^Files:\s*\n((\s+.*\s*\n)+)/mi and $files = $1;
 
1002
                        push(@files, map { (split( /\s+/, $_ ))[3] } split( "\n", $files ));
 
1003
 
 
1004
                        my $file;
 
1005
                        foreach $file (@files) {
 
1006
                                system ("cp", "$main::cwd/$file", "$file");
 
1007
                        }
 
1008
                        exec "$conf::sudo", "/usr/sbin/chroot", "$main::cwd/$main::chroot_dir",
 
1009
                                "$conf::su", $main::username, "-s", "/bin/sh", "-c",
 
1010
                                "cd /build/$main::username && $conf::dpkg_source -sn -x $dsc 2>&1";
 
1011
                        unlink @files;
 
1012
                }
 
1013
                $main::sub_task = "dpkg-source";
 
1014
                
 
1015
                while( <PIPE> ) {
 
1016
                        print PLOG $_;
 
1017
                        $dir = $1 if /^dpkg-source: (?:info: )?extracting \S+ in (\S+)/;
 
1018
                        $main::pkg_fail_stage = "unpack-check"
 
1019
                                if /^dpkg-source: error: file.*instead of expected/;
 
1020
                }
 
1021
                close( PIPE );
 
1022
                undef $main::sub_pid;
 
1023
                if ($?) {
 
1024
                        print PLOG "FAILED [dpkg-source died]\n";
 
1025
                
 
1026
                    system ("rm -fr $tmpunpackdir") if -d $tmpunpackdir;
 
1027
                        return 0;
 
1028
                }
 
1029
                if (!$dir) {
 
1030
                        print PLOG "Couldn't find directory of $dsc in dpkg-source output\n";
 
1031
                    system ("rm -fr $tmpunpackdir") if -d $tmpunpackdir;
 
1032
                        return 0;
 
1033
                }
 
1034
                $dir = "$main::chroot_build_dir$dir";
 
1035
 
 
1036
                if (system( "chmod -R g-s,go+rX $dir" ) != 0) {
 
1037
                        print PLOG "chmod -R g-s,go+rX $dir failed.\n";
 
1038
                        return 0;
 
1039
                }
 
1040
                
 
1041
                if (@main::have_dsc_build_deps && !defined $main::build_source) {
 
1042
                        my ($d, $di, $c, $ci) = @main::have_dsc_build_deps;
 
1043
                        open( F, ">$dir/debian/.sbuild-build-deps" );
 
1044
                        print F "Package: $pkg\n";
 
1045
                        print F "Build-Depends: $d\n" if $d;
 
1046
                        print F "Build-Depends-Indep: $di\n" if $di;
 
1047
                        print F "Build-Conflicts: $c\n" if $c;
 
1048
                        print F "Build-Conflicts-Indep: $ci\n" if $ci;
 
1049
                        close( F );
 
1050
                }
 
1051
        }
 
1052
        else {
 
1053
                $dir = "$main::chroot_build_dir$dsc";
 
1054
                $do_apply_patches = 0;
 
1055
 
 
1056
                $main::pkg_fail_stage = "check-unpacked-version";
 
1057
                # check if the unpacked tree is really the version we need
 
1058
                $main::sub_pid = open( PIPE, "-|" );
 
1059
                if (!defined $main::sub_pid) {
 
1060
                        print PLOG "Can't spawn dpkg-parsechangelog: $!\n";
 
1061
                        return 0;
 
1062
                }
 
1063
                if ($main::sub_pid == 0) {
 
1064
                        setpgrp( 0, $$ );
 
1065
                        chdir( $dir );
 
1066
                        exec "dpkg-parsechangelog 2>&1";
 
1067
                }
 
1068
                $main::sub_task = "dpkg-parsechangelog";
 
1069
 
 
1070
                my $clog = "";
 
1071
                while( <PIPE> ) {
 
1072
                        $clog .= $_;
 
1073
                }
 
1074
                close( PIPE );
 
1075
                undef $main::sub_pid;
 
1076
                if ($?) {
 
1077
                        print PLOG "FAILED [dpkg-parsechangelog died]\n";
 
1078
                        return 0;
 
1079
                }
 
1080
                if ($clog !~ /^Version:\s*(.+)\s*$/mi) {
 
1081
                        print PLOG "dpkg-parsechangelog didn't print Version:\n";
 
1082
                        return 0;
 
1083
                }
 
1084
                my $tree_version = $1;
 
1085
                my $cmp_version = ($main::binNMU && -f "$dir/debian/.sbuild-binNMU-done") ?
 
1086
                        binNMU_version($version) : $version;
 
1087
                if ($tree_version ne $cmp_version) {
 
1088
                        print PLOG "The unpacked source tree $dir is version ".
 
1089
                                           "$tree_version, not wanted $cmp_version!\n";
 
1090
                        return 0;
 
1091
                }
 
1092
        }
 
1093
 
 
1094
        if (!chdir( $dir )) {
 
1095
                print PLOG "Couldn't cd to $dir: $!\n";
 
1096
                system ("rm -fr $tmpunpackdir") if -d $tmpunpackdir;
 
1097
                return 0;
 
1098
        }
 
1099
 
 
1100
        $main::pkg_fail_stage = "check-space";
 
1101
        my $current_usage = `/usr/bin/du -s .`;
 
1102
        $current_usage =~ /^(\d+)/;
 
1103
        $current_usage = $1;
 
1104
        if ($current_usage) {
 
1105
                my $free = df( "." );
 
1106
                if ($free < 2*$current_usage) {
 
1107
                        print PLOG "Disk space is propably not enough for building.\n".
 
1108
                                           "(Source needs $current_usage KB, free are $free KB.)\n";
 
1109
                        print PLOG "Purging $dir\n";
 
1110
                        chdir( $main::cwd );
 
1111
                        system "$conf::sudo rm -rf $dir";
 
1112
                        return 0;
 
1113
                }
 
1114
        }
 
1115
 
 
1116
        $main::pkg_fail_stage = "hack-binNMU";
 
1117
        if ($main::binNMU && ! -f "debian/.sbuild-binNMU-done") {
 
1118
                if (open( F, "<debian/changelog" )) {
 
1119
                        my($firstline, $text);
 
1120
                        $firstline = <F> while $firstline =~ /^$/;
 
1121
                        { local($/); undef $/; $text = <F>; }
 
1122
                        close( F );
 
1123
                        $firstline =~ /^(\S+)\s+\((\S+)\)\s+([^;]+)\s*;\s*urgency=(\S+)\s*$/;
 
1124
                        my ($name, $version, $dists, $urgent) = ($1, $2, $3, $4);
 
1125
                        my $NMUversion = binNMU_version($version);
 
1126
                        chomp( my $date = `822-date` );
 
1127
                        if (!open( F, ">debian/changelog" )) {
 
1128
                                print PLOG "Can't open debian/changelog for binNMU hack: $!\n";
 
1129
                                chdir( $main::cwd );
 
1130
                                return 0;
 
1131
                        }
 
1132
                        $dists = $main::distribution;
 
1133
                        print F "$name ($NMUversion) $dists; urgency=low\n\n";
 
1134
                        print F "  * Binary-only non-maintainer upload for $main::arch; ",
 
1135
                                        "no source changes.\n";
 
1136
                        print F "  * ", join( "    ", split( "\n", $main::binNMU )), "\n\n";
 
1137
                        print F " -- $conf::maintainer_name  $date\n\n";
 
1138
 
 
1139
                        print F $firstline, $text;
 
1140
                        close( F );
 
1141
                        system "touch debian/.sbuild-binNMU-done";
 
1142
                        print PLOG "*** Created changelog entry for bin-NMU version $NMUversion\n";
 
1143
                }
 
1144
                else {
 
1145
                        print PLOG "Can't open debian/changelog -- no binNMU hack!\n";
 
1146
                }
 
1147
        }
 
1148
        
 
1149
        if ($do_apply_patches) {
 
1150
                if (!apply_patches( $pkg )) {
 
1151
                        chdir( $main::cwd );
 
1152
                        return 0;
 
1153
                }
 
1154
        }
 
1155
        
 
1156
        if (-f "debian/files") {
 
1157
                local( *FILES );
 
1158
                my @lines;
 
1159
                open( FILES, "<debian/files" );
 
1160
                chomp( @lines = <FILES> );
 
1161
                close( FILES );
 
1162
                @lines = map { my $ind = 68-length($_);
 
1163
                                           $ind = 0 if $ind < 0;
 
1164
                                           "| $_".(" " x $ind)." |\n"; } @lines;
 
1165
                
 
1166
                print PLOG <<"EOF";
 
1167
 
 
1168
+----------------------------------------------------------------------+
 
1169
| sbuild Warning:                                                      |
 
1170
| ---------------                                                      |
 
1171
| After unpacking, there exists a file debian/files with the contents: |
 
1172
|                                                                      |
 
1173
EOF
 
1174
                print PLOG @lines;
 
1175
                print PLOG <<"EOF";
 
1176
|                                                                      |
 
1177
| This should be reported as a bug.                                    |
 
1178
| The file has been removed to avoid dpkg-genchanges errors.           |
 
1179
+----------------------------------------------------------------------+
 
1180
 
 
1181
EOF
 
1182
                unlink "debian/files";
 
1183
        }
 
1184
 
 
1185
        open CURRENT, ">$main::cwd/$main::chroot_dir/CurrentlyBuilding" or die "$main::cwd/$main::chroot_dir/CurrentlyBuilding open failed";
 
1186
        # Package: must be first
 
1187
        print CURRENT "Package: $pkg\nComponent: $main::component\n";
 
1188
        print CURRENT "Suite: $main::distribution\n" if $main::distribution;
 
1189
        print CURRENT "Purpose: $main::purpose\n" if $main::purpose;
 
1190
        print CURRENT "Build-Debug-Symbols: yes\n" if $main::build_debug_symbols;
 
1191
        close CURRENT;
 
1192
 
 
1193
        $main::build_start_time = time;
 
1194
        $main::pkg_fail_stage = "build";
 
1195
        $main::sub_pid = open( PIPE, "-|" );
 
1196
        if (!defined $main::sub_pid) {
 
1197
                print PLOG "Can't spawn dpkg-buildpackage: $!\n";
 
1198
                chdir( $main::cwd );
 
1199
                return 0;
 
1200
        }
 
1201
        if ($main::sub_pid == 0) {
 
1202
                setpgrp( 0, $$ );
 
1203
                my $binopt = $main::build_source ? "" :
 
1204
                                         $main::build_arch_all ? "-b" : "-B";
 
1205
                my $env_cmnd = $conf::build_env_cmnd;
 
1206
                $env_cmnd = $conf::build_env_cmnd{$pkg} if $conf::build_env_cmnd{$pkg};
 
1207
                if ($main::chroot_dir) {
 
1208
                        my $bdir = $dir;
 
1209
                        $bdir =~ s/^\Q$main::chroot_dir\E//;
 
1210
                        if (-f "$main::chroot_dir/etc/ld.so.conf" &&
 
1211
                            ! -r "$main::chroot_dir/etc/ld.so.conf") {
 
1212
                                system "$conf::sudo chmod a+r $main::chroot_dir/etc/ld.so.conf";
 
1213
                                print PLOG "ld.so.conf was not readable! Fixed.\n";
 
1214
                        }
 
1215
                        exec "$conf::sudo", "/usr/sbin/chroot", "$main::cwd/$main::chroot_dir",
 
1216
                                "$conf::su", $main::username, "-s", "/bin/sh", "-c",
 
1217
                                "cd $bdir && PATH=$conf::path ".
 
1218
                                (defined($main::nr_processors) ?
 
1219
                                "DEB_BUILD_OPTIONS=\"parallel=".$main::nr_processors."\" " : "").
 
1220
                                (defined($main::ld_library_path) ?
 
1221
                                "LD_LIBRARY_PATH=".$main::ld_library_path." " : "").
 
1222
                                "exec $env_cmnd dpkg-buildpackage $conf::pgp_options ".
 
1223
                                "$binopt -m'$conf::maintainer_name' -r$conf::fakeroot 2>&1";
 
1224
                }
 
1225
                else {
 
1226
                        if (-f "/etc/ld.so.conf" && ! -r "/etc/ld.so.conf") {
 
1227
                                system "$conf::sudo chmod a+r /etc/ld.so.conf";
 
1228
                                print PLOG "ld.so.conf was not readable! Fixed.\n";
 
1229
                        }
 
1230
                        exec "$env_cmnd dpkg-buildpackage $conf::pgp_options $binopt ".
 
1231
                                "-m'$conf::maintainer_name' -r$conf::fakeroot 2>&1";
 
1232
                }
 
1233
        }
 
1234
        $main::sub_task = "dpkg-buildpackage";
 
1235
 
 
1236
        # We must send the signal as root, because some subprocesses of
 
1237
        # dpkg-buildpackage could run as root. So we have to use a shell
 
1238
        # command to send the signal... but /bin/kill can't send to
 
1239
        # process groups :-( So start another Perl :-)
 
1240
        my $timeout = $conf::individual_stalled_pkg_timeout{$pkg} ||
 
1241
                                  $conf::stalled_pkg_timeout;
 
1242
        $timeout *= 60;
 
1243
        my $timed_out = 0;
 
1244
        my(@timeout_times, @timeout_sigs, $last_time);
 
1245
        $SIG{'ALRM'} = sub {
 
1246
                my $signal = ($timed_out > 0) ? 9 : 15;
 
1247
                system "$conf::sudo perl -e 'kill( -$signal, $main::sub_pid )'";
 
1248
                $timeout_times[$timed_out] = time - $last_time;
 
1249
                $timeout_sigs[$timed_out] = $signal;
 
1250
                $timed_out++;
 
1251
                $timeout = 5*60; # only wait 5 minutes until next signal
 
1252
        };
 
1253
 
 
1254
        alarm( $timeout );
 
1255
        while( <PIPE> ) {
 
1256
                alarm( $timeout );
 
1257
                $last_time = time;
 
1258
                print PLOG $_;
 
1259
        }
 
1260
        close( PIPE );
 
1261
        undef $main::sub_pid;
 
1262
        alarm( 0 );
 
1263
        $rv = $?;
 
1264
 
 
1265
        my $i;
 
1266
        for( $i = 0; $i < $timed_out; ++$i ) {
 
1267
                print PLOG "Build killed with signal ", $timeout_sigs[$i],
 
1268
                                   " after ", int($timeout_times[$i]/60),
 
1269
                                   " minutes of inactivity\n";
 
1270
        }
 
1271
        $main::pkg_end_time = time;
 
1272
        my $date = `date +%Y%m%d-%H%M`;
 
1273
        print PLOG "*"x78, "\n";
 
1274
        print PLOG "Build finished at $date";
 
1275
        chdir( $main::cwd );
 
1276
 
 
1277
        my @space_files = ("$dir");
 
1278
        if (!$main::nolog and defined $conf::exit_hook and open TMP, '-|', "$conf::exit_hook <$main::pkg_logfile") {
 
1279
                local $/ = undef;
 
1280
                my $log = <TMP>;
 
1281
                close TMP;
 
1282
                $rv |= $?;
 
1283
                print PLOG $log;
 
1284
        }
 
1285
        if ($rv) {
 
1286
                print PLOG "FAILED [dpkg-buildpackage died]\n";
 
1287
        }
 
1288
        else {
 
1289
                my $trans_oldfmt="$main::chroot_build_dir${pkg}_${version}_translations.tar.gz";
 
1290
                my $trans_newfmt="$main::chroot_build_dir${pkg}_${version}_${main::arch}_translations.tar.gz";
 
1291
                my $translations="";
 
1292
                if (-r $trans_newfmt) {
 
1293
                        $translations = $trans_newfmt;
 
1294
                } elsif (-r $trans_oldfmt) {
 
1295
                        $translations = $trans_oldfmt;
 
1296
                }
 
1297
                if ($translations) {
 
1298
                        print PLOG "Publishing $translations for rosetta.\n";
 
1299
                        my $date = strftime '%Y%m%d',gmtime;
 
1300
                        my $target = "$main::HOME/public_html/translations/$date/";
 
1301
                        system "mkdir -p $target";
 
1302
                        if (system("cp",$translations,$target) != 0) {
 
1303
                                print PLOG "ERROR: Could not move $translations to $target\n";
 
1304
                        } else {
 
1305
                                open TRANS, ">>$target/translations.txt";
 
1306
                                print TRANS     "File: " . basename(${translations}) . "\n".
 
1307
                                                "Distribution: ${main::archive}\n".
 
1308
                                                "Release: ${main::distribution}\n".
 
1309
                                                "Component: ${main::component}\n".
 
1310
                                                "Source: ${pkg}\n".
 
1311
                                                "Version: ${version}\n\n";
 
1312
                                close TRANS;
 
1313
                                system("chmod -R go+rX $main::HOME/public_html/translations");
 
1314
                            }
 
1315
                    }
 
1316
 
 
1317
                my $ddebtar = "";
 
1318
                my $ddebstring = "";
 
1319
                if (-r glob("$main::chroot_build_dir/*.ddeb")) {
 
1320
                    my @ddeblist = glob("$main::chroot_build_dir/*.ddeb");
 
1321
                    $ddebtar="${pkg}_${version}_${main::arch}_ddebs.tar";
 
1322
                    while (@ddeblist) {
 
1323
                        $ddebstring .= basename(@ddeblist[0]) . " ";
 
1324
                        shift @ddeblist;
 
1325
                    }
 
1326
                }
 
1327
                if ($ddebstring) {
 
1328
                    print PLOG "Publishing debug debs.\n";
 
1329
                    my $date = strftime '%Y%m%d',gmtime;
 
1330
                    my $target = "$main::HOME/public_html/ddebs/$date/";
 
1331
                    system "mkdir -p $target";
 
1332
                    if (system("tar -C $main::chroot_build_dir -chf $target/$ddebtar $ddebstring") != 0) {
 
1333
                        print PLOG "ERROR: Could not create $ddebtar in $target\n";
 
1334
                    } else {
 
1335
                        open TRANS, ">>$target/ddebs.txt";
 
1336
                        print TRANS "File: " . basename(${ddebtar}) . "\n".
 
1337
                        "Distribution: ${main::archive}\n".
 
1338
                        "Release: ${main::distribution}\n".
 
1339
                        "Component: ${main::component}\n".
 
1340
                        "Source: ${pkg}\n".
 
1341
                        "Version: ${version}\n\n";
 
1342
                    close TRANS;
 
1343
                        system("chmod -R go+rX $main::HOME/public_html/ddebs");
 
1344
                    }
 
1345
                }
 
1346
 
 
1347
                if (-r "$dir/debian/files") {
 
1348
                        my @debs;
 
1349
                        my @files;
 
1350
                        open( F, "<$dir/debian/files" );
 
1351
                        while( <F> ) {
 
1352
                                my $f = (split( /\s+/, $_ ))[0];
 
1353
                                push( @files, "$main::chroot_build_dir$f" );
 
1354
                                if ($main::build_arch_all) {
 
1355
                                        next if ($f !~ /$main::arch\.[\w\d.-]*$/ && $f !~ /all\.[\w\d.-]*$/);
 
1356
                                } else {
 
1357
                                        next if ($f !~ /$main::arch\.[\w\d.-]*$/);
 
1358
                                }
 
1359
                                push( @debs, "$main::chroot_build_dir$f" );
 
1360
                                push( @space_files, $f );
 
1361
                        }
 
1362
                        close( F );
 
1363
                        my @debs2 = @debs;
 
1364
                        foreach (@debs) {
 
1365
                                print PLOG "\n$_:\n";
 
1366
                                if (!open( PIPE, "dpkg --info $_ 2>&1 |" )) {
 
1367
                                        print PLOG "Can't spawn dpkg: $! -- can't dump infos\n";
 
1368
                                }
 
1369
                                else {
 
1370
                                        print PLOG $_ while( <PIPE> );
 
1371
                                        close( PIPE );
 
1372
                                }
 
1373
                        }
 
1374
                        foreach (@debs2) {
 
1375
                                print PLOG "\n$_:\n";
 
1376
                                if (!open( PIPE, "dpkg --contents $_ 2>&1 |" )) {
 
1377
                                        print PLOG "Can't spawn dpkg: $! -- can't dump infos\n";
 
1378
                                }
 
1379
                                else {
 
1380
                                        print PLOG $_ while( <PIPE> );
 
1381
                                        close( PIPE );
 
1382
                                }
 
1383
                        }
 
1384
                        if ($main::chroot_build_dir) {
 
1385
                                foreach (@files) {
 
1386
                                        system "mv", $_, "."
 
1387
                                                and print PLOG "ERROR: Could not move $_ to .\n";
 
1388
                                }
 
1389
                        }
 
1390
                }
 
1391
 
 
1392
                if (-r $translations) {
 
1393
                    system("rm",$translations);
 
1394
                }
 
1395
 
 
1396
                $changes = "${pkg}_".
 
1397
                        ($main::binNMU ? binNMU_version($sversion) : $sversion).
 
1398
                        "_$main::arch.changes";
 
1399
                if (-r "$main::chroot_build_dir$changes") {
 
1400
                        my(@do_dists, @saved_dists);
 
1401
                        print PLOG "\n$changes:\n";
 
1402
                        open( F, "<$main::chroot_build_dir$changes" );
 
1403
                        if (open( F2, ">$changes.new" )) {
 
1404
                                while( <F> ) {
 
1405
                                        if (/^Distribution:\s*(.*)\s*$/) {
 
1406
                                                print PLOG "Distribution: $main::distribution\n";
 
1407
                                                print F2 "Distribution: $main::distribution\n";
 
1408
                                        }
 
1409
                                        else {
 
1410
                                                print F2 $_;
 
1411
                                                while (length $_ > 989)
 
1412
                                                {
 
1413
                                                        my $index = rindex($_,' ',989);
 
1414
                                                        print PLOG substr ($_,0,$index) . "\n";
 
1415
                                                        $_ = '        ' . substr ($_,$index+1);
 
1416
                                                }
 
1417
                                                print PLOG $_;
 
1418
                                        }
 
1419
                                }
 
1420
                                close( F2 );
 
1421
                                rename( "$changes.new", "$changes" )
 
1422
                                        or print PLOG "$changes.new could not be renamed ".
 
1423
                                                                  "to $changes: $!\n";
 
1424
                                unlink( "$main::chroot_build_dir$changes" )
 
1425
                                        if $main::chroot_build_dir;
 
1426
                        }
 
1427
                        else {
 
1428
                                print PLOG "Cannot create $changes.new: $!\n";
 
1429
                                print PLOG "Distribution field may be wrong!!!\n";
 
1430
                                if ($main::chroot_build_dir) {
 
1431
                                        system "mv", "$main::chroot_build_dir$changes", "."
 
1432
                                                and print PLOG "ERROR: Could not move $_ to .\n";
 
1433
                                }
 
1434
                        }
 
1435
                        close( F );
 
1436
                        print PLOG "\n";
 
1437
                }
 
1438
                else {
 
1439
                        print PLOG "Can't find $changes -- can't dump infos\n";
 
1440
                }
 
1441
 
 
1442
                print PLOG "*"x78, "\n";
 
1443
                print PLOG "Built successfully\n";
 
1444
        }
 
1445
 
 
1446
        check_watches();
 
1447
        check_space( @space_files );
 
1448
 
 
1449
        #if ($conf::purge_build_directory eq "always" ||
 
1450
        #       ($conf::purge_build_directory eq "successful" && $rv == 0)) {
 
1451
        #       print PLOG "Purging $dir\n";
 
1452
        #       system "$conf::sudo rm -rf $dir";
 
1453
        #}
 
1454
        #
 
1455
        #print PLOG "-"x78, "\n";
 
1456
        return $rv == 0 ? 1 : 0;
 
1457
}
 
1458
 
 
1459
sub apply_patches {
 
1460
        my $pkg = shift;
 
1461
        my $name;
 
1462
        
 
1463
        $main::pkg_fail_stage = "apply-patch";
 
1464
        foreach $name ((map { $_->{'Package'} } @{$main::deps{$pkg}}),
 
1465
                                   @main::global_patches) {
 
1466
                if ($name =~ /^\*/ && exists $main::specials{$name}->{'patch'}) {
 
1467
                        if (exists $main::specials{$name}->{'patchcond'}) {
 
1468
                                print "Testing condition for $name patch:\n"
 
1469
                                        if $main::debug;
 
1470
                                if (run_script("+e",$main::specials{$name}->{'patchcond'})!=0){
 
1471
                                        print PLOG "Condition for $name patch not true -- ",
 
1472
                                                                "not applying\n" if $name !~ /^\*\*/;
 
1473
                                        next;
 
1474
                                }
 
1475
                                print PLOG "Condition for $name patch ok\n";
 
1476
                        }
 
1477
                        print PLOG "Applying $name patch\n";
 
1478
                        $main::sub_pid = open( PIPE, "|-" );
 
1479
                        if (!defined $main::sub_pid) {
 
1480
                                print PLOG "Can't spawn patch: $! -- can't patch\n";
 
1481
                                return 0;
 
1482
                        }
 
1483
                        if ($main::sub_pid == 0) {
 
1484
                                setpgrp( 0, $$ );
 
1485
                                open( STDOUT, ">&PLOG" );
 
1486
                                open( STDERR, ">&PLOG" );
 
1487
                                exec "patch --batch --quiet -p1 -E -N --no-backup-if-mismatch";
 
1488
                        }
 
1489
                        $main::sub_task = "patch";
 
1490
 
 
1491
                        print PIPE $main::specials{$name}->{'patch'};
 
1492
                        close( PIPE );
 
1493
                        undef $main::sub_pid;
 
1494
                        if ($name !~ /^\*\*/ && $?) {
 
1495
                                print PLOG "FAILED [patch died]\n";
 
1496
                                return 0;
 
1497
                        }
 
1498
                }
 
1499
        }
 
1500
        return 1;
 
1501
}
 
1502
 
 
1503
sub analyze_fail_stage {
 
1504
        my $pkgv = shift;
 
1505
        
 
1506
        return if $main::pkg_status ne "failed";
 
1507
        return if !$main::auto_giveback;
 
1508
        if (isin( $main::pkg_fail_stage,
 
1509
                          qw(find-dsc fetch-src unpack-check check-space install-deps-env))) {
 
1510
                $main::pkg_status = "given-back";
 
1511
                print PLOG "Giving back package $pkgv after failure in ".
 
1512
                               "$main::pkg_fail_stage stage.\n";
 
1513
                chdir( $main::cwd );
 
1514
                my $cmd = "";
 
1515
                $cmd = "ssh -l$main::auto_giveback_user $main::auto_giveback_host "
 
1516
                        if $main::auto_giveback_host;
 
1517
                $cmd .= "-S $main::auto_giveback_socket "
 
1518
                        if ($main::auto_giveback_socket and -S "$main::auto_giveback_socket");
 
1519
                $cmd .= "wanna-build --give-back --no-down-propagation ".
 
1520
                            "--dist=$main::distribution";
 
1521
                $cmd .= " --database=$main::database" if $main::database;
 
1522
                $cmd .= " --user=$main::auto_giveback_wb_user "
 
1523
                        if $main::auto_giveback_wb_user;
 
1524
                $cmd .= " $pkgv";
 
1525
                system $cmd;
 
1526
                if ($?) {
 
1527
                        print PLOG "wanna-build failed with status $?\n";
 
1528
                }
 
1529
                else {
 
1530
                        add_givenback( $pkgv, time );
 
1531
                        if ($main::stats_dir) {
 
1532
                                local( *F );
 
1533
                                lock_file( "$main::stats_dir" );
 
1534
                                open( F, ">>$main::stats_dir/give-back" );
 
1535
                                print F "1\n";
 
1536
                                close( F );
 
1537
                                unlock_file( "$main::stats_dir" );
 
1538
                        }
 
1539
                }
 
1540
        }
 
1541
}
 
1542
 
 
1543
sub remove_files {
 
1544
 
 
1545
        foreach (@_) {
 
1546
                unlink $_;
 
1547
                print "Removed $_\n" if $main::debug;
 
1548
        }
 
1549
}
 
1550
 
 
1551
 
 
1552
sub install_deps {
 
1553
        my $pkg = shift;
 
1554
        my( @positive, @negative, @special, @instd, @rmvd );
 
1555
 
 
1556
        if (!exists $main::deps{$pkg}) {
 
1557
                prepare_watches( [] );
 
1558
                return 1;
 
1559
        }
 
1560
        
 
1561
        my $dep = $main::deps{$pkg};
 
1562
        if ($main::debug) {
 
1563
                print "Source dependencies of $pkg: ", format_deps(@$dep), "\n";
 
1564
        }
 
1565
 
 
1566
  repeat:
 
1567
        lock_file( "$main::ilock_file", 1 );
 
1568
        
 
1569
        print "Filtering dependencies\n" if $main::debug;
 
1570
        if (!filter_dependencies( $dep, \@positive, \@negative, \@special )) {
 
1571
                print PLOG "Package installation not possible\n";
 
1572
                unlock_file( "$main::ilock_file" );
 
1573
                return 0;
 
1574
        }
 
1575
 
 
1576
        print PLOG "Checking for source dependency conflicts...\n";
 
1577
        if (!run_apt( "-s", \@instd, \@rmvd, @positive )) {
 
1578
                print PLOG "Test what should be installed failed.\n";
 
1579
                unlock_file( "$main::ilock_file" );
 
1580
                return 0;
 
1581
        }
 
1582
        # add negative deps as to be removed for checking srcdep conflicts
 
1583
        push( @rmvd, @negative );
 
1584
        my @confl;
 
1585
        if (@confl = check_srcdep_conflicts( \@instd, \@rmvd, \@special )) {
 
1586
                print PLOG "Waiting for job(s) @confl to finish\n";
 
1587
 
 
1588
                unlock_file( "$main::ilock_file" );
 
1589
                wait_for_srcdep_conflicts( @confl );
 
1590
                goto repeat;
 
1591
        }
 
1592
        
 
1593
        write_srcdep_lock_file( $dep, \@special );
 
1594
        
 
1595
        foreach my $sp (@special) {
 
1596
                next if $sp !~ /^\*/ || !exists $main::specials{$sp}->{'prepre'};
 
1597
                print PLOG "Running prepre script for $sp\n";
 
1598
                if (run_script( "-e", $main::specials{$sp}->{'prepre'} ) != 0) {
 
1599
                        print PLOG "prepre script of special dependency $sp failed\n";
 
1600
                        unlock_file( "$main::ilock_file" );
 
1601
                        return 0;
 
1602
                }
 
1603
        }
 
1604
 
 
1605
        print "Installing positive dependencies: @positive\n" if $main::debug;
 
1606
        if (!run_apt( "-y", \@instd, \@rmvd, @positive )) {
 
1607
                print PLOG "Package installation failed\n";
 
1608
                # try to reinstall removed packages
 
1609
                print PLOG "Trying to reinstall removed packages:\n";
 
1610
                print "Reinstalling removed packages: @rmvd\n" if $main::debug;
 
1611
                my (@instd2, @rmvd2);
 
1612
                print PLOG "Failed to reinstall removed packages!\n"
 
1613
                        if !run_apt( "-y", \@instd2, \@rmvd2, @rmvd );
 
1614
                print "Installed were: @instd2\n" if $main::debug;
 
1615
                print "Removed were: @rmvd2\n" if $main::debug;
 
1616
                # remove additional packages
 
1617
                print PLOG "Trying to uninstall newly installed packages:\n";
 
1618
                uninstall_debs( $main::chroot_dir ? "purge" : "remove", @instd );
 
1619
                unlock_file( "$main::ilock_file" );
 
1620
                return 0;
 
1621
        }
 
1622
        set_installed( @instd );
 
1623
        set_removed( @rmvd );
 
1624
        
 
1625
        print "Removing negative dependencies: @negative\n" if $main::debug;
 
1626
        if (!uninstall_debs( $main::chroot_dir ? "purge" : "remove", @negative )) {
 
1627
                print PLOG "Removal of packages failed\n";
 
1628
                unlock_file( "$main::ilock_file" );
 
1629
                return 0;
 
1630
        }
 
1631
        set_removed( @negative );
 
1632
        
 
1633
        my $fail = check_dependencies( $dep );
 
1634
        if ($fail) {
 
1635
                print PLOG "After installing, the following source dependencies are ".
 
1636
                         "still unsatisfied:\n$fail\n";
 
1637
                unlock_file( "$main::ilock_file" );
 
1638
                return 0;
 
1639
        }
 
1640
 
 
1641
        foreach my $sp (@special) {
 
1642
                next if $sp !~ /^\*/ ||
 
1643
                            (!exists $main::specials{$sp}->{'pre'} &&
 
1644
                             !exists $main::specials{$sp}->{'post'} &&
 
1645
                             !exists $main::specials{$sp}->{'unpack'});
 
1646
                if (exists $main::specials{$sp}->{'unpack'}) {
 
1647
                        my $s = $main::specials{$sp}->{'unpack'};
 
1648
                        $s =~ s/^\s+//mg;
 
1649
                        $s =~ s/\s+$//mg;
 
1650
                        my @s = split( /\s+/, $s );
 
1651
                        my @rem;
 
1652
                        print PLOG "Unpacking special sources $sp: @s\n";
 
1653
                        if (!(@rem = unpack_special_source( @s ))) {
 
1654
                                print PLOG "unpacking of special dependency sources for $sp failed\n";
 
1655
                                unlock_file( "$main::ilock_file" );
 
1656
                                return 0;
 
1657
                        }
 
1658
                        $main::changes->{'unpacked'}->{$sp} = \@rem;
 
1659
                }
 
1660
                if (exists $main::specials{$sp}->{'pre'}) {
 
1661
                        print PLOG "Running pre script for $sp\n";
 
1662
                        $main::changes->{'specials'}->{$sp} = 1;
 
1663
                        if (run_script( "-e", $main::specials{$sp}->{'pre'} ) != 0) {
 
1664
                                print PLOG "pre script of special dependency $sp failed\n";
 
1665
                                unlock_file( "$main::ilock_file" );
 
1666
                                return 0;
 
1667
                        }
 
1668
                }
 
1669
        }
 
1670
        
 
1671
        local (*F);
 
1672
        if (open( F, "| $conf::sudo /usr/sbin/chroot $main::chroot_dir $conf::dpkg --set-selections")) {
 
1673
                foreach my $tpkg (@instd) {
 
1674
                        print F $tpkg . " purge\n";
 
1675
                }
 
1676
                close( F );
 
1677
                if ($?) {
 
1678
                        print PLOG "$conf::dpkg --set-selections failed";
 
1679
                }
 
1680
        }
 
1681
 
 
1682
        unlock_file( "$main::ilock_file" );
 
1683
 
 
1684
        prepare_watches( $dep, @instd );
 
1685
        return 1;
 
1686
}
 
1687
 
 
1688
sub unpack_special_source {
 
1689
        my @s = @_;
 
1690
        my (@files, @dirs);
 
1691
        local (*PIPE);
 
1692
 
 
1693
        foreach my $s (@s) {
 
1694
                my $dsc;
 
1695
 
 
1696
                {
 
1697
                        if (!open( PIPE, "$conf::apt_get $main::chroot_apt_options ".
 
1698
                       "--only-source -q -d source $s 2>&1 </dev/null |" )) {
 
1699
                                print PLOG "Can't open pipe to apt-get: $!\n";
 
1700
                                goto failed;
 
1701
                        }
 
1702
                        while( <PIPE> ) {
 
1703
                                $dsc = "$1_$2.dsc" if /(\S+) (?:[^:]+:)?(\S+) \(dsc\)/;
 
1704
                                print PLOG $_;
 
1705
                        }
 
1706
                        close( PIPE );
 
1707
                        if ($?) {
 
1708
                                print PLOG "Apt-get of special unpack sources failed\n";
 
1709
                                goto failed;
 
1710
                        }
 
1711
                        push( @files, $dsc );
 
1712
                        if (!open( F, "<$dsc" )) {
 
1713
                                print PLOG "Can't open $dsc: $!\n";
 
1714
                                goto failed;
 
1715
                        }
 
1716
                        my $dsctext;
 
1717
                        { local($/); $dsctext = <F>; }
 
1718
                        close( F );
 
1719
                        my $files;
 
1720
                        $dsctext =~ /^Files:\s*\n((\s+.*\s*\n)+)/mi and $files = $1;
 
1721
                        push(@files, map { (split( /\s+/, $_ ))[3] } split( "\n", $files ));
 
1722
                }
 
1723
 
 
1724
                my $pid = open( PIPE, "-|" );
 
1725
                if (!defined $pid) {
 
1726
                        print PLOG "Can't spawn dpkg-source: $! -- special unpack failed\n";
 
1727
                        goto failed;
 
1728
                }
 
1729
                if ($pid == 0) {
 
1730
                        setpgrp( 0, $$ );
 
1731
                        if ($main::chroot_build_dir && !chdir( $main::chroot_build_dir )) {
 
1732
                                print PLOG "Couldn't cd to $main::chroot_build_dir: $! -- special unpack failed\n";
 
1733
                                exit 1;
 
1734
                        }
 
1735
                        exec "$conf::dpkg_source -sn -x $main::cwd/$dsc 2>&1";
 
1736
                }
 
1737
                my $dir;
 
1738
                while( <PIPE> ) {
 
1739
                        print PLOG $_;
 
1740
                        $dir = $1 if /^dpkg-source: (?:info: )?extracting \S+ in (\S+)/;
 
1741
                }
 
1742
                close( PIPE );
 
1743
                if ($?) {
 
1744
                        print PLOG "dpkg-source failure -- special unpack failed\n";
 
1745
                        goto failed;
 
1746
                }
 
1747
                push( @dirs, "$main::chroot_build_dir$dir" );
 
1748
                unlink( @files );
 
1749
        }
 
1750
 
 
1751
        return @dirs;
 
1752
        
 
1753
  failed:
 
1754
        unlink( @files );
 
1755
        system( "rm", "-rf", @dirs );
 
1756
        return ();
 
1757
}
 
1758
        
 
1759
sub wait_for_srcdep_conflicts {
 
1760
        my @confl = @_;
 
1761
        
 
1762
        for(;;) {
 
1763
                sleep( $conf::srcdep_lock_wait*60 );
 
1764
                my $allgone = 1;
 
1765
                for (@confl) {
 
1766
                        /^(\d+)-(\d+)$/;
 
1767
                        my $pid = $1;
 
1768
                        if (-f "$conf::srcdep_lock_dir/$_") {
 
1769
                                if (kill( 0, $pid ) == 0 && $! == ESRCH) {
 
1770
                                        print PLOG "Ignoring stale src-dep lock $_\n";
 
1771
                                        unlink( "$conf::srcdep_lock_dir/$_" ) or
 
1772
                                                print PLOG "Cannot remove $conf::srcdep_lock_dir/$_: $!\n";
 
1773
                                }
 
1774
                                else {
 
1775
                                        $allgone = 0;
 
1776
                                        last;
 
1777
                                }
 
1778
                        }
 
1779
                }
 
1780
                last if $allgone;
 
1781
        }
 
1782
}
 
1783
 
 
1784
sub uninstall_deps {
 
1785
        my( @pkgs, @instd, @rmvd );
 
1786
 
 
1787
        lock_file( "$main::ilock_file", 1 );
 
1788
 
 
1789
        @pkgs = keys %{$main::changes->{'removed'}};
 
1790
        print "Reinstalling removed packages: @pkgs\n" if $main::debug;
 
1791
        print PLOG "Failed to reinstall removed packages!\n"
 
1792
                if !run_apt( "-y", \@instd, \@rmvd, @pkgs );
 
1793
        print "Installed were: @instd\n" if $main::debug;
 
1794
        print "Removed were: @rmvd\n" if $main::debug;
 
1795
        unset_removed( @instd );
 
1796
        unset_installed( @rmvd );
 
1797
 
 
1798
        @pkgs = keys %{$main::changes->{'installed'}};
 
1799
        print "Removing installed packages: @pkgs\n" if $main::debug;
 
1800
        print PLOG "Failed to remove installed packages!\n"
 
1801
                if !uninstall_debs( "purge", @pkgs );
 
1802
        unset_installed( @pkgs );
 
1803
 
 
1804
        unlock_file( "$main::ilock_file" );
 
1805
}
 
1806
 
 
1807
sub uninstall_debs {
 
1808
        my $mode = shift;
 
1809
        local (*PIPE);
 
1810
        
 
1811
        return 1 if !@_;
 
1812
        print "Uninstalling packages: @_\n" if $main::debug;
 
1813
        print PLOG "  $conf::sudo dpkg --$mode @_\n";
 
1814
  repeat:
 
1815
        my $output;
 
1816
        if (!open( PIPE, "$conf::sudo /usr/sbin/chroot $main::chroot_dir $conf::dpkg --$mode @_ 2>&1 </dev/null |")) {
 
1817
                print PLOG "Can't open pipe to dpkg: $!\n";
 
1818
                return 0;
 
1819
        }
 
1820
        while ( <PIPE> ) {
 
1821
                $output .= $_;
 
1822
                print PLOG $_;
 
1823
        }
 
1824
        close( PIPE );
 
1825
 
 
1826
        if ($output =~ /status database area is locked/mi) {
 
1827
                print PLOG "Another dpkg is running -- retrying later\n";
 
1828
                $output = "";
 
1829
                sleep( 2*60 );
 
1830
                goto repeat;
 
1831
        }
 
1832
        print PLOG "dpkg run to remove packages (@_) failed!\n" if $?;
 
1833
        return $? == 0;
 
1834
}
 
1835
 
 
1836
sub undo_specials {
 
1837
        my $sp;
 
1838
 
 
1839
        print "Running post scripts of special dependencies:\n" if $main::debug;
 
1840
        foreach $sp (keys %{$main::changes->{'specials'}}) {
 
1841
                print PLOG "Running post script for $sp\n";
 
1842
                if (run_script( "-e", $main::specials{$sp}->{'post'} ) != 0) {
 
1843
                        print PLOG "post script of special dependency $sp failed\n";
 
1844
                }
 
1845
                delete $main::changes->{'specials'}->{$sp};
 
1846
        }
 
1847
        foreach $sp (keys %{$main::changes->{'unpacked'}}) {
 
1848
                my @dirs = @{$main::changes->{'unpacked'}->{$sp}};
 
1849
                print PLOG "Removing special unpacked sources for $sp: @dirs\n";
 
1850
                system "rm", "-rf", @dirs;
 
1851
                delete $main::changes->{'unpacked'}->{$sp};
 
1852
        }
 
1853
}
 
1854
 
 
1855
 
 
1856
sub run_apt {
 
1857
        my $mode = shift;
 
1858
        my $inst_ret = shift;
 
1859
        my $rem_ret = shift;
 
1860
        my @to_install = @_;
 
1861
        my( $msgs, $status, $pkgs, $rpkgs );
 
1862
        local (*PIPE);
 
1863
        local (%ENV) = %ENV; # make local environment
 
1864
        # hardwire frontend for debconf to non-interactive
 
1865
        $ENV{'DEBIAN_FRONTEND'} = "noninteractive";
 
1866
 
 
1867
        @$inst_ret = ();
 
1868
        @$rem_ret = ();
 
1869
        return 1 if !@to_install;
 
1870
  repeat:
 
1871
        print PLOG "  $conf::sudo $conf::apt_get --purge $main::chroot_apt_op -q $mode install @to_install\n"
 
1872
                if $mode ne "-s";
 
1873
        $msgs = "";
 
1874
        # redirection of stdin from /dev/null so that conffile question are
 
1875
        # treated as if RETURN was pressed.
 
1876
        # dpkg since 1.4.1.18 issues an error on the conffile question if it reads
 
1877
        # EOF -- hardwire the new --force-confold option to avoid the questions.
 
1878
        if (!open( PIPE, "$conf::sudo /usr/sbin/chroot ".
 
1879
                           "$main::chroot_dir $conf::apt_get --purge ".
 
1880
                           ($main::new_dpkg ? "-o DPkg::Options::=--force-confold " : "").
 
1881
                           "-q $mode install @to_install 2>&1 </dev/null |" )) {
 
1882
                print PLOG "Can't open pipe to apt-get: $!\n";
 
1883
                return 0;
 
1884
        }
 
1885
        while( <PIPE> ) {
 
1886
                $msgs .= $_;
 
1887
                print PLOG $_ if $mode ne "-s" || $main::debug;
 
1888
        }
 
1889
        close( PIPE );
 
1890
        $status = $?;
 
1891
 
 
1892
        if ($status != 0 && $msgs =~ /^E: Packages file \S+ (has changed|is out of sync)/mi) {
 
1893
                print PLOG "$conf::sudo $conf::apt_get $main::chroot_apt_op -q update\n";
 
1894
                if (!open( PIPE, "$conf::sudo /usr/sbin/chroot $main::chroot_dir $conf::apt_get -q update 2>&1 |" )) {
 
1895
                        print PLOG "Can't open pipe to apt-get: $!\n";
 
1896
                        return 0;
 
1897
                }
 
1898
                $msgs = "";
 
1899
                while( <PIPE> ) {
 
1900
                        $msgs .= $_;
 
1901
                        print PLOG $_;
 
1902
                }
 
1903
                close( PIPE );
 
1904
                print PLOG "apt-get update failed\n" if $?;
 
1905
                $msgs = "";
 
1906
                goto repeat;
 
1907
        }
 
1908
 
 
1909
        if ($status != 0 && $msgs =~ /^Package (\S+) is a virtual package provided by:\n((^\s.*\n)*)/mi) {
 
1910
                my $to_replace = $1;
 
1911
                my @providers;
 
1912
                foreach (split( "\n", $2 )) {
 
1913
                        s/^\s*//;
 
1914
                        push( @providers, (split( /\s+/, $_ ))[0] );
 
1915
                }
 
1916
                print PLOG "$to_replace is a virtual package provided by: @providers\n";
 
1917
                my $selected;
 
1918
                if (@providers == 1) {
 
1919
                        $selected = $providers[0];
 
1920
                        print PLOG "Using $selected (only possibility)\n";
 
1921
                }
 
1922
                elsif (exists $conf::alternatives{$to_replace}) {
 
1923
                        $selected = $conf::alternatives{$to_replace};
 
1924
                        print PLOG "Using $selected (selected in sbuildrc)\n";
 
1925
                }
 
1926
                else {
 
1927
                        $selected = $providers[0];
 
1928
                        print PLOG "Using $selected (no default, using first one)\n";
 
1929
                }
 
1930
                
 
1931
                @to_install = grep { $_ ne $to_replace } @to_install;
 
1932
                push( @to_install, $selected );
 
1933
                
 
1934
                goto repeat;
 
1935
        }
 
1936
        
 
1937
        if ($status != 0 && ($msgs =~ /^E: Could( not get lock|n.t lock)/mi ||
 
1938
                                                 $msgs =~ /^dpkg: status database area is locked/mi)) {
 
1939
                print PLOG "Another apt-get or dpkg is running -- retrying later\n";
 
1940
                sleep( 2*60 );
 
1941
                goto repeat;
 
1942
        }
 
1943
 
 
1944
        # check for errors that are probably caused by something broken in
 
1945
        # the build environment, and give back the packages.
 
1946
        if ($status != 0 && $mode ne "-s" &&
 
1947
                (($msgs =~ /^E: dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem./mi) ||
 
1948
                ($msgs =~ /^dpkg: parse error, in file `\/.+\/var\/lib\/dpkg\/(?:available|status)' near line/mi) ||
 
1949
                ($msgs =~ /^E: Unmet dependencies. Try 'apt-get -f install' with no packages \(or specify a solution\)\./mi))) {
 
1950
                print PLOG "Build environment unusable, giving back\n";
 
1951
                $main::pkg_fail_stage = "install-deps-env";
 
1952
        }
 
1953
 
 
1954
        if ($status != 0 && $mode ne "-s" &&
 
1955
                (($msgs =~ /^E: Unable to fetch some archives, maybe run apt-get update or try with/mi))) {
 
1956
                print PLOG "Unable to fetch build-depends\n";
 
1957
                $main::pkg_fail_stage = "install-deps-env";
 
1958
        }
 
1959
        
 
1960
        $pkgs = $rpkgs = "";
 
1961
        if ($msgs =~ /NEW packages will be installed:\n((^[     ].*\n)*)/mi) {
 
1962
                ($pkgs = $1) =~ s/^[    ]*((.|\n)*)\s*$/$1/m;
 
1963
                $pkgs =~ s/\*//g;
 
1964
        }
 
1965
        if ($msgs =~ /packages will be REMOVED:\n((^[   ].*\n)*)/mi) {
 
1966
                ($rpkgs = $1) =~ s/^[   ]*((.|\n)*)\s*$/$1/m;
 
1967
                $rpkgs =~ s/\*//g;
 
1968
        }
 
1969
        @$inst_ret = split( /\s+/, $pkgs );
 
1970
        @$rem_ret = split( /\s+/, $rpkgs );
 
1971
 
 
1972
        print PLOG "apt-get failed.\n" if $status && $mode ne "-s";
 
1973
        return $mode eq "-s" || $status == 0;
 
1974
}
 
1975
 
 
1976
sub filter_dependencies {
 
1977
        my $dependencies = shift;
 
1978
        my $pos_list = shift;
 
1979
        my $neg_list = shift;
 
1980
        my $special_list = shift;
 
1981
        my($dep, $d, $name, %names);
 
1982
 
 
1983
        print PLOG "Checking for already installed source dependencies...\n";
 
1984
        
 
1985
        @$pos_list = @$neg_list = @$special_list = ();
 
1986
        foreach $d (@$dependencies) {
 
1987
                my $name = $d->{'Package'};
 
1988
                $names{$name} = 1 if $name !~ /^\*/;
 
1989
                foreach (@{$d->{'Alternatives'}}) {
 
1990
                        my $name = $_->{'Package'};
 
1991
                        $names{$name} = 1 if $name !~ /^\*/;
 
1992
                }
 
1993
        }
 
1994
        my $status = get_dpkg_status( keys %names );
 
1995
 
 
1996
        foreach $dep (@$dependencies) {
 
1997
                $name = $dep->{'Package'};
 
1998
                next if !$name;
 
1999
                if ($name =~ /^\*/) {
 
2000
                        my $doit = 1;
 
2001
                        if (exists $main::specials{$name}->{'condition'}) {
 
2002
                                print "Testing condition for special dependency $name:\n"
 
2003
                                        if $main::debug;
 
2004
                                if (run_script("+e",$main::specials{$name}->{'condition'})!=0){
 
2005
                                        print "Condition false -> not running scripts\n"
 
2006
                                                if $main::debug;
 
2007
                                        $doit = 0;
 
2008
                                }
 
2009
                        }
 
2010
                        push( @$special_list, $name ) if $doit;
 
2011
                        next;
 
2012
                }
 
2013
                my $stat = $status->{$name};
 
2014
                if ($dep->{'Neg'}) {
 
2015
                        if ($stat->{'Installed'}) {
 
2016
                                my ($rel, $vers) = ($dep->{'Rel'}, $dep->{'Version'});
 
2017
                                my $ivers = $stat->{'Version'};
 
2018
                                if (!$rel || version_cmp( $ivers, $rel, $vers )){
 
2019
                                        print "$name: neg dep, installed, not versioned or ",
 
2020
                                                  "version relation satisfied --> remove\n" if $main::debug;
 
2021
                                        print PLOG "$name: installed (negative dependency)";
 
2022
                                        print PLOG " (bad version $ivers $rel $vers)"
 
2023
                                                if $rel;
 
2024
                                        print PLOG "\n";
 
2025
                                        push( @$neg_list, $name );
 
2026
                                }
 
2027
                                else {
 
2028
                                        print PLOG "$name: installed (negative dependency)",
 
2029
                                                           "(but version ok $ivers $rel $vers)\n";
 
2030
                                }
 
2031
                        }
 
2032
                        else {
 
2033
                                print "$name: neg dep, not installed\n" if $main::debug;
 
2034
                                print PLOG "$name: already deinstalled\n";
 
2035
                        }
 
2036
                        next;
 
2037
                }
 
2038
                
 
2039
                my $is_satisfied = 0;
 
2040
                my $installable = "";
 
2041
                my $upgradeable = "";
 
2042
                my $downgradeable = "";
 
2043
                foreach $d ($dep, @{$dep->{'Alternatives'}}) {
 
2044
                        my ($name, $rel, $vers) =
 
2045
                                ($d->{'Package'}, $d->{'Rel'}, $d->{'Version'});
 
2046
                        my $stat = $status->{$name};
 
2047
                        if (!$stat->{'Installed'}) {
 
2048
                                print "$name: pos dep, not installed\n" if $main::debug;
 
2049
                                print PLOG "$name: missing\n";
 
2050
                                my $exists = package_exists($name);
 
2051
                                print PLOG "$name: does not exist\n" if not $exists;
 
2052
                                $installable = $name if !$installable and $exists;
 
2053
                                next;
 
2054
                        }
 
2055
                        my $ivers = $stat->{'Version'};
 
2056
                        if (!$rel || version_cmp( $ivers, $rel, $vers )) {
 
2057
                                print "$name: pos dep, installed, no versioned dep or ",
 
2058
                                          "version ok\n" if $main::debug;
 
2059
                                print PLOG "$name: already installed ($ivers";
 
2060
                                print PLOG " $rel $vers is satisfied"
 
2061
                                        if $rel;
 
2062
                                print PLOG ")\n";
 
2063
                                $is_satisfied = 1;
 
2064
                                last;
 
2065
                        }
 
2066
                        print "$name: vers dep, installed $ivers ! $rel $vers\n"
 
2067
                                if $main::debug;
 
2068
                        print PLOG "$name: non-matching version installed ",
 
2069
                                  "($ivers ! $rel $vers)\n";
 
2070
                        if ($rel =~ /^</ ||
 
2071
                                ($rel eq '=' && version_cmp($ivers, '>>', $vers))) {
 
2072
                                print "$name: would be a downgrade!\n" if $main::debug;
 
2073
                                print PLOG "$name: would have to downgrade!\n";
 
2074
                                $downgradeable = $name if !$downgradeable;
 
2075
                        }
 
2076
                        else {
 
2077
                                $upgradeable = $name if !$upgradeable;
 
2078
                        }
 
2079
                }
 
2080
                if (!$is_satisfied) {
 
2081
                        if ($upgradeable) {
 
2082
                                print "using $upgradeable for upgrade\n" if $main::debug;
 
2083
                                push( @$pos_list, $upgradeable );
 
2084
                        }
 
2085
                        elsif ($installable) {
 
2086
                                print "using $installable for install\n" if $main::debug;
 
2087
                                push( @$pos_list, $installable );
 
2088
                        }
 
2089
                        elsif ($downgradeable) {
 
2090
                                print PLOG "To satisfy this dependency the package(s) would ",
 
2091
                                                   "have\n",
 
2092
                                                   "to be downgraded; this is not implemented.\n";
 
2093
                                return 0;
 
2094
                        }
 
2095
                        else {
 
2096
                                # None of the build-deps exist. Return the
 
2097
                                # first one so that we get a useful dep-wait.
 
2098
                                $installable = $dep->{'Package'};
 
2099
                                print "using $installable for install (does not exist)\n" if $main::debug;
 
2100
                                push( @$pos_list, $installable );
 
2101
                        }
 
2102
                }
 
2103
        }
 
2104
 
 
2105
        return 1;
 
2106
}
 
2107
 
 
2108
sub check_dependencies {
 
2109
        my $dependencies = shift;
 
2110
        my $fail = "";
 
2111
        my($dep, $d, $name, %names);
 
2112
 
 
2113
        print PLOG "Checking correctness of source dependencies...\n";
 
2114
        
 
2115
        foreach $d (@$dependencies) {
 
2116
                my $name = $d->{'Package'};
 
2117
                $names{$name} = 1 if $name !~ /^\*/;
 
2118
                foreach (@{$d->{'Alternatives'}}) {
 
2119
                        my $name = $_->{'Package'};
 
2120
                        $names{$name} = 1 if $name !~ /^\*/;
 
2121
                }
 
2122
        }
 
2123
        foreach $name (@main::toolchain_pkgs) {
 
2124
                $names{$name} = 1;
 
2125
        }
 
2126
        my $status = get_dpkg_status( keys %names );
 
2127
 
 
2128
        foreach $dep (@$dependencies) {
 
2129
                $name = $dep->{'Package'};
 
2130
                next if $name =~ /^\*/;
 
2131
                my $stat = $status->{$name};
 
2132
                if ($dep->{'Neg'}) {
 
2133
                    if ($stat->{'Installed'}) {
 
2134
                                if (!$dep->{'Rel'}) {
 
2135
                                        $fail .= "$name(still installed) ";
 
2136
                                }
 
2137
                                elsif (version_cmp($stat->{'Version'}, $dep->{'Rel'},
 
2138
                                                                   $dep->{'Version'})) {
 
2139
                                        $fail .= "$name(inst $stat->{'Version'} $dep->{'Rel'} ".
 
2140
                                                         "conflicted $dep->{'Version'})\n";
 
2141
                                }
 
2142
                        }
 
2143
                }
 
2144
                else {
 
2145
                        my $is_satisfied = 0;
 
2146
                        my $f = "";
 
2147
                        foreach $d ($dep, @{$dep->{'Alternatives'}}) {
 
2148
                                my $name = $d->{'Package'};
 
2149
                                my $stat = $status->{$name};
 
2150
                                if (!$stat->{'Installed'}) {
 
2151
                                        $f =~ s/ $/\|/ if $f;
 
2152
                                        $f .= "$name(missing) ";
 
2153
                                }
 
2154
                                elsif ($d->{'Rel'} &&
 
2155
                                           !version_cmp( $stat->{'Version'}, $d->{'Rel'},
 
2156
                                                                         $d->{'Version'} )) {
 
2157
                                        $f =~ s/ $/\|/ if $f;
 
2158
                                        $f .= "$name(inst $stat->{'Version'} ! $d->{'Rel'} ".
 
2159
                                                  "wanted $d->{'Version'}) ";
 
2160
                                }
 
2161
                                else {
 
2162
                                        $is_satisfied = 1;
 
2163
                                }
 
2164
                        }
 
2165
                        if (!$is_satisfied) {
 
2166
                                $fail .= $f;
 
2167
                        }
 
2168
                }
 
2169
        }
 
2170
        $fail =~ s/\s+$//;
 
2171
        if (!$fail && @main::toolchain_pkgs) {
 
2172
                print PLOG "Toolchain package versions:";
 
2173
                foreach $name (@main::toolchain_pkgs) {
 
2174
                        print PLOG ' ' . $name . '_' . $status->{$name}->{'Version'};
 
2175
                }
 
2176
                print PLOG "\n";
 
2177
        }
 
2178
 
 
2179
        return $fail;
 
2180
}
 
2181
 
 
2182
sub get_dpkg_status {
 
2183
        my @interest = @_;
 
2184
        my %result;
 
2185
        local( *STATUS );
 
2186
 
 
2187
        return () if !@_;
 
2188
        print "Requesting dpkg status for packages: @interest\n"
 
2189
                if $main::debug;
 
2190
        if (!open( STATUS, "<$main::chroot_dir/var/lib/dpkg/status" )) {
 
2191
                print PLOG "Can't open $main::chroot_dir/var/lib/dpkg/status: $!\n";
 
2192
                return ();
 
2193
        }
 
2194
        local( $/ ) = "";
 
2195
        while( <STATUS> ) {
 
2196
                my( $pkg, $status, $version, $provides );
 
2197
                /^Package:\s*(.*)\s*$/mi and $pkg = $1;
 
2198
                /^Status:\s*(.*)\s*$/mi and $status = $1;
 
2199
                /^Version:\s*(.*)\s*$/mi and $version = $1;
 
2200
                /^Provides:\s*(.*)\s*$/mi and $provides = $1;
 
2201
                if (!$pkg) {
 
2202
                        print PLOG "sbuild: parse error in $main::chroot_dir/var/lib/dpkg/status: ",
 
2203
                                           "no Package: field\n";
 
2204
                        next;
 
2205
                }
 
2206
                print "$pkg ($version) status: $status\n" if $main::debug >= 2;
 
2207
                if (!$status) {
 
2208
                        print PLOG "sbuild: parse error in $main::chroot_dir/var/lib/dpkg/status: ",
 
2209
                                           "no Status: field for package $pkg\n";
 
2210
                        next;
 
2211
                }
 
2212
                if ($status !~ /\sinstalled$/) {
 
2213
                        $result{$pkg}->{'Installed'} = 0
 
2214
                                if !(exists($result{$pkg}) &&
 
2215
                                         $result{$pkg}->{'Version'} eq '=*=PROVIDED=*=');
 
2216
                        next;
 
2217
                }
 
2218
                if (!$version) {
 
2219
                        print PLOG "sbuild: parse error in $main::chroot_dir/var/lib/dpkg/status: ",
 
2220
                                           "no Version: field for package $pkg\n";
 
2221
                        next;
 
2222
                }
 
2223
                $result{$pkg} = { Installed => 1, Version => $version }
 
2224
                        if isin( $pkg, @interest );
 
2225
                if ($provides) {
 
2226
                        foreach (split( /\s*,\s*/, $provides )) {
 
2227
                                $result{$_} = { Installed => 1, Version => '=*=PROVIDED=*=' }
 
2228
                                        if (isin( $_, @interest ) &&
 
2229
                                                $result{$_}->{'Installed'} != 1);
 
2230
                        }
 
2231
                }
 
2232
        }
 
2233
        close( STATUS );
 
2234
        return \%result;
 
2235
}
 
2236
 
 
2237
sub version_cmp {
 
2238
        my $v1 = shift;
 
2239
        my $rel = shift;
 
2240
        my $v2 = shift;
 
2241
        if ($v1 eq "=*=PROVIDED=*=") {
 
2242
                return 0;
 
2243
        }
 
2244
        
 
2245
        system "$conf::dpkg", "--compare-versions", $v1, $rel, $v2;
 
2246
        return $? == 0;
 
2247
}
 
2248
 
 
2249
sub run_script {
 
2250
        my $e_mode = shift;
 
2251
        my $x_mode = "";
 
2252
        my $script = shift;
 
2253
 
 
2254
        if ($main::debug >= 2) {
 
2255
                $x_mode = "set -x -v\n";
 
2256
        }
 
2257
        elsif ($main::debug)  {
 
2258
                print "Running script:\n  ",
 
2259
                join( "\n  ", split( "\n", "set $e_mode\n$script" )), "\n";
 
2260
        }
 
2261
        my $pid = fork();
 
2262
        if (!defined $pid) {
 
2263
                print PLOG "Can't fork: $! -- can't execute script\n";
 
2264
                return 1;
 
2265
        }
 
2266
        if ($pid == 0) {
 
2267
                setpgrp( 0, $$ );
 
2268
                open( STDOUT, ">&PLOG" );
 
2269
                open( STDERR, ">&PLOG" );
 
2270
                if ($main::chroot_dir) {
 
2271
                        exec "$conf::sudo", "/usr/sbin/chroot", "$main::cwd/$main::chroot_dir",
 
2272
                                 "$conf::su", $main::username, "-s", "/bin/sh", "-c",
 
2273
                                 "cd /build/$main::username\nset $e_mode\n$x_mode$script";
 
2274
                }
 
2275
                else {
 
2276
                        exec "/bin/sh", "-c", "set $e_mode\n$x_mode$script";
 
2277
                }
 
2278
                die "Can't exec /bin/sh: $!\n";
 
2279
        }
 
2280
        wait;
 
2281
        print "Script return value: $?\n" if $main::debug;
 
2282
        return $?
 
2283
}
 
2284
 
 
2285
 
 
2286
sub read_deps {
 
2287
        my @for_pkgs = @_;
 
2288
        my $fname;
 
2289
        local( *F );
 
2290
 
 
2291
        open( F, $fname = "<$conf::source_dependencies-$main::distribution" )
 
2292
                or open( F, $fname = "<$conf::source_dependencies" )
 
2293
                or die "Cannot open $conf::source_dependencies: $!\n";
 
2294
        $fname = substr( $fname, 1 );
 
2295
        print "Reading source dependencies from $fname\n"
 
2296
                if $main::debug;
 
2297
        while( <F> ) {
 
2298
                chomp;
 
2299
                next if /^\s*$/ || /^\s*#/;
 
2300
                while( /\\$/ ) {
 
2301
                        chop;
 
2302
                        $_ .= <F>;
 
2303
                        chomp;
 
2304
                }
 
2305
                if (/^(\*\*?[\w\d.+-]+):\s*$/) {
 
2306
                        # is a special definition
 
2307
                        my $sp = $1;
 
2308
                        get_special( $fname, $sp, \*F );
 
2309
                        next;
 
2310
                }
 
2311
                if (/^abbrev\s+([\w\d.+-]+)\s*=\s*(.*)\s*$/) {
 
2312
                        my ($abbrev, $def) = ($1, $2);
 
2313
                        parse_one_srcdep( $abbrev, $def, \%main::abbrevs );
 
2314
                        next;
 
2315
                }
 
2316
                if (!/^([a-zA-Z\d.+-]+):\s*(.*)\s*$/) {
 
2317
                        warn "Syntax error in line $. in $fname\n";
 
2318
                        next;
 
2319
                }
 
2320
                my( $pkg, $deps ) = ($1, $2);
 
2321
                if (exists $main::deps{$pkg}) {
 
2322
                        warn "Ignoring double entry for package $pkg at line $. ".
 
2323
                                 "in $fname\n";
 
2324
                        next;
 
2325
                }
 
2326
                next if !isin( $pkg, @for_pkgs );
 
2327
                parse_one_srcdep( $pkg, $deps, \%main::deps );
 
2328
        }
 
2329
        close( F );
 
2330
 
 
2331
        foreach (@main::manual_srcdeps) {
 
2332
                if (!/^([fa])([a-zA-Z\d.+-]+):\s*(.*)\s*$/) {
 
2333
                        warn "Syntax error in manual source dependency: ",
 
2334
                                 substr( $_, 1 ), "\n";
 
2335
                        next;
 
2336
                }
 
2337
                my ($mode, $pkg, $deps) = ($1, $2, $3);
 
2338
                next if !isin( $pkg, @for_pkgs );
 
2339
                @{$main::deps{$pkg}} = () if $mode eq 'f';
 
2340
                parse_one_srcdep( $pkg, $deps, \%main::deps );
 
2341
        }
 
2342
 
 
2343
        # substitute abbrevs and warn about undefined special deps
 
2344
        my( $pkg, $i, %warned );
 
2345
        foreach $pkg (keys %main::deps) {
 
2346
          repeat:
 
2347
                my $dl = $main::deps{$pkg};
 
2348
                for( $i = 0; $i < @$dl; ++$i ) {
 
2349
                        my $dep = $dl->[$i];
 
2350
                        my $name = $dep->{'Package'};
 
2351
                        if ($name =~ /^\*/) {
 
2352
                                if (!$warned{$name} && !exists $main::specials{$name}) {
 
2353
                                        warn "Warning: $pkg: No definition for special ",
 
2354
                                                 "dependency $name!\n";
 
2355
                                        $warned{$name}++;
 
2356
                                }
 
2357
                        }
 
2358
                        elsif (defined $main::abbrevs{$name}) {
 
2359
                                my @l = @{$main::abbrevs{$name}};
 
2360
                                if (defined $dep->{'Alternatives'}) {
 
2361
                                        warn "Warning: $pkg: abbrev $name not allowed ",
 
2362
                                                 "in alternative\n";
 
2363
                                        @l = ();
 
2364
                                }
 
2365
                                if ($dep->{'Neg'}) {
 
2366
                                        warn "Warning: $pkg: Negation of abbrev $name ",
 
2367
                                                 "not allowed\n";
 
2368
                                        @l = ();
 
2369
                                }
 
2370
                                if ($dep->{'Rel'}) {
 
2371
                                        warn "Warning: $pkg: No relation with abbrev $name ",
 
2372
                                                 "allowed\n";
 
2373
                                        @l = ();
 
2374
                                }
 
2375
                                if (my $ov = $dep->{'Override'}) {
 
2376
                                        @l = map { my $x = copy($_);
 
2377
                                                           $x->{'Override'} = $ov; $x } @l;
 
2378
                                }
 
2379
                                splice @$dl, $i, 1, @l;
 
2380
                                goto repeat;
 
2381
                        }
 
2382
                        elsif (defined $dep->{'Alternatives'}) {
 
2383
                                my $alt;
 
2384
                                foreach $alt (@{$dep->{'Alternatives'}}) {
 
2385
                                        if (defined $main::abbrevs{$alt->{'Package'}}) {
 
2386
                                                warn "Warning: $pkg: abbrev $alt->{'Package'} not ",
 
2387
                                                         "allowed in alternative\n";
 
2388
                                                splice @$dl, $i, 1;
 
2389
                                        }
 
2390
                                }
 
2391
                        }
 
2392
                }
 
2393
        }
 
2394
}
 
2395
 
 
2396
sub copy {
 
2397
        my $r = shift;
 
2398
        my $new;
 
2399
 
 
2400
        if (ref($r) eq "HASH") {
 
2401
                $new = { };
 
2402
                foreach (keys %$r) {
 
2403
                        $new->{$_} = copy($r->{$_});
 
2404
                }
 
2405
        }
 
2406
        elsif (ref($r) eq "ARRAY") {
 
2407
                my $i;
 
2408
                $new = [ ];
 
2409
                for( $i = 0; $i < @$r; ++$i ) {
 
2410
                        $new->[$i] = copy($r->[$i]);
 
2411
                }
 
2412
        }
 
2413
        elsif (!ref($r)) {
 
2414
                $new = $r;
 
2415
        }
 
2416
        else {
 
2417
                die "unknown ref type in copy\n";
 
2418
        }
 
2419
        
 
2420
        return $new;
 
2421
}
 
2422
 
 
2423
sub merge_pkg_build_deps {
 
2424
        my $pkg = shift;
 
2425
        my $depends = shift;
 
2426
        my $dependsi = shift;
 
2427
        my $conflicts = shift;
 
2428
        my $conflictsi = shift;
 
2429
        my (@l, $dep);
 
2430
 
 
2431
        print PLOG "** Using build dependencies supplied by package:\n";
 
2432
        print PLOG "Build-Depends: $depends\n" if $depends;
 
2433
        print PLOG "Build-Depends-Indep: $dependsi\n" if $dependsi;
 
2434
        print PLOG "Build-Conflicts: $conflicts\n" if $conflicts;
 
2435
        print PLOG "Build-Conflicts-Indep: $conflictsi\n" if $conflictsi;
 
2436
 
 
2437
        my $old_deps = copy($main::deps{$pkg});
 
2438
        # keep deps from the central file marked as overrides (& prefix)
 
2439
        if ( $main::useSNAP ) {
 
2440
            $dep->{'Package'} = "gcc-snapshot";
 
2441
            $dep->{'Override'} = 1;
 
2442
            push( @{$main::deps{$pkg}}, $dep );
 
2443
        }
 
2444
        foreach $dep (@{$main::deps{$pkg}}) {
 
2445
                if ($dep->{'Override'}) {
 
2446
                        print PLOG "Added override: ",
 
2447
                                  (map { ($_->{'Neg'} ? "!" : "") .
 
2448
                                             $_->{'Package'} .
 
2449
                                                 ($_->{'Rel'} ? " ($_->{'Rel'} $_->{'Version'})":"") }
 
2450
                                        scalar($dep), @{$dep->{'Alternatives'}}), "\n";
 
2451
                        push( @l, $dep );
 
2452
                }
 
2453
        }
 
2454
 
 
2455
        $conflicts = join( ", ", map { "!$_" } split( /\s*,\s*/, $conflicts ));
 
2456
        $conflictsi = join( ", ", map { "!$_" } split( /\s*,\s*/, $conflictsi ));
 
2457
        
 
2458
        my $deps = $depends . ", " . $conflicts;
 
2459
        $deps .= ", " . $dependsi . ", " . $conflictsi if $main::build_arch_all;
 
2460
        # For the moment, we treat multiarch-annotated build-dependencies as
 
2461
        # the same as any others because we're not implementing a
 
2462
        # cross-buildd.
 
2463
        $deps =~ s/:any//g;
 
2464
        $deps =~ s/:native//g;
 
2465
 
 
2466
        @{$main::deps{$pkg}} = @l;
 
2467
        print "Merging pkg deps: $deps\n" if $main::debug;
 
2468
        parse_one_srcdep( $pkg, $deps, \%main::deps );
 
2469
 
 
2470
        my $missing = (cmp_dep_lists( $old_deps, $main::deps{$pkg} ))[1];
 
2471
 
 
2472
        # read list of build-essential packages (if not yet done) and expand their
 
2473
        # dependencies (those are implicitly essential)
 
2474
        if (!defined($main::deps{'ESSENTIAL'})) {
 
2475
                my $ess = read_build_essential();
 
2476
                parse_one_srcdep( 'ESSENTIAL', $ess, \%main::deps );
 
2477
        }
 
2478
        my ($exp_essential, $exp_pkgdeps, $filt_essential, $filt_pkgdeps);
 
2479
        $exp_essential = expand_dependencies( $main::deps{'ESSENTIAL'} );
 
2480
        print "Dependency-expanded build essential packages:\n",
 
2481
                  format_deps(@$exp_essential), "\n" if $main::debug;
 
2482
 
 
2483
        # populate toolchain_pkgs from toolchain_regexes and essential packages.
 
2484
        @main::toolchain_pkgs = ();
 
2485
        foreach my $tpkg (@$exp_essential) {
 
2486
                foreach my $regex (@conf::toolchain_regex) {
 
2487
                        push @main::toolchain_pkgs,$tpkg->{'Package'}
 
2488
                                if $tpkg->{'Package'} =~ m,^$regex,;
 
2489
                }
 
2490
        }
 
2491
        return if !@$missing;
 
2492
 
 
2493
        # remove missing central deps that are essential
 
2494
        ($filt_essential, $missing) = cmp_dep_lists( $missing, $exp_essential );
 
2495
        print PLOG "** Filtered missing central deps that are build-essential:\n",
 
2496
                           format_deps(@$filt_essential), "\n"
 
2497
                                   if @$filt_essential;
 
2498
 
 
2499
        # if some build deps are virtual packages, replace them by an alternative
 
2500
        # over all providing packages
 
2501
        $exp_pkgdeps = expand_virtuals( $main::deps{$pkg} );
 
2502
        print "Provided-expanded build deps:\n",
 
2503
                  format_deps(@$exp_pkgdeps), "\n" if $main::debug;
 
2504
 
 
2505
        # now expand dependencies of package build deps
 
2506
        $exp_pkgdeps = expand_dependencies( $exp_pkgdeps );
 
2507
        print "Dependency-expanded build deps:\n",
 
2508
                  format_deps(@$exp_pkgdeps), "\n" if $main::debug;
 
2509
        $main::additional_deps = $exp_pkgdeps;
 
2510
 
 
2511
        # remove missing central deps that are dependencies of build deps
 
2512
        ($filt_pkgdeps, $missing) = cmp_dep_lists( $missing, $exp_pkgdeps );
 
2513
        print PLOG "** Filtered missing central deps that are dependencies of ",
 
2514
                           "or provide build-deps:\n",
 
2515
                           format_deps(@$filt_pkgdeps), "\n"
 
2516
                                   if @$filt_pkgdeps;
 
2517
 
 
2518
        # remove comment package names
 
2519
        push( @$main::additional_deps,
 
2520
                  grep { $_->{'Neg'} && $_->{'Package'} =~ /^needs-no-/ } @$missing );
 
2521
        $missing = [ grep { !($_->{'Neg'} &&
 
2522
                                              ($_->{'Package'} =~ /^this-package-does-not-exist/ ||
 
2523
                                                   $_->{'Package'} =~ /^needs-no-/)) } @$missing ];
 
2524
 
 
2525
        print PLOG "**** Warning:\n",
 
2526
                           "**** The following central src deps are ",
 
2527
                           "(probably) missing:\n  ", format_deps(@$missing), "\n"
 
2528
                                   if @$missing;
 
2529
}
 
2530
 
 
2531
sub cmp_dep_lists {
 
2532
        my $list1 = shift;
 
2533
        my $list2 = shift;
 
2534
        my ($dep, @common, @missing);
 
2535
 
 
2536
        foreach $dep (@$list1) {
 
2537
                my $found = 0;
 
2538
 
 
2539
                if ($dep->{'Neg'}) {
 
2540
                        foreach (@$list2) {
 
2541
                                if ($dep->{'Package'} eq $_->{'Package'} && $_->{'Neg'}) {
 
2542
                                        $found = 1;
 
2543
                                        last;
 
2544
                                }
 
2545
                        }
 
2546
                }
 
2547
                else {
 
2548
                        my $al = get_altlist($dep);
 
2549
                        foreach (@$list2) {
 
2550
                                if (is_superset( get_altlist($_), $al )) {
 
2551
                                        $found = 1;
 
2552
                                        last;
 
2553
                                }
 
2554
                        }
 
2555
                }
 
2556
 
 
2557
                if ($found) {
 
2558
                        push( @common, $dep );
 
2559
                }
 
2560
                else {
 
2561
                        push( @missing, $dep );
 
2562
                }
 
2563
        }
 
2564
        return (\@common, \@missing);
 
2565
}
 
2566
 
 
2567
sub get_altlist {
 
2568
        my $dep = shift;
 
2569
        my %l;
 
2570
 
 
2571
        foreach (scalar($dep), @{$dep->{'Alternatives'}}) {
 
2572
                $l{$_->{'Package'}} = 1 if !$_->{'Neg'};
 
2573
        }
 
2574
        return \%l;
 
2575
}
 
2576
 
 
2577
sub is_superset {
 
2578
        my $l1 = shift;
 
2579
        my $l2 = shift;
 
2580
 
 
2581
        foreach (keys %$l2) {
 
2582
                return 0 if !exists $l1->{$_};
 
2583
        }
 
2584
        return 1;
 
2585
}
 
2586
 
 
2587
sub read_build_essential {
 
2588
        my @essential;
 
2589
        local (*F);
 
2590
 
 
2591
        if (open( F, "$main::chroot_dir/usr/share/doc/build-essential/essential-packages-list" )) {
 
2592
                while( <F> ) {
 
2593
                        last if $_ eq "\n";
 
2594
                }
 
2595
                while( <F> ) {
 
2596
                        chomp;
 
2597
                        push( @essential, $_ ) if $_ !~ /^\s*$/;
 
2598
                }
 
2599
                close( F );
 
2600
        }
 
2601
        else {
 
2602
                warn "Cannot open $main::chroot_dir/usr/share/doc/build-essential/essential-packages-list: $!\n";
 
2603
        }
 
2604
 
 
2605
        if (open( F, "$main::chroot_dir/usr/share/doc/build-essential/list" )) {
 
2606
                while( <F> ) {
 
2607
                        last if $_ eq "BEGIN LIST OF PACKAGES\n";
 
2608
                }
 
2609
                while( <F> ) {
 
2610
                        chomp;
 
2611
                        last if $_ eq "END LIST OF PACKAGES";
 
2612
                        next if /^\s/ || /^$/;
 
2613
                        push( @essential, $_ );
 
2614
                }
 
2615
                close( F );
 
2616
        }
 
2617
        else {
 
2618
                warn "Cannot open $main::chroot_dir/usr/share/doc/build-essential/list: $!\n";
 
2619
        }
 
2620
 
 
2621
        return join( ", ", @essential );
 
2622
}
 
2623
 
 
2624
sub expand_dependencies {
 
2625
        my $dlist = shift;
 
2626
        my (@to_check, @result, %seen, $check, $dep);
 
2627
 
 
2628
        foreach $dep (@$dlist) {
 
2629
                next if $dep->{'Neg'} || $dep->{'Package'} =~ /^\*/;
 
2630
                foreach (scalar($dep), @{$dep->{'Alternatives'}}) {
 
2631
                        my $name = $_->{'Package'};
 
2632
                        push( @to_check, $name );
 
2633
                        $seen{$name} = 1;
 
2634
                }
 
2635
                push( @result, copy($dep) );
 
2636
        }
 
2637
 
 
2638
        while( @to_check ) {
 
2639
                my $deps = get_dependencies( @to_check );
 
2640
                my @check = @to_check;
 
2641
                @to_check = ();
 
2642
                foreach $check (@check) {
 
2643
                        foreach (split( /\s*,\s*/, $deps->{$check} )) {
 
2644
                                foreach (split( /\s*\|\s*/, $_ )) {
 
2645
                                        my $pkg = (/^([^\s([]+)/)[0];
 
2646
                                        if (!$seen{$pkg}) {
 
2647
                                                push( @to_check, $pkg );
 
2648
                                                push( @result, { Package => $pkg, Neg => 0 } );
 
2649
                                                $seen{$pkg} = 1;
 
2650
                                        }
 
2651
                                }
 
2652
                        }
 
2653
                }
 
2654
        }
 
2655
        
 
2656
        return \@result;
 
2657
}
 
2658
 
 
2659
sub expand_virtuals {
 
2660
        my $dlist = shift;
 
2661
        my ($dep, %names, @new_dlist);
 
2662
 
 
2663
        foreach $dep (@$dlist) {
 
2664
                foreach (scalar($dep), @{$dep->{'Alternatives'}}) {
 
2665
                        $names{$_->{'Package'}} = 1;
 
2666
                }
 
2667
        }
 
2668
        my $provided_by = get_virtuals( keys %names );
 
2669
 
 
2670
        foreach $dep (@$dlist) {
 
2671
                my %seen;
 
2672
                foreach (scalar($dep), @{$dep->{'Alternatives'}}) {
 
2673
                        my $name = $_->{'Package'};
 
2674
                        $seen{$name} = 1;
 
2675
                        if (exists $provided_by->{$name}) {
 
2676
                                foreach( keys %{$provided_by->{$name}} ) {
 
2677
                                        $seen{$_} = 1;
 
2678
                                }
 
2679
                        }
 
2680
                }
 
2681
                my @l = map { { Package => $_, Neg => 0 } } keys %seen;
 
2682
                my $l = shift @l;
 
2683
                foreach (@l) {
 
2684
                        push( @{$l->{'Alternatives'}}, $_ );
 
2685
                }
 
2686
                push( @new_dlist, $l );
 
2687
        }
 
2688
 
 
2689
        return \@new_dlist;
 
2690
}
 
2691
                
 
2692
sub get_dependencies {
 
2693
        local(*PIPE);
 
2694
        my %deps;
 
2695
        
 
2696
        open( PIPE, "$conf::sudo /usr/sbin/chroot $main::chroot_dir $conf::apt_cache show @_ 2>&1 |" )
 
2697
                or die "Cannot start $conf::apt_cache $main::chroot_apt_op: $!\n";
 
2698
        local($/) = "";
 
2699
        while( <PIPE> ) {
 
2700
                my ($name, $dep, $predep);
 
2701
                /^Package:\s*(.*)\s*$/mi and $name = $1;
 
2702
                next if !$name || $deps{$name};
 
2703
                /^Depends:\s*(.*)\s*$/mi and $dep = $1;
 
2704
                /^Pre-Depends:\s*(.*)\s*$/mi and $predep = $1;
 
2705
                $dep .= ", " if $dep && $predep;
 
2706
                $dep .= $predep;
 
2707
                $deps{$name} = $dep;
 
2708
        }
 
2709
        close( PIPE );
 
2710
        die "$conf::apt_cache exit status $?\n" if $?;
 
2711
 
 
2712
        return \%deps;
 
2713
}
 
2714
                
 
2715
sub get_virtuals {
 
2716
        local(*PIPE);
 
2717
 
 
2718
        open( PIPE, "$conf::sudo /usr/sbin/chroot $main::chroot_dir $conf::apt_cache showpkg @_ 2>&1 |" )
 
2719
                or die "Cannot start $conf::apt_cache $main::chroot_apt_op: $!\n";
 
2720
        my $name;
 
2721
        my $in_rprov = 0;
 
2722
        my %provided_by;
 
2723
        while( <PIPE> ) {
 
2724
                if (/^Package:\s*(\S+)\s*$/) {
 
2725
                        $name = $1;
 
2726
                }
 
2727
                elsif (/^Reverse Provides: $/) {
 
2728
                        $in_rprov = 1;
 
2729
                }
 
2730
                elsif ($in_rprov && /^(\w+):\s/) {
 
2731
                        $in_rprov = 0;
 
2732
                }
 
2733
                elsif ($in_rprov && /^(\S+)\s*\S+\s*$/) {
 
2734
                        $provided_by{$name}->{$1} = 1;
 
2735
                }
 
2736
        }
 
2737
        close( PIPE );
 
2738
        die "$conf::apt_cache exit status $?\n" if $?;
 
2739
 
 
2740
        return \%provided_by;
 
2741
}
 
2742
 
 
2743
# Try to figure out if a package exists. We need to take account of virtual
 
2744
# packages, so showpkg is the best tool I can think of; but that shows
 
2745
# packages which only exist as (reverse) dependencies. As such, we make
 
2746
# sure that either Versions: or Reverse Provides: has some content.
 
2747
sub package_exists {
 
2748
        local(*PIPE);
 
2749
 
 
2750
        open( PIPE, "$conf::sudo /usr/sbin/chroot $main::chroot_dir ".
 
2751
                    "$conf::apt_cache showpkg @_ 2>&1 |" )
 
2752
                or die "Cannot start $conf::apt_cache $main::chroot_apt_op: $!\n";
 
2753
        my $name;
 
2754
        my $in_versions = 0;
 
2755
        my $in_rprov = 0;
 
2756
        my $real = 0;
 
2757
        while( <PIPE> ) {
 
2758
                if (/^Package:\s*(\S+)\s*$/) {
 
2759
                        $name = $1;
 
2760
                }
 
2761
                elsif (/^Versions: $/) {
 
2762
                        $in_versions = 1;
 
2763
                        $in_rprov = 0;
 
2764
                }
 
2765
                elsif (/^Reverse Provides: $/) {
 
2766
                        $in_rprov = 1;
 
2767
                        $in_versions = 0;
 
2768
                }
 
2769
                elsif (($in_versions || $in_rprov) && /^(\w.*):\s/) {
 
2770
                        $in_versions = 0;
 
2771
                        $in_rprov = 0;
 
2772
                }
 
2773
                elsif (($in_versions || $in_rprov) && /^\S/) {
 
2774
                        $real = 1;
 
2775
                }
 
2776
        }
 
2777
        close( PIPE );
 
2778
        if (defined $name and $real) {
 
2779
                return 1;
 
2780
        } else {
 
2781
                return 0;
 
2782
        }
 
2783
}
 
2784
 
 
2785
sub parse_one_srcdep {
 
2786
        my $pkg = shift;
 
2787
        my $deps = shift;
 
2788
        my $hash = shift;
 
2789
        
 
2790
        $deps =~ s/^\s*(.*)\s*$/$1/;
 
2791
        foreach (split( /\s*,\s*/, $deps )) {
 
2792
                my @l;
 
2793
                my $override;
 
2794
                if (/^\&/) {
 
2795
                        $override = 1;
 
2796
                        s/^\&\s+//;
 
2797
                }
 
2798
                my @alts = split( /\s*\|\s*/, $_ );
 
2799
                my $special_seen = 0;
 
2800
                my $neg_seen = 0;
 
2801
                foreach (@alts) {
 
2802
                        if (!/^([^\s([]+)\s*(\(\s*([<=>]+)\s*(\S+)\s*\))?(\s*\[([^]]+)\])?/) {
 
2803
                                warn "Warning: syntax error in dependency '$_' of $pkg\n";
 
2804
                                next;
 
2805
                        }
 
2806
                        my( $dep, $rel, $relv, $archlist ) = ($1, $3, $4, $6);
 
2807
                        if ($archlist) {
 
2808
                                $archlist =~ s/^\s*(.*)\s*$/$1/;
 
2809
                                my @archs = split( /\s+/, $archlist );
 
2810
                                my ($use_it, $ignore_it, $include) = (0, 0, 0);
 
2811
                                foreach (@archs) {
 
2812
                                        # Use 'dpkg-architecture' to support architecture
 
2813
                                        # wildcards.
 
2814
                                        if (/^!/) {
 
2815
                                                if (system("$conf::sudo", "/usr/sbin/chroot",
 
2816
                                                    "$main::cwd/$main::chroot_dir",
 
2817
                                                    "dpkg-architecture", "-a".$main::arch, "-i".substr($_, 1)) eq 0) {
 
2818
                                                        $ignore_it = 1
 
2819
                                                }
 
2820
                                        }
 
2821
                                        else {
 
2822
                                                if (system("$conf::sudo", "/usr/sbin/chroot",    
 
2823
                                                    "$main::cwd/$main::chroot_dir",
 
2824
                                                    "dpkg-architecture", "-a".$main::arch, "-i".$_) eq 0) {
 
2825
                                                        $use_it = 1
 
2826
                                                }
 
2827
                                                $include = 1;
 
2828
                                        }
 
2829
                                }
 
2830
                                warn "Warning: inconsistent arch restriction on ",
 
2831
                                         "$pkg: $dep depedency\n"
 
2832
                                                 if $ignore_it && $use_it;
 
2833
                                next if $ignore_it || ($include && !$use_it);
 
2834
                        }
 
2835
                        if ($dep =~ /^\*/) {
 
2836
                                warn "Warning: $pkg: ignoring version relation on ".
 
2837
                                         "special dependency $dep\n"
 
2838
                                                 if $rel || $relv;
 
2839
                                push( @l, { Package => $dep, Override => 1 } );
 
2840
                                $special_seen = 1;
 
2841
                                next;
 
2842
                        }
 
2843
                        my $neg = 0;
 
2844
                        if ($dep =~ /^!/) {
 
2845
                                $dep =~ s/^!\s*//;
 
2846
                                $neg = 1;
 
2847
                                $neg_seen = 1;
 
2848
                        }
 
2849
                        if ($conf::srcdep_over{$dep}) {
 
2850
                                if ($main::verbose) {
 
2851
                                        print PLOG "Replacing source dep $dep";
 
2852
                                        print PLOG " ($rel $relv)" if $relv;
 
2853
                                        print PLOG " with $conf::srcdep_over{$dep}[0]";
 
2854
                                        print PLOG " ($conf::srcdep_over{$dep}[1] $conf::srcdep_over{$dep}[2])"
 
2855
                                          if $conf::srcdep_over{$dep}[1];
 
2856
                                        print PLOG ".\n";
 
2857
                                }
 
2858
                                $dep = $conf::srcdep_over{$dep}[0];
 
2859
                                $rel = $conf::srcdep_over{$dep}[1];
 
2860
                                $relv = $conf::srcdep_over{$dep}[2];
 
2861
                        }
 
2862
                        my $h = { Package => $dep, Neg => $neg };
 
2863
                        if ($rel && $relv) {
 
2864
                                $h->{'Rel'} = $rel;
 
2865
                                $h->{'Version'} = $relv;
 
2866
                        }
 
2867
                        $h->{'Override'} = $override if $override;
 
2868
                        push( @l, $h );
 
2869
                }
 
2870
                if (@alts > 1 && $special_seen) {
 
2871
                        warn "Warning: $pkg: alternatives with special dependencies ",
 
2872
                                 "forbidden -- skipped\n";
 
2873
                }
 
2874
                elsif (@alts > 1 && $neg_seen) {
 
2875
                        warn "Warning: $pkg: alternatives with negative dependencies ",
 
2876
                                 "forbidden -- skipped\n";
 
2877
                }
 
2878
                elsif (@l) {
 
2879
                        my $l = shift @l;
 
2880
                        foreach (@l) {
 
2881
                                push( @{$l->{'Alternatives'}}, $_ );
 
2882
                        }
 
2883
                        push( @{$hash->{$pkg}}, $l );
 
2884
                }
 
2885
        }
 
2886
}
 
2887
 
 
2888
sub get_special {
 
2889
        my $fname = shift;
 
2890
        my $sp = shift;
 
2891
        my $sub = "";
 
2892
        
 
2893
        while( <F> ) {
 
2894
                last if /^$/;
 
2895
                if (/^\s*(\w+)\s*\{\s*$/) {
 
2896
                        if ($sub) {
 
2897
                                warn "Syntax error in line $. in $fname:\n";
 
2898
                                warn "  Start of special subsection inside ".
 
2899
                                        "another one.\n";
 
2900
                        }
 
2901
                        else {
 
2902
                                $sub = $1;
 
2903
                                $main::specials{$sp}->{$sub} = "";
 
2904
                        }
 
2905
                }
 
2906
                elsif (/^\s*\}\s*$/) {
 
2907
                        if (!$sub) {
 
2908
                                warn "Syntax error in line $. in $fname:\n";
 
2909
                                warn "  }  outside of special subsection\n";
 
2910
                        }
 
2911
                        else {
 
2912
                                $sub = "";
 
2913
                        }
 
2914
                }
 
2915
                elsif ($sub) {
 
2916
                        $main::specials{$sp}->{$sub} .= $_;
 
2917
                }
 
2918
                else {
 
2919
                        warn "Syntax error in line $. in $fname:\n";
 
2920
                        warn "  Subsection start expected\n";
 
2921
                }
 
2922
        }
 
2923
        if ($sub) {
 
2924
                warn "Syntax error in line $. in $fname:\n";
 
2925
                warn "  Subsection not finished with }\n";
 
2926
        }
 
2927
 
 
2928
        push( @main::global_patches, $sp ) if $sp =~ /^\*\*/;
 
2929
}
 
2930
 
 
2931
 
 
2932
sub open_log {
 
2933
        my $date = `date +%Y%m%d-%H%M`;
 
2934
        chomp( $date );
 
2935
 
 
2936
        if ($main::nolog) {
 
2937
                open( LOG, ">&STDOUT" );
 
2938
                open( PLOG, ">&LOG" ) or warn "Can't redirect PLOG\n";
 
2939
                select( LOG );
 
2940
                return;
 
2941
        }
 
2942
 
 
2943
        $main::main_logfile = "build-$date.log";
 
2944
 
 
2945
        if ($main::verbose) {
 
2946
                my $pid;
 
2947
                ($pid = open( LOG, "|-")) || exec "tee $main::main_logfile";
 
2948
                if (!defined $pid) {
 
2949
                        warn "Cannot open pipe to 'tee $main::main_logfile': $!\n";
 
2950
                }
 
2951
                else {
 
2952
                        $main::tee_pid = $pid;
 
2953
                }
 
2954
        }
 
2955
        else {
 
2956
                open( LOG, ">$main::main_logfile" )
 
2957
                        or warn "Cannot open log file $main::main_logfile: $!\n";
 
2958
        }
 
2959
        select( (select( LOG ), $| = 1)[0] );
 
2960
        open( STDOUT, ">&LOG" ) or warn "Can't redirect stdout\n";
 
2961
        open( STDERR, ">&LOG" ) or warn "Can't redirect stderr\n";
 
2962
        open( PLOG, ">&LOG" ) or warn "Can't redirect PLOG\n";
 
2963
}
 
2964
 
 
2965
sub close_log {
 
2966
        my $date = `date +%Y%m%d-%H%M`;
 
2967
        chomp( $date );
 
2968
 
 
2969
        kill( 15, $main::tee_pid ) if $main::verbose;
 
2970
        close( LOG );
 
2971
        if (!$main::nolog && !$main::verbose &&
 
2972
                -s $main::main_logfile && $conf::mailto) {
 
2973
                send_mail( $conf::mailto, "Log from sbuild $date",
 
2974
                                   $main::main_logfile ) if $conf::mailto;
 
2975
        }
 
2976
        elsif (!$main::nolog && !$main::verbose && ! -s $main::main_logfile) {
 
2977
                unlink( $main::main_logfile );
 
2978
        }
 
2979
}
 
2980
 
 
2981
sub open_pkg_log {
 
2982
        my $date = `date +%Y%m%d-%H%M`;
 
2983
        my $pkg = shift;
 
2984
 
 
2985
        if ($main::nolog) {
 
2986
                open( PLOG, ">&STDOUT" );
 
2987
        }
 
2988
        else {
 
2989
                $pkg = basename( $pkg );
 
2990
                if ($main::binNMU) {
 
2991
                        $pkg =~ /^([^_]+)_([^_]+)(.*)$/;
 
2992
                        $pkg = $1."_".binNMU_version($2);
 
2993
                        $main::binNMU_name = $pkg;
 
2994
                        $pkg .= $3;
 
2995
                }
 
2996
                $main::pkg_logfile = "$conf::log_dir/${pkg}_$date";
 
2997
                if ($main::verbose) {
 
2998
                        my $pid;
 
2999
                        ($pid = open( PLOG, "|-")) || exec "tee $main::pkg_logfile";
 
3000
                        if (!defined $pid) {
 
3001
                                warn "Cannot open pipe to 'tee $main::pkg_logfile': $!\n";
 
3002
                        }
 
3003
                        else {
 
3004
                                $main::pkg_tee_pid = $pid;
 
3005
                        }
 
3006
                }
 
3007
                else {
 
3008
                        if (!open( PLOG, ">$main::pkg_logfile" )) {
 
3009
                                warn "Can't open logfile $main::pkg_logfile: $!\n";
 
3010
                                return 0;
 
3011
                        }
 
3012
                }
 
3013
        }
 
3014
        select( (select( PLOG ), $| = 1)[0] );
 
3015
 
 
3016
        my $revision = '$Revision: 1.170.5 $';
 
3017
        $revision =~ /([\d.]+)/;
 
3018
        $revision = $1;
 
3019
 
 
3020
        print PLOG "Automatic build of $pkg on $main::HOSTNAME by ".
 
3021
                           "sbuild/$main::arch $revision\n";
 
3022
        print PLOG "Build started at $date";
 
3023
        print PLOG "*"x78, "\n";
 
3024
        return 1;
 
3025
}
 
3026
 
 
3027
sub close_pkg_log {
 
3028
        my $date = `date +%Y%m%d-%H%M`;
 
3029
        my $pkg = shift;
 
3030
        my $t = $main::pkg_end_time - $main::pkg_start_time;
 
3031
        
 
3032
        $pkg = basename( $pkg );
 
3033
        $t = 0 if $t < 0;
 
3034
        #if ($main::pkg_status eq "successful") {
 
3035
        #       add_time_entry( $pkg, $t );
 
3036
        #       add_space_entry( $pkg, $main::this_space );
 
3037
        #}
 
3038
        print PLOG "*"x78, "\n";
 
3039
        printf PLOG "Finished at ${date}Build needed %02d:%02d:%02d, %dk disk space\n",
 
3040
                   int($t/3600), int(($t%3600)/60), int($t%60), $main::this_space;
 
3041
        kill( 15, $main::pkg_tee_pid ) if $main::verbose && !$main::nolog;
 
3042
        close( PLOG );
 
3043
        open( PLOG, ">&LOG" ) or warn "Can't redirect PLOG\n";
 
3044
        send_mail( $conf::mailto,
 
3045
                           "Log for $main::pkg_status build of ".
 
3046
                           ($main::binNMU_name || $pkg)." (dist=$main::distribution)",
 
3047
                           $main::pkg_logfile ) if !$main::nolog && $conf::mailto;
 
3048
}
 
3049
 
 
3050
sub add_time_entry {
 
3051
        my $pkg = shift;
 
3052
        my $t = shift;
 
3053
 
 
3054
        return if !$conf::avg_time_db;
 
3055
        my %db;
 
3056
        if (!tie %db, 'GDBM_File',$conf::avg_time_db,GDBM_WRCREAT,0664) {
 
3057
                print "Can't open average time db $conf::avg_time_db\n";
 
3058
                return;
 
3059
        }
 
3060
        $pkg =~ s/_.*//;
 
3061
                
 
3062
        if (exists $db{$pkg}) {
 
3063
                my @times = split( /\s+/, $db{$pkg} );
 
3064
                push( @times, $t );
 
3065
                my $sum = 0;
 
3066
                foreach (@times[1..$#times]) { $sum += $_; }
 
3067
                $times[0] = $sum / (@times-1);
 
3068
                $db{$pkg} = join( ' ', @times );
 
3069
        }
 
3070
        else {
 
3071
                $db{$pkg} = "$t $t";
 
3072
        }
 
3073
        untie %db;
 
3074
}
 
3075
 
 
3076
sub check_space {
 
3077
        my @files = @_;
 
3078
        local( *PIPE );
 
3079
 
 
3080
        if (!open( PIPE, "sudo /usr/bin/du -s @files 2>/dev/null |" )) {
 
3081
                print PLOG "Cannot determine space needed (du failed): $!\n";
 
3082
                return;
 
3083
        }
 
3084
        my $sum = 0;
 
3085
        while( <PIPE> ) {
 
3086
                next if !/^(\d+)/;
 
3087
                $sum += $1;
 
3088
        }
 
3089
        close( PIPE );
 
3090
        $main::this_space = $sum;
 
3091
}
 
3092
 
 
3093
sub add_space_entry {
 
3094
        my $pkg = shift;
 
3095
        my $t = shift;
 
3096
 
 
3097
        my $keepvals = 4;
 
3098
        
 
3099
        return if !$conf::avg_space_db || $main::this_space == 0;
 
3100
        my %db;
 
3101
        if (!tie %db, 'GDBM_File',$conf::avg_space_db,GDBM_WRCREAT,0664) {
 
3102
                print "Can't open average space db $conf::avg_space_db\n";
 
3103
                return;
 
3104
        }
 
3105
        $pkg =~ s/_.*//;
 
3106
                
 
3107
        if (exists $db{$pkg}) {
 
3108
                my @values = split( /\s+/, $db{$pkg} );
 
3109
                shift @values;
 
3110
                unshift( @values, $t );
 
3111
                pop @values if @values > $keepvals;
 
3112
                my ($sum, $n, $weight, $i) = (0, 0, scalar(@values));
 
3113
                for( $i = 0; $i < @values; ++$i) {
 
3114
                        $sum += $values[$i] * $weight;
 
3115
                        $n += $weight;
 
3116
                }
 
3117
                unshift( @values, $sum/$n );
 
3118
                $db{$pkg} = join( ' ', @values );
 
3119
        }
 
3120
        else {
 
3121
                $db{$pkg} = "$t $t";
 
3122
        }
 
3123
        untie %db;
 
3124
}
 
3125
 
 
3126
sub file_for_name {
 
3127
        my $name = shift;
 
3128
        my @x = grep { /^\Q$name\E_/ } @_;
 
3129
        return $x[0];
 
3130
}
 
3131
                                
 
3132
sub write_jobs_file {
 
3133
        my $news = shift;
 
3134
        my $job;
 
3135
        local( *F );
 
3136
        
 
3137
        $main::job_state{$main::current_job} = $news
 
3138
                if $news && $main::current_job;
 
3139
 
 
3140
        return if !$main::batchmode;
 
3141
        
 
3142
        return if !open( F, ">$main::jobs_file" );
 
3143
        foreach $job (@ARGV) {
 
3144
                print F ($job eq $main::current_job) ? "" : "  ",
 
3145
                                $job,
 
3146
                                ($main::job_state{$job} ? ": $main::job_state{$job}" : ""),
 
3147
                                "\n";
 
3148
        }
 
3149
        close( F );
 
3150
}
 
3151
 
 
3152
sub append_to_FINISHED {
 
3153
        my $pkg = shift;
 
3154
        local( *F );
 
3155
 
 
3156
        return if !$main::batchmode;
 
3157
        
 
3158
        open( F, ">>SBUILD-FINISHED" );
 
3159
        print F "$pkg\n";
 
3160
        close( F );
 
3161
}
 
3162
 
 
3163
sub write_srcdep_lock_file {
 
3164
        my $deps = shift;
 
3165
        my $specials = shift;
 
3166
        local( *F );
 
3167
 
 
3168
        ++$main::srcdep_lock_cnt;
 
3169
        my $f = "$conf::srcdep_lock_dir/$$-$main::srcdep_lock_cnt";
 
3170
        if (!open( F, ">$f" )) {
 
3171
                print "Warning: cannot create srcdep lock file $f: $!";
 
3172
                return;
 
3173
        }
 
3174
        print "Writing srcdep lock file $f:\n" if $main::debug;
 
3175
 
 
3176
        chomp( my $user = `/usr/bin/whoami` );
 
3177
        print F "$main::current_job $$ $user\n";
 
3178
        print "Job $main::current_job pid $$ user $user\n" if $main::debug;
 
3179
        foreach (@$deps) {
 
3180
                my $name = $_->{'Package'};
 
3181
                # add special deps only if they affect global state ("global" sub)
 
3182
                next if $name =~ /^\*/ &&
 
3183
                            (!isin( $name, @$specials ) ||
 
3184
                                 $main::specials{$name}->{'global'} !~ /yes/m);
 
3185
                print F ($_->{'Neg'} ? "!" : ""), "$name\n";
 
3186
                print "  ", ($_->{'Neg'} ? "!" : ""), "$name\n" if $main::debug;
 
3187
        }
 
3188
        close( F );
 
3189
}
 
3190
 
 
3191
sub check_srcdep_conflicts {
 
3192
        my $to_inst = shift;
 
3193
        my $to_remove = shift;
 
3194
        my $special = shift;
 
3195
        local( *F, *DIR );
 
3196
        my $mypid = $$;
 
3197
        my %conflict_builds;
 
3198
 
 
3199
        if (!opendir( DIR, $conf::srcdep_lock_dir )) {
 
3200
                print PLOG "Cannot opendir $conf::srcdep_lock_dir: $!\n";
 
3201
                return 1;
 
3202
        }
 
3203
        my @files = grep { !/^\.\.?$/ && !/^install\.lock/ && !/^$mypid-\d+$/ }
 
3204
                                         readdir(DIR);
 
3205
        closedir(DIR);
 
3206
 
 
3207
        my $file;
 
3208
        foreach $file (@files) {
 
3209
                if (!open( F, "<$conf::srcdep_lock_dir/$file" )) {
 
3210
                        print PLOG "Cannot open $conf::srcdep_lock_dir/$file: $!\n";
 
3211
                        next;
 
3212
                }
 
3213
                <F> =~ /^(\S+)\s+(\S+)\s+(\S+)/;
 
3214
                my ($job, $pid, $user) = ($1, $2, $3);
 
3215
 
 
3216
                # ignore (and remove) a lock file if associated process doesn't exist
 
3217
                # anymore
 
3218
                if (kill( 0, $pid ) == 0 && $! == ESRCH) {
 
3219
                        close( F );
 
3220
                        print PLOG "Found stale srcdep lock file $file -- removing it\n";
 
3221
                        print PLOG "Cannot remove: $!\n"
 
3222
                                if !unlink( "$conf::srcdep_lock_dir/$file" );
 
3223
                        next;
 
3224
                }
 
3225
 
 
3226
                print "Reading srclock file $file by job $job user $user\n"
 
3227
                        if $main::debug;
 
3228
 
 
3229
                while( <F> ) {
 
3230
                        my ($neg, $pkg) = /^(!?)(\S+)/;
 
3231
                        print "Found ", ($neg ? "neg " : ""), "entry $pkg\n"
 
3232
                                if $main::debug;
 
3233
 
 
3234
                        if ($pkg =~ /^\*/) {
 
3235
                                print PLOG "Build of $job by $user (pid $pid) has ",
 
3236
                                                   "installed the global special dependency $pkg.\n";
 
3237
                                $conflict_builds{$file} = 1;
 
3238
                        }
 
3239
                        else {
 
3240
                                if (isin( $pkg, @$to_inst, @$to_remove )) {
 
3241
                                        print PLOG "Source dependency conflict with build of ",
 
3242
                                                           "$job by $user (pid $pid):\n";
 
3243
                                        print PLOG "  $job ", ($neg ? "conflicts with" : "needs"),
 
3244
                                                           " $pkg\n";
 
3245
                                        print PLOG "  $main::current_job wants to ",
 
3246
                                                           (isin( $pkg, @$to_inst ) ? "update" : "remove"),
 
3247
                                                           " $pkg\n";
 
3248
                                        $conflict_builds{$file} = 1;
 
3249
                                }
 
3250
                        }
 
3251
                }
 
3252
                close( F );
 
3253
        }
 
3254
 
 
3255
        foreach (@$special) {
 
3256
                if ($main::specials{$_}->{'global'} =~ /yes/m) {
 
3257
                        print PLOG "$main::current_job wants to apply global ",
 
3258
                                           "special dependency $_\n",
 
3259
                                           "Must wait for other builds to finish\n";
 
3260
                        foreach (@files) {
 
3261
                                $conflict_builds{$_} = 1;
 
3262
                        }
 
3263
                }
 
3264
        }
 
3265
 
 
3266
        my @conflict_builds = keys %conflict_builds;
 
3267
        if (@conflict_builds) {
 
3268
                print "Srcdep conflicts with: @conflict_builds\n" if $main::debug;
 
3269
        }
 
3270
        else {
 
3271
                print "No srcdep conflicts\n" if $main::debug;
 
3272
        }
 
3273
        return @conflict_builds;
 
3274
}
 
3275
 
 
3276
sub remove_srcdep_lock_file {
 
3277
        my $f = "$conf::srcdep_lock_dir/$$-$main::srcdep_lock_cnt";
 
3278
 
 
3279
        print "Removing srcdep lock file $f\n" if $main::debug;
 
3280
        if (!unlink( $f )) {
 
3281
                print "Warning: cannot remove srcdep lock file $f: $!\n"
 
3282
                        if $! != ENOENT;
 
3283
        }
 
3284
}
 
3285
 
 
3286
sub prepare_watches {
 
3287
        my $dependencies = shift;
 
3288
        my @instd = @_;
 
3289
        my(@dep_on, $dep, $pkg, $prg);
 
3290
 
 
3291
        @dep_on = @instd;
 
3292
        foreach $dep (@$dependencies, @$main::additional_deps) {
 
3293
                if ($dep->{'Neg'} && $dep->{'Package'} =~ /^needs-no-(\S+)/) {
 
3294
                        push( @dep_on, $1 );
 
3295
                }
 
3296
                elsif ($dep->{'Package'} !~ /^\*/ && !$dep->{'Neg'}) {
 
3297
                        foreach (scalar($dep), @{$dep->{'Alternatives'}}) {
 
3298
                                push( @dep_on, $_->{'Package'} );
 
3299
                        }
 
3300
                }
 
3301
        }
 
3302
        # init %this_watches to names of packages which have not been installed as
 
3303
        # source dependencies
 
3304
        undef %main::this_watches;
 
3305
        foreach $pkg (keys %conf::watches) {
 
3306
                if (isin( $pkg, @dep_on )) {
 
3307
                        print "Excluding from watch: $pkg\n" if $main::debug;
 
3308
                        next;
 
3309
                }
 
3310
                foreach $prg (@{$conf::watches{$pkg}}) {
 
3311
                        $prg = "/usr/bin/$prg" if $prg !~ m,^/,;
 
3312
                        $main::this_watches{"$main::chroot_dir$prg"} = $pkg;
 
3313
                        print "Will watch for $prg ($pkg)\n" if $main::debug;
 
3314
                }
 
3315
        }
 
3316
}
 
3317
 
 
3318
sub check_watches {
 
3319
        my($prg, @st, %used);
 
3320
 
 
3321
        foreach $prg (keys %main::this_watches) {
 
3322
                if (!(@st = stat( $prg ))) {
 
3323
                        print "Watch: $prg: stat failed\n" if $main::debug;
 
3324
                        next;
 
3325
                }
 
3326
                if ($st[8] > $main::build_start_time) {
 
3327
                        my $pkg = $main::this_watches{$prg};
 
3328
                        my $prg2 = $prg;
 
3329
                        $prg2 =~ s/^\Q$main::chroot_dir\E// if $main::chroot_dir;
 
3330
                        push( @{$used{$pkg}}, $prg2 )
 
3331
                                if @main::have_dsc_build_deps ||
 
3332
                                   !isin( $pkg, @conf::ignore_watches_no_build_deps );
 
3333
                }
 
3334
                else {
 
3335
                        print "Watch: $prg: untouched\n" if $main::debug;
 
3336
                }
 
3337
        }
 
3338
        return if !%used;
 
3339
 
 
3340
        print PLOG <<EOF;
 
3341
 
 
3342
NOTE: The package could have used binaries from the following packages
 
3343
(access time changed) without a source dependency:
 
3344
EOF
 
3345
        foreach (keys %used) {
 
3346
                print PLOG "  $_: @{$used{$_}}\n";
 
3347
        }
 
3348
        print PLOG "\n";
 
3349
}
 
3350
 
 
3351
sub should_skip {
 
3352
        my $pkgv = shift;
 
3353
 
 
3354
        fixup_pkgv( \$pkgv );
 
3355
        lock_file( "SKIP" );
 
3356
        goto unlock if !open( F, "SKIP" );
 
3357
        my @pkgs = <F>;
 
3358
        close( F );
 
3359
 
 
3360
        if (!open( F, ">SKIP" )) {
 
3361
                print "Can't open SKIP for writing: $!\n",
 
3362
                          "Would write: @pkgs\nminus $pkgv\n";
 
3363
                goto unlock;
 
3364
        }
 
3365
        my $found = 0;
 
3366
        foreach (@pkgs) {
 
3367
                if (/^\Q$pkgv\E$/) {
 
3368
                        ++$found;
 
3369
                        print PLOG "$pkgv found in SKIP file -- skipping building it\n";
 
3370
                }
 
3371
                else {
 
3372
                        print F $_;
 
3373
                }
 
3374
        }
 
3375
        close( F );
 
3376
  unlock:
 
3377
        unlock_file( "SKIP" );
 
3378
        return $found;
 
3379
}
 
3380
 
 
3381
sub add_givenback {
 
3382
        my $pkgv = shift;
 
3383
        my $time = shift;
 
3384
        local( *F );
 
3385
 
 
3386
        lock_file( "SBUILD-GIVEN-BACK" );
 
3387
 
 
3388
        if (open( F, ">>SBUILD-GIVEN-BACK" )) {
 
3389
                print F "$pkgv $time\n";
 
3390
                close( F );
 
3391
        }
 
3392
        else {
 
3393
                print PLOG "Can't open SBUILD-GIVEN-BACK: $!\n";
 
3394
        }
 
3395
 
 
3396
  unlock:
 
3397
        unlock_file( "SBUILD-GIVEN-BACK" );
 
3398
}
 
3399
 
 
3400
sub send_mail {
 
3401
        my $to = shift;
 
3402
        my $subject = shift;
 
3403
        my $file = shift;
 
3404
        local( *MAIL, *F );
 
3405
 
 
3406
        if (!open( F, "<$file" )) {
 
3407
                warn "Cannot open $file for mailing: $!\n";
 
3408
                return 0;
 
3409
        }
 
3410
        local $SIG{'PIPE'} = 'IGNORE';
 
3411
        
 
3412
        if (!open( MAIL, "|$conf::mailprog -oem $to" )) {
 
3413
                warn "Could not open pipe to $conf::mailprog: $!\n";
 
3414
                close( F );
 
3415
                return 0;
 
3416
        }
 
3417
 
 
3418
        print MAIL "Subject: $subject\n\n";
 
3419
        while( <F> ) {
 
3420
                print MAIL "." if $_ eq ".\n";
 
3421
                print MAIL $_;
 
3422
        }
 
3423
        
 
3424
        close( F );
 
3425
        if (!close( MAIL )) {
 
3426
                warn "$conf::mailprog failed (exit status $?)\n";
 
3427
                return 0;
 
3428
        }
 
3429
        return 1;
 
3430
}
 
3431
 
 
3432
 
 
3433
sub set_installed {
 
3434
        foreach (@_) {
 
3435
                $main::changes->{'installed'}->{$_} = 1;
 
3436
        }
 
3437
        print "Added to installed list: @_\n" if $main::debug;
 
3438
}
 
3439
 
 
3440
sub set_removed {
 
3441
        foreach (@_) {
 
3442
                $main::changes->{'removed'}->{$_} = 1;
 
3443
                if (exists $main::changes->{'installed'}->{$_}) {
 
3444
                        delete $main::changes->{'installed'}->{$_};
 
3445
                        $main::changes->{'auto-removed'}->{$_} = 1;
 
3446
                        print "Note: $_ was installed\n" if $main::debug;
 
3447
                }
 
3448
        }
 
3449
        print "Added to removed list: @_\n" if $main::debug;
 
3450
}
 
3451
 
 
3452
sub unset_installed {
 
3453
        foreach (@_) {
 
3454
                delete $main::changes->{'installed'}->{$_};
 
3455
        }
 
3456
        print "Removed from installed list: @_\n" if $main::debug;
 
3457
}
 
3458
 
 
3459
sub unset_removed {
 
3460
        foreach (@_) {
 
3461
                delete $main::changes->{'removed'}->{$_};
 
3462
                if (exists $main::changes->{'auto-removed'}->{$_}) {
 
3463
                        delete $main::changes->{'auto-removed'}->{$_};
 
3464
                        $main::changes->{'installed'}->{$_} = 1;
 
3465
                        print "Note: revived $_ to installed list\n" if $main::debug;
 
3466
                }
 
3467
        }
 
3468
        print "Removed from removed list: @_\n" if $main::debug;
 
3469
}
 
3470
 
 
3471
sub basename {
 
3472
        my $b = $_[0];
 
3473
        $b =~ s,^.*/,,;
 
3474
        return $b;
 
3475
}
 
3476
 
 
3477
sub df {
 
3478
        my $dir = shift;
 
3479
 
 
3480
        my $free = `/bin/df $dir | tail -1`;
 
3481
        my @free = split( /\s+/, $free );
 
3482
        return $free[3];
 
3483
}
 
3484
 
 
3485
sub isin {
 
3486
        my $val = shift;
 
3487
        return grep( $_ eq $val, @_ );
 
3488
}
 
3489
 
 
3490
sub fixup_pkgv {
 
3491
        my $pkgv = shift;
 
3492
        
 
3493
        $$pkgv =~ s,^.*/,,; # strip path
 
3494
        $$pkgv =~ s/\.(dsc|diff\.gz|tar\.gz|deb)$//; # strip extension
 
3495
        $$pkgv =~ s/_[a-zA-Z\d+~-]+\.(changes|deb)$//; # strip extension
 
3496
}
 
3497
 
 
3498
sub format_deps {
 
3499
        return join( ", ",
 
3500
                   map { join( "|",
 
3501
                                 map { ($_->{'Neg'} ? "!" : "") .
 
3502
                                           $_->{'Package'} .
 
3503
                                           ($_->{'Rel'} ? " ($_->{'Rel'} $_->{'Version'})":"")}
 
3504
                                 scalar($_), @{$_->{'Alternatives'}}) } @_ );
 
3505
}
 
3506
 
 
3507
sub lock_file {
 
3508
        my $file = shift;
 
3509
        my $for_srcdep = shift;
 
3510
        my $lockfile = "$file.lock";
 
3511
        my $try = 0;
 
3512
        
 
3513
  repeat:
 
3514
        if (!sysopen( F, $lockfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644 )){
 
3515
                if ($! == EEXIST) {
 
3516
                        # lock file exists, wait
 
3517
                        goto repeat if !open( F, "<$lockfile" );
 
3518
                        my $line = <F>;
 
3519
                        my ($pid, $user);
 
3520
                        close( F );
 
3521
                        if ($line !~ /^(\d+)\s+([\w\d.-]+)$/) {
 
3522
                                warn "Bad lock file contents ($lockfile) -- still trying\n";
 
3523
                        }
 
3524
                        else {
 
3525
                                ($pid, $user) = ($1, $2);
 
3526
                                if (kill( 0, $pid ) == 0 && $! == ESRCH) {
 
3527
                                        # process doesn't exist anymore, remove stale lock
 
3528
                                        warn "Removing stale lock file $lockfile ".
 
3529
                                                 " (pid $pid, user $user)\n";
 
3530
                                        unlink( $lockfile );
 
3531
                                        goto repeat;
 
3532
                                }
 
3533
                        }
 
3534
                        ++$try;
 
3535
                        if (!$for_srcdep && $try > $main::max_lock_trys) {
 
3536
                                warn "Lockfile $lockfile still present after ".
 
3537
                                     $main::max_lock_trys*$main::lock_interval.
 
3538
                                         " seconds -- giving up\n";
 
3539
                                return;
 
3540
                        }
 
3541
                        print PLOG "Another sbuild process ($pid by $user) is currently ",
 
3542
                                           "installing or\n",
 
3543
                                           "removing packages -- waiting...\n"
 
3544
                                                   if $for_srcdep && $try == 1;
 
3545
                        sleep $main::lock_interval;
 
3546
                        goto repeat;
 
3547
                }
 
3548
                warn "Can't create lock file $lockfile: $!\n";
 
3549
        }
 
3550
        F->print("$$ $ENV{'LOGNAME'}\n");
 
3551
        F->close();
 
3552
}
 
3553
 
 
3554
sub unlock_file {
 
3555
        my $file = shift;
 
3556
        my $lockfile = "$file.lock";
 
3557
 
 
3558
        unlink( $lockfile );
 
3559
}
 
3560
 
 
3561
sub check_dpkg_version {
 
3562
        my $t = `$conf::dpkg --version`;
 
3563
        my $version = ($t =~ /version\s+(\S+)/)[0];
 
3564
 
 
3565
        $main::new_dpkg = 1
 
3566
                if 0 == system "$conf::dpkg --compare-versions '$version' ge 1.4.1.18";
 
3567
}
 
3568
 
 
3569
sub binNMU_version {
 
3570
        my $v = shift;
 
3571
 
 
3572
        if ($v =~ /^(.*)-([^-]+)$/) {
 
3573
                my ($upstream, $debian) = ($1, $2);
 
3574
                my @parts = split( /\./, $debian );
 
3575
                if (@parts == 1) {
 
3576
                        return "$upstream-$debian.0.$main::binNMUver";
 
3577
                }
 
3578
                elsif (@parts == 2) {
 
3579
                        return "$upstream-$debian.$main::binNMUver";
 
3580
                }
 
3581
                else {
 
3582
                        $parts[$#parts]+=$main::binNMUver;
 
3583
                        return "$upstream-".join( ".", @parts );
 
3584
                }
 
3585
        }
 
3586
        else {
 
3587
                return "$v.0.$main::binNMUver";
 
3588
        }
 
3589
}
 
3590
 
 
3591
sub shutdown {
 
3592
        my $signame = shift;
 
3593
        my($job,@npkgs,@pkgs);
 
3594
        local( *F );
 
3595
 
 
3596
        $SIG{'INT'} = 'IGNORE';
 
3597
        $SIG{'QUIT'} = 'IGNORE';
 
3598
        $SIG{'TERM'} = 'IGNORE';
 
3599
        $SIG{'ALRM'} = 'IGNORE';
 
3600
        $SIG{'PIPE'} = 'IGNORE';
 
3601
        print PLOG "sbuild received SIG$signame -- shutting down\n";
 
3602
        chdir( $main::cwd );
 
3603
 
 
3604
        goto not_ni_shutdown if !$main::batchmode;
 
3605
        
 
3606
        # most important: dump out names of unfinished jobs to REDO
 
3607
        foreach $job (@ARGV) {
 
3608
                my $job2 = $job;
 
3609
                fixup_pkgv( \$job2 );
 
3610
                push( @npkgs, $job2 )
 
3611
                        if !$main::job_state{$job} || $job eq $main::current_job;
 
3612
        }
 
3613
        print LOG "The following jobs were not finished: @npkgs\n";
 
3614
 
 
3615
        my $f = "$main::HOME/build/REDO";
 
3616
        if (-f "$main::HOME/build/REDO.lock") {
 
3617
                # if lock file exists, write to a different file -- timing may
 
3618
                # be critical
 
3619
                $f = "$main::HOME/build/REDO2";
 
3620
        }
 
3621
        if (open( F, "<$f" )) {
 
3622
                @pkgs = <F>;
 
3623
                close( F );
 
3624
        }
 
3625
        if (open( F, ">>$f" )) {
 
3626
                foreach $job (@npkgs) {
 
3627
                        next if grep( /^\Q$job\E\s/, @pkgs );
 
3628
                        print F "$job $main::distribution $main::component\n";
 
3629
                }
 
3630
                close( F );
 
3631
        }
 
3632
        else {
 
3633
                print "Cannot open $f: $!\n";
 
3634
        }
 
3635
        open( F, ">SBUILD-REDO-DUMPED" );
 
3636
        close( F );
 
3637
        print LOG "SBUILD-REDO-DUMPED created\n";
 
3638
        unlink( "SBUILD-FINISHED" );
 
3639
 
 
3640
        # next: say which packages should be uninstalled
 
3641
        @pkgs = keys %{$main::changes->{'installed'}};
 
3642
        if (@pkgs) {
 
3643
                if (open( F, ">>NEED-TO-UNINSTALL" )) {
 
3644
                        print F "@pkgs\n";
 
3645
                        close( F );
 
3646
                }
 
3647
                print "The following packages still need to be uninstalled ",
 
3648
                          "(--purge):\n@pkgs\n";
 
3649
        }
 
3650
        
 
3651
  not_ni_shutdown:
 
3652
        # next: kill currently running command (if one)
 
3653
        if ($main::sub_pid) {
 
3654
                print "Killing $main::sub_task subprocess $main::sub_pid\n";
 
3655
                system "$conf::sudo perl -e 'kill( -15, $main::sub_pid )'";
 
3656
        }
 
3657
        remove_srcdep_lock_file();
 
3658
 
 
3659
        # close logs and send mails
 
3660
        if ( $main::current_job ) {
 
3661
                fixup_pkgv( \$main::current_job );
 
3662
                close_pkg_log( $main::current_job );
 
3663
        }
 
3664
        close_log();
 
3665
        unlink( $main::jobs_file ) if $main::batchmode;
 
3666
        $? = 0; $! = 0;
 
3667
        exit 0;
 
3668
}