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