Change debian package to fix a bunch of lintian errors
[webmin.git] / makedebian.pl
1 #!/usr/local/bin/perl
2 # Build a Debian package of Webmin
3
4 use POSIX;
5
6 if ($ARGV[0] eq "--webmail" || $ARGV[0] eq "-webmail") {
7         $webmail = 1;
8         shift(@ARGV);
9         }
10 if ($0 =~ /useradmin|usermin/ || `pwd` =~ /useradmin|usermin/) {
11         if ($webmail) {
12                 $product = "usermin-webmail";
13                 }
14         else {
15                 $product = "usermin";
16                 }
17         $baseproduct = "usermin";
18         $port = 20000;
19         }
20 else {
21         $product = "webmin";
22         $baseproduct = "webmin";
23         $port = 10000;
24         }
25 $ucproduct = ucfirst($baseproduct);
26 $tmp_dir = "/tmp/debian";
27 $debian_dir = "$tmp_dir/DEBIAN";
28 $control_file = "$debian_dir/control";
29 $doc_dir = "$tmp_dir/usr/share/doc/$baseproduct";
30 $copyright_file = "$doc_dir/copyright";
31 $usr_dir = "$tmp_dir/usr/share/$baseproduct";
32 $pam_dir = "$tmp_dir/etc/pam.d";
33 $init_dir = "$tmp_dir/etc/init.d";
34 $pam_file = "$pam_dir/$baseproduct";
35 $preinstall_file = "$debian_dir/preinst";
36 $postinstall_file = "$debian_dir/postinst";
37 $preuninstall_file = "$debian_dir/prerm";
38 $postuninstall_file = "$debian_dir/postrm";
39 $debian_copyright_file = "$debian_dir/copyright";
40 $changelog_file = "$debian_dir/changelog";
41 $changelog_doc_file = "$doc_dir/changelog";
42 $conffiles_file = "$debian_dir/conffiles";
43
44 -d "tarballs" || die "makedebian.pl must be run in the $ucproduct root directory";
45 -r "/etc/debian_version" || die "makedebian.pl must be run on Debian";
46 chop($webmin_dir = `pwd`);
47
48 @ARGV == 1 || @ARGV == 2 ||
49         die "usage: makedebian.pl [--webmail] <version> [release]";
50 $ver = $ARGV[0];
51 if ($ARGV[1]) {
52         $rel = "-".$ARGV[1];
53         }
54 -r "tarballs/$product-$ver.tar.gz" || die "tarballs/$product-$ver.tar.gz not found";
55
56 # Create the base directories
57 print "Creating Debian package of ",ucfirst($product)," ",$ver,$rel," ...\n";
58 system("rm -rf $tmp_dir");
59 mkdir($tmp_dir, 0755);
60 chmod(0755, $tmp_dir);
61 mkdir($debian_dir, 0755);
62 system("mkdir -p $pam_dir");
63 system("mkdir -p $init_dir");
64 system("mkdir -p $usr_dir");
65 system("mkdir -p $doc_dir");
66
67 # Un-tar the package to the correct locations
68 system("gunzip -c tarballs/$product-$ver.tar.gz | (cd $tmp_dir ; tar xf -)") &&
69         die "un-tar failed!";
70 system("mv $tmp_dir/$product-$ver/* $usr_dir");
71 rmdir("$tmp_dir/$product-$ver");
72 system("mv $usr_dir/$baseproduct-debian-pam $pam_file");
73 system("cd $usr_dir && (find . -name '*.cgi' ; find . -name '*.pl') | perl perlpath.pl /usr/bin/perl -");
74 system("cd $usr_dir && rm -f mount/freebsd-mounts*");
75 system("cd $usr_dir && rm -f mount/openbsd-mounts*");
76 if ($product eq "webmin") {
77         system("cd $usr_dir && rm -f mount/macos-mounts*");
78         system("cd $usr_dir && rm -f webmin-gentoo-init");
79         system("cd $usr_dir && rm -rf format bsdexports hpuxexports sgiexports zones rbac");
80         system("cd $usr_dir && rm -rf acl/Authen-SolarisRBAC-0.1*");
81         }
82
83 # Create init script
84 system("mv $usr_dir/$baseproduct-init $init_dir/$baseproduct");
85 chmod(0755, "$init_dir/$baseproduct");
86 system("echo deb >$usr_dir/install-type");
87 system("echo $product >$usr_dir/deb-name");
88 system("cd $usr_dir && chmod -R og-w .");
89 if ($< == 0) {
90         system("cd $usr_dir && chown -R root:bin .");
91         }
92 $size = int(`du -sk $tmp_dir`);
93
94 # Create the control file
95 @deps = ( "perl", "libnet-ssleay-perl", "openssl", "libauthen-pam-perl", "libpam-runtime", "libio-pty-perl", "apt-show-versions" );
96 if ($baseproduct eq "webmin") {
97         push(@deps, "python");
98         }
99 $deps = join(", ", @deps);
100 open(CONTROL, ">$control_file");
101 print CONTROL <<EOF;
102 Package: $product
103 Version: $ver$rel
104 Section: admin
105 Priority: optional
106 Architecture: all
107 Depends: $deps
108 Pre-Depends: perl
109 Installed-Size: $size
110 Maintainer: Jamie Cameron <jcameron\@webmin.com>
111 Provides: $baseproduct
112 EOF
113 if ($product eq "webmin") {
114         print CONTROL <<EOF;
115 Replaces: webmin-adsl, webmin-apache, webmin-bandwidth, webmin-bind, webmin-burner, webmin-cfengine, webmin-cluster, webmin-core, webmin-cpan, webmin-dhcpd, webmin-exim, webmin-exports, webmin-fetchmail, webmin-firewall, webmin-freeswan, webmin-frox, webmin-fsdump, webmin-grub, webmin-heartbeat, webmin-htaccess, webmin-inetd, webmin-jabber, webmin-ldap-netgroups, webmin-ldap-user-simple, webmin-ldap-useradmin, webmin-lilo, webmin-logrotate, webmin-lpadmin, webmin-lvm, webmin-mailboxes, webmin-mon, webmin-mysql, webmin-nis, webmin-openslp, webmin-postfix, webmin-postgresql, webmin-ppp, webmin-pptp-client, webmin-pptp-server, webmin-procmail, webmin-proftpd, webmin-pserver, webmin-quota, webmin-samba, webmin-sarg, webmin-sendmail, webmin-shorewall, webmin-slbackup, webmin-smart-status, webmin-snort, webmin-software, webmin-spamassassin, webmin-squid, webmin-sshd, webmin-status, webmin-stunnel, webmin-updown, webmin-usermin, webmin-vgetty, webmin-webalizer, webmin-wuftpd, webmin-wvdial, webmin-xinetd
116 Description: web-based administration interface for Unix systems
117   Using Webmin you can configure DNS, Samba, NFS, local/remote filesystems
118   and more using your web browser.  After installation, enter the URL
119   https://localhost:10000/ into your browser and login as root with your root
120   password.
121 EOF
122         }
123 else {
124         print CONTROL <<EOF;
125 Replaces: usermin-at, usermin-changepass, usermin-chfn, usermin-commands, usermin-cron, usermin-cshrc, usermin-fetchmail, usermin-forward, usermin-gnupg, usermin-htaccess, usermin-htpasswd, usermin-mailbox, usermin-man, usermin-mysql, usermin-plan, usermin-postgresql, usermin-proc, usermin-procmail, usermin-quota, usermin-schedule, usermin-shell, usermin-spamassassin, usermin-ssh, usermin-tunnel, usermin-updown, usermin-usermount
126 Description: web-based user account administration interface for Unix systems
127   After installation, enter the URL http://localhost:20000/ into your browser
128   and login as any user on your system.
129 EOF
130         }
131 close(CONTROL);
132
133 # Create the copyright file
134 $nowstr = strftime("%a, %d %b %Y %H:%M:%S %z", localtime(time()));
135 open(COPY, ">$copyright_file");
136 print COPY <<EOF;
137 This package was debianized by Jamie Cameron <jcameron\@webmin.com> on
138 $nowstr.
139
140 It was downloaded from: http://www.webmin.com/
141
142 Upstream author: Jamie Cameron <jcameron\@webmin.com>
143
144 Copyright:
145
146 EOF
147 open(BSD, "$usr_dir/LICENCE");
148 while(<BSD>) {
149         print COPY $_;
150         }
151 close(BSD);
152 close(COPY);
153 system("cp $copyright_file $debian_copyright_file");
154
155 # Create the config files file, for those we don't want to replace
156 open(CONF, ">$conffiles_file");
157 print CONF "/etc/pam.d/$baseproduct\n";
158 print CONF "/etc/init.d/$baseproduct\n";
159 close(CONF);
160 chmod(0644, $conffiles_file);
161
162 # Get the changes for each module and version
163 $changes = { };
164 foreach $f (sort { $a cmp $b } ( glob("*/CHANGELOG"), "CHANGELOG" )) {
165         # Get the module name and type
166         local $mod = $f =~ /^(\S+)\/CHANGELOG/ ? $1 : "core";
167         next if ($mod ne "core" && -l $mod);
168         local $desc;
169         if ($mod eq "core") {
170                 $desc = "$ucproduct Core";
171                 }
172         else {
173                 local $m = $f;
174                 local %minfo;
175                 $m =~ s/CHANGELOG/module.info/;
176                 &read_file($m, \%minfo);
177                 next if (!$minfo{'longdesc'});
178                 $desc = $minfo{'desc'};
179                 }
180
181         # Read its change log file
182         local $inversion;
183         open(LOG, $f);
184         while(<LOG>) {
185                 s/\r|\n//g;
186                 if (/^----\s+Changes\s+since\s+(\S+)\s+----/) {
187                         $inversion = $1;
188                         }
189                 elsif ($inversion && /\S/) {
190                         push(@{$changes->{$inversion}->{$desc}}, $_);
191                         }
192                 }
193         }
194
195 # Create the changelog file from actual changes, plus the historical changelog
196 open(CHANGELOG, ">$changelog_file");
197 foreach $v (sort { $a <=> $b } (keys %$changes)) {
198         if ($ver > $v && sprintf("%.2f0", $ver) == $v) {
199                 $forv = $ver;
200                 }
201         else {
202                 $forv = sprintf("%.2f0", $v+0.01);
203                 }
204         @st = stat("tarballs/webmin-$forv.tar.gz");
205         $vtimestr = strftime("%a, %d %b %Y %H:%M:%S %z", localtime($st[9]));
206         print CHANGELOG "$baseproduct ($forv) stable; urgency=low\n";
207         print CHANGELOG "\n";
208         foreach $desc (keys %{$changes->{$v}}) {
209                 foreach $c (@{$changes->{$v}->{$desc}}) {
210                         @lines = &wrap_lines("$desc : $c", 65);
211                         print CHANGELOG " * $lines[0]\n";
212                         foreach $l (@lines[1 .. $#lines]) {
213                                 print CHANGELOG "   $l\n";
214                                 }
215                         }
216                 }
217         print CHANGELOG "\n";
218         print CHANGELOG "-- Jamie Cameron <jcameron\@webmin.com> $vtimestr\n";
219         print CHANGELOG "\n";
220         }
221 close(CHANGELOG);
222 system("iconv -f ISO-8859-1 -t UTF-8 $changelog_file >$changelog_doc_file");
223
224 # Get the temp-directory creator script
225 open(TEMP, "maketemp.pl");
226 while(<TEMP>) {
227         $maketemp .= $_;
228         }
229 close(TEMP);
230 $maketemp =~ s/\\/\\\\/g;
231 $maketemp =~ s/`/\\`/g;
232 $maketemp =~ s/\$/\\\$/g;
233
234 # Create the pre-install script
235 # No need for an OS check, as all debians are supported.
236 open(SCRIPT, ">$preinstall_file");
237 print SCRIPT <<EOF;
238 #!/bin/sh
239 perl <<EOD;
240 $maketemp
241 EOD
242 if [ "\$1" != "upgrade" ]; then
243         if [ "\$WEBMIN_PORT\" != \"\" ]; then
244                 port=\$WEBMIN_PORT
245         else
246                 port=$port
247         fi
248         perl -e 'use Socket; socket(FOO, PF_INET, SOCK_STREAM, getprotobyname("tcp")); setsockopt(FOO, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)); bind(FOO, pack_sockaddr_in(\$ARGV[0], INADDR_ANY)) || exit(1); exit(0);' \$port
249         if [ "\$?" != "0" ]; then
250                 echo Port \$port is already in use
251                 exit 2
252         fi
253 fi
254 EOF
255 close(SCRIPT);
256 system("chmod 755 $preinstall_file");
257
258 # Create the post-install script
259 open(SCRIPT, ">$postinstall_file");
260 print SCRIPT <<EOF;
261 #!/bin/sh
262 inetd=`grep "^inetd=" /etc/$baseproduct/miniserv.conf 2>/dev/null | sed -e 's/inetd=//g'`
263 if [ "\$1" = "upgrade" ]; then
264         # Upgrading the package, so stop the old webmin properly
265         if [ "\$inetd" != "1" ]; then
266                 /etc/$baseproduct/stop >/dev/null 2>&1 </dev/null
267         fi
268 fi
269 cd /usr/share/$baseproduct
270 config_dir=/etc/$baseproduct
271 var_dir=/var/$baseproduct
272 perl=/usr/bin/perl
273 autoos=3
274 if [ "\$WEBMIN_PORT\" != \"\" ]; then
275         port=\$WEBMIN_PORT
276 else
277         port=$port
278 fi
279 login=root
280 if [ -r /etc/shadow ]; then
281         crypt=x
282 else
283         crypt=`grep "^root:" /etc/passwd | cut -f 2 -d :`
284 fi
285 host=`hostname`
286 ssl=1
287 atboot=1
288 nochown=1
289 autothird=1
290 noperlpath=1
291 nouninstall=1
292 nostart=1
293 export config_dir var_dir perl autoos port login crypt host ssl nochown autothird noperlpath nouninstall nostart allow atboot
294 tempdir=/tmp/.webmin
295 if [ ! -d \$tempdir ]; then
296         tempdir=/tmp
297 fi
298 ./setup.sh >$tempdir/$product-setup.out 2>&1
299 if [ "$product" = "webmin" ]; then
300         grep sudo= /etc/$product/miniserv.conf >/dev/null 2>&1
301         if [ "\$?" = 1 ]; then
302                 # Allow sudo-based logins for Ubuntu
303                 echo sudo=1 >>/etc/$product/miniserv.conf
304         fi
305 fi
306 rm -f /var/lock/subsys/$baseproduct
307 if [ "$inetd" != "1" ]; then
308         if [ -x "`which invoke-rc.d 2>/dev/null`" ]; then
309                 invoke-rc.d $baseproduct start >/dev/null 2>&1 </dev/null
310         else
311                 /etc/$baseproduct/start >/dev/null 2>&1 </dev/null
312         fi
313 fi
314 if [ "$product" = "usermin" ]; then
315         insserv $baseproduct >/dev/null 2>&1
316 fi
317 cat >/etc/$baseproduct/uninstall.sh <<EOFF
318 #!/bin/sh
319 printf "Are you sure you want to uninstall $ucproduct? (y/n) : "
320 read answer
321 printf "\\n"
322 if [ "\\\$answer" = "y" ]; then
323         echo "Removing $ucproduct package .."
324         dpkg --remove $product
325         echo "Done!"
326 fi
327 EOFF
328 chmod +x /etc/$baseproduct/uninstall.sh
329 port=`grep "^port=" /etc/$baseproduct/miniserv.conf | sed -e 's/port=//g'`
330 perl -e 'use Net::SSLeay' >/dev/null 2>/dev/null
331 sslmode=0
332 if [ "\$?" = "0" ]; then
333         grep ssl=1 /etc/$baseproduct/miniserv.conf >/dev/null 2>/dev/null
334         if [ "\$?" = "0" ]; then
335                 sslmode=1
336         fi
337 fi
338 if [ "\$sslmode" = "1" ]; then
339         echo "$ucproduct install complete. You can now login to https://\$host:\$port/"
340 else
341         echo "$ucproduct install complete. You can now login to http://\$host:\$port/"
342 fi
343 if [ "$product" = "webmin" ]; then
344         echo "as root with your root password, or as any user who can use sudo"
345         echo "to run commands as root."
346 else
347         echo "as any user on the system."
348 fi
349 EOF
350 close(SCRIPT);
351 system("chmod 755 $postinstall_file");
352
353 # Create the pre-uninstall script
354 open(SCRIPT, ">$preuninstall_file");
355 print SCRIPT <<EOF;
356 #!/bin/sh
357 if [ "\$1" != "upgrade" ]; then
358         grep root=/usr/share/$baseproduct /etc/$baseproduct/miniserv.conf >/dev/null 2>&1
359         if [ "\$?" = 0 ]; then
360                 # Package is being removed, and no new version of webmin
361                 # has taken it's place. Run uninstalls and stop the server
362                 if [ "$product" = "webmin" ]; then
363                         echo "Running uninstall scripts .."
364                         (cd /usr/share/$baseproduct ; WEBMIN_CONFIG=/etc/$baseproduct WEBMIN_VAR=/var/$baseproduct LANG= /usr/share/$baseproduct/run-uninstalls.pl)
365                 fi
366                 /etc/$baseproduct/stop >/dev/null 2>&1 </dev/null
367                 /bin/true
368         fi
369 fi
370 EOF
371 close(SCRIPT);
372 system("chmod 755 $preuninstall_file");
373
374 # Create the post-uninstall script
375 open(SCRIPT, ">$postuninstall_file");
376 print SCRIPT <<EOF;
377 #!/bin/sh
378 if [ "\$1" != "upgrade" ]; then
379         grep root=/usr/share/$baseproduct /etc/$baseproduct/miniserv.conf >/dev/null 2>&1
380         if [ "\$?" = 0 ]; then
381                 # Package is being removed, and no new version of webmin
382                 # has taken it's place. Delete the config files
383                 rm -rf /etc/$baseproduct /var/$baseproduct
384         fi
385 fi
386 EOF
387 close(SCRIPT);
388 system("chmod 755 $postuninstall_file");
389
390 # Run the actual build command
391 system("fakeroot dpkg --build $tmp_dir deb/${product}_${ver}${rel}_all.deb") &&
392         die "dpkg failed";
393 #system("rm -rf $tmp_dir");
394 print "Wrote deb/${product}_${ver}${rel}_all.deb\n";
395 $md5 = `md5sum tarballs/$product-$ver$rel.tar.gz`;
396 $md5 =~ s/\s+.*\n//g;
397 @st = stat("tarballs/$product-$ver.tar.gz");
398
399 # Create the .diff file, which just contains the debian directory
400 $diff_orig_dir = "$tmp_dir/$product-$ver-orig";
401 $diff_new_dir = "$tmp_dir/$product-$ver";
402 mkdir($diff_orig_dir, 0755);
403 mkdir($diff_new_dir, 0755);
404 system("cp -r $debian_dir $diff_new_dir");
405 system("cd $tmp_dir && diff -r -N -u $product-$ver-orig $product-$ver >$webmin_dir/deb/${product}_${ver}${rel}.diff");
406 $diffmd5 = `md5sum deb/${product}_${ver}${rel}.diff`;
407 $diffmd5 =~ s/\s+.*\n//g;
408 @diffst = stat("deb/${product}_${ver}${rel}.diff");
409
410 # Create the .dsc file
411 open(DSC, ">deb/${product}_$ver$rel.plain");
412 print DSC <<EOF;
413 Format: 1.0
414 Source: $product
415 Version: $ver$rel
416 Binary: $product
417 Maintainer: Jamie Cameron <jcameron\@webmin.com>
418 Architecture: all
419 Standards-Version: 3.6.1
420 Build-Depends-Indep: debhelper (>= 4.1.16), debconf (>= 0.5.00), perl
421 Uploaders: Jamie Cameron <jcameron\@webmin.com>
422 Files:
423  $md5 $st[7] ${product}-${ver}.tar.gz
424  $diffmd5 $diffst[7] ${product}_${ver}.diff
425
426 EOF
427 close(DSC);
428 unlink("deb/${product}_$ver$rel.dsc");
429 system("gpg --output deb/${product}_$ver$rel.dsc --clearsign deb/${product}_$ver$rel.plain");
430 unlink("deb/${product}_$ver$rel.plain");
431 print "Wrote source deb/${product}_$ver$rel.dsc\n";
432
433 $dir = "sarge";
434 if (-d "/usr/local/webadmin/deb/repository") {
435         # Add to our repository
436         chdir("/usr/local/webadmin/deb/repository");
437         system("reprepro -Vb . remove $dir $product");
438         system("reprepro -Vb . includedeb $dir ../${product}_${ver}${rel}_all.deb");
439         chdir("/usr/local/webadmin");
440         }
441
442 # Create PGP signature
443 unlink("sigs/${product}_${ver}${rel}_all.deb-sig.asc");
444 system("gpg --armor --output sigs/${product}_${ver}${rel}_all.deb-sig.asc --default-key jcameron\@webmin.com --detach-sig deb/${product}_${ver}${rel}_all.deb");
445
446 # read_file(file, &assoc, [&order], [lowercase])
447 # Fill an associative array with name=value pairs from a file
448 sub read_file
449 {
450 local $_;
451 open(ARFILE, $_[0]) || return 0;
452 while(<ARFILE>) {
453         chomp;
454         local $hash = index($_, "#");
455         local $eq = index($_, "=");
456         if ($hash != 0 && $eq >= 0) {
457                 local $n = substr($_, 0, $eq);
458                 local $v = substr($_, $eq+1);
459                 $_[1]->{$_[3] ? lc($n) : $n} = $v;
460                 push(@{$_[2]}, $n) if ($_[2]);
461                 }
462         }
463 close(ARFILE);
464 if (defined($main::read_file_cache{$_[0]})) {
465         %{$main::read_file_cache{$_[0]}} = %{$_[1]};
466         }
467 return 1;
468 }
469
470 # wrap_lines(text, width)
471 # Given a multi-line string, return an array of lines wrapped to
472 # the given width
473 sub wrap_lines
474 {
475 local @rv;
476 local $w = $_[1];
477 local $rest;
478 foreach $rest (split(/\n/, $_[0])) {
479         if ($rest =~ /\S/) {
480                 while($rest =~ /^(.{1,$w}\S*)\s*([\0-\377]*)$/) {
481                         push(@rv, $1);
482                         $rest = $2;
483                         }
484                 }
485         else {
486                 # Empty line .. keep as it is
487                 push(@rv, $rest);
488                 }
489         }
490 return @rv;
491 }
492
493