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