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