Handle hostnames with upper-case letters
[webmin.git] / makemodulerpm.pl
1 #!/usr/bin/perl
2 # makemodulerpm.pl
3 # Create an RPM for a webmin or usermin module or theme
4
5 $target_dir = "/tmp";   # where to copy the RPM to
6
7 if (-d "/usr/src/OpenLinux") {
8         $basedir = "/usr/src/OpenLinux";
9         }
10 else {
11         $basedir = "/usr/src/redhat";
12         }
13 $licence = "Freeware";
14 $release = 1;
15 $< = $>;                # If running setuid
16 $ENV{'PATH'} = "/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin";
17 $allow_overwrite = 0;
18
19 # Parse command-line args
20 while(@ARGV) {
21         local $a = &untaint(shift(@ARGV));
22         if ($a eq "--force-theme") {
23                 $force_theme = 1;
24                 }
25         elsif ($a eq "--rpm-dir") {
26                 $basedir = &untaint(shift(@ARGV));
27                 }
28         elsif ($a eq "--licence" || $a eq "--license") {
29                 $licence = &untaint(shift(@ARGV));
30                 }
31         elsif ($a eq "--rpm-depends") {
32                 $rpmdepends = 1;
33                 }
34         elsif ($a eq "--no-prefix") {
35                 $no_prefix = 1;
36                 }
37         elsif ($a eq "--vendor") {
38                 $vendor = &untaint(shift(@ARGV));
39                 }
40         elsif ($a eq "--provides") {
41                 $provides = &untaint(shift(@ARGV));
42                 }
43         elsif ($a eq "--url") {
44                 $url = shift(@ARGV);
45                 }
46         elsif ($a eq "--release") {
47                 $release = &untaint(shift(@ARGV));
48                 }
49         elsif ($a eq "--usermin") {
50                 $force_usermin = 1;
51                 }
52         elsif ($a eq "--target-dir") {
53                 $target_dir = &untaint(shift(@ARGV));
54                 }
55         elsif ($a eq "--dir") {
56                 $final_mod = &untaint(shift(@ARGV));
57                 }
58         elsif ($a eq "--requires") {
59                 push(@extrareqs, shift(@ARGV));
60                 }
61         elsif ($a eq "--allow-overwrite") {
62                 $allow_overwrite = 1;
63                 }
64         elsif ($a eq "--sign") {
65                 $sign = 1;
66                 }
67         elsif ($a eq "--epoch") {
68                 $epoch = shift(@ARGV);
69                 }
70         elsif ($a =~ /^\-\-/) {
71                 print STDERR "Unknown option $a\n";
72                 exit(1);
73                 }
74         else {
75                 if (!defined($dir)) {
76                         $dir = $a;
77                         }
78                 else {
79                         $ver = $a;
80                         }
81                 }
82         }
83
84 # Validate args
85 if (!$dir) {
86         print STDERR "usage: makemodulerpm.pl [--force-theme]\n";
87         print STDERR "                        [--rpm-dir directory]\n";
88         print STDERR "                        [--rpm-depends]\n";
89         print STDERR "                        [--no-prefix]\n";
90         print STDERR "                        [--vendor name]\n";
91         print STDERR "                        [--licence name]\n";
92         print STDERR "                        [--url url]\n";
93         print STDERR "                        [--provides provides]\n";
94         print STDERR "                        [--usermin]\n";
95         print STDERR "                        [--release number]\n";
96         print STDERR "                        [--epoch number]\n";
97         print STDERR "                        [--target-dir directory]\n";
98         print STDERR "                        [--dir directory-in-package]\n";
99         print STDERR "                        [--allow-overwrite]\n";
100         print STDERR "                        <module> [version]\n";
101         exit(1);
102         }
103 chop($par = `/usr/bin/dirname $dir`);
104 $par = &untaint($par);
105 chop($source_mod = `/bin/basename $dir`);
106 $source_mod = &untaint($source_mod);
107 $source_dir = "$par/$source_mod";
108 $mod = $final_mod || $source_mod;
109 if (!-d $basedir) {
110         die "RPM directory $basedir does not exist";
111         }
112 if ($mod eq "." || $mod eq "..") {
113         die "directory must be an actual directory (module) name, not \"$mod\"";
114         }
115 $spec_dir = "$basedir/SPECS";
116 $rpm_source_dir = "$basedir/SOURCES";
117 $rpm_dir = "$basedir/RPMS/noarch";
118 $source_rpm_dir = "$basedir/SRPMS";
119 if (!-d $spec_dir || !-d $rpm_source_dir || !-d $rpm_dir) {
120         die "RPM directory $basedir is not valid";
121         }
122
123 # Is this actually a module or theme directory?
124 -d $source_dir || die "$dir is not a directory";
125 if (&read_file("$source_dir/module.info", \%minfo) && $minfo{'desc'}) {
126         $depends = join(" ", map { s/\/[0-9\.]+//; $_ }
127                                 grep { !/^[0-9\.]+$/ }
128                                   split(/\s+/, $minfo{'depends'}));
129         if ($minfo{'usermin'} && (!$minfo{'webmin'} || $force_usermin)) {
130                 $prefix = "usm-";
131                 $desc = "Usermin module for '$minfo{'desc'}'";
132                 $prog = "usermin";
133                 }
134         else {
135                 $prefix = "wbm-";
136                 $desc = "Webmin module for '$minfo{'desc'}'";
137                 $prog = "webmin";
138                 }
139         $iver = $minfo{'version'};
140         $post_config = 1;
141         }
142 elsif (&read_file("$source_dir/theme.info", \%tinfo) && $tinfo{'desc'}) {
143         if ($tinfo{'usermin'} && (!$tinfo{'usermin'} || $force_usermin)) {
144                 $prefix = "ust-";
145                 $desc = "Usermin theme '$tinfo{'desc'}'";
146                 $prog = "usermin";
147                 }
148         else {
149                 $prefix = "wbt-";
150                 $desc = "Webmin theme '$tinfo{'desc'}'";
151                 $prog = "webmin";
152                 }
153         $iver = $tinfo{'version'};
154         $istheme = 1;
155         $post_config = 0;
156         }
157 else {
158         die "$source_dir does not appear to be a webmin module or theme";
159         }
160 $prefix = "" if ($no_prefix);
161 $ucprog = ucfirst($prog);
162 $ver ||= $iver;         # Use module.info version, or 1
163 $ver ||= 1;
164
165 # Copy the directory to a temp location for tarring
166 system("/bin/mkdir -p /tmp/makemodulerpm");
167 system("cd $par && /bin/cp -rpL $source_mod /tmp/makemodulerpm/$mod");
168 system("/usr/bin/find /tmp/makemodulerpm -name .svn | xargs rm -rf");
169 system("/usr/bin/find /tmp/makemodulerpm -name .xvpics | xargs rm -rf");
170 system("/usr/bin/find /tmp/makemodulerpm -name '*.bak' | xargs rm -rf");
171 system("/usr/bin/find /tmp/makemodulerpm -name '*~' | xargs rm -rf");
172 system("/usr/bin/find /tmp/makemodulerpm -name '*.rej' | xargs rm -rf");
173 system("/usr/bin/find /tmp/makemodulerpm -name core | xargs rm -rf");
174 system("/bin/chown -R root:bin /tmp/makemodulerpm/$mod");
175
176 # Tar up the directory
177 system("cd /tmp/makemodulerpm && tar czhf $rpm_source_dir/$mod.tar.gz $mod");
178 system("/bin/rm -rf /tmp/makemodulerpm");
179
180 # Build list of dependencies on other RPMs, for inclusion as an RPM
181 # Requires: header
182 if ($rpmdepends) {
183         foreach $d (split(/\s+/, $minfo{'depends'})) {
184                 local ($dwebmin, $dmod, $dver);
185                 if ($d =~ /^[0-9\.]+$/) {
186                         # Depends on a version of Webmin
187                         $dwebmin = $d;
188                         }
189                 elsif ($d =~ /^(\S+)\/([0-9\.]+)$/) {
190                         # Depends on some version of a module
191                         $dmod = $1;
192                         $dver = $2;
193                         }
194                 else {
195                         # Depends on any version of a module
196                         $dmod = $d;
197                         }
198
199                 # If the module is part of Webmin, we don't need to depend on it
200                 if ($dmod) {
201                         local %dinfo;
202                         &read_file("$dmod/module.info", \%dinfo);
203                         next if ($dinfo{'longdesc'});
204                         }
205                 push(@rdeps, $dwebmin ? ("webmin", ">=", $dwebmin) :
206                              $dver ? ($prefix.$dmod, ">=", $dver) :
207                                      ($prefix.$dmod));
208                 }
209         }
210 $rdeps = join(" ", @rdeps, @extrareqs);
211
212 # Create the SPEC file
213 $providesheader = $provides ? "Provides: $provides" : undef;
214 $vendorheader = $vendor ? "Vendor: $vendor" : undef;
215 $urlheader = $url ? "URL: $url" : undef;
216 $epochheader = $epoch ? "Epoch: $epoch" : undef;
217 open(SPEC, ">$spec_dir/$prefix$mod.spec");
218 print SPEC <<EOF;
219 %define __spec_install_post %{nil}
220
221 Summary: $desc
222 Name: $prefix$mod
223 Version: $ver
224 Release: $release
225 PreReq: /bin/sh /usr/bin/perl /usr/libexec/$prog
226 Requires: /bin/sh /usr/bin/perl /usr/libexec/$prog $rdeps
227 AutoReq: 0
228 License: $licence
229 Group: System/Tools
230 Source: $mod.tar.gz
231 Vendor: Jamie Cameron
232 BuildRoot: /tmp/%{name}-%{version}
233 BuildArchitectures: noarch
234 $epochheader
235 $providesheader
236 $vendorheader
237 $urlheader
238 %description
239 $desc in RPM format
240
241 %prep
242 %setup -n $mod
243
244 %build
245 (find . -name '*.cgi' ; find . -name '*.pl') | perl -ne 'chop; open(F,\$_); \@l=<F>; close(F); \$l[0] = "#\!/usr/bin/perl\$1\n" if (\$l[0] =~ /#\!\\S*perl\\S*(.*)/); open(F,">\$_"); print F \@l; close(F)'
246 (find . -name '*.cgi' ; find . -name '*.pl') | xargs chmod +x
247
248 %install
249 mkdir -p %{buildroot}/usr/libexec/$prog/$mod
250 cp -rp * %{buildroot}/usr/libexec/$prog/$mod
251 echo rpm >%{buildroot}/usr/libexec/$prog/$mod/install-type
252
253 %clean
254 [ "%{buildroot}" != "/" ] && rm -rf %{buildroot}
255
256 %files
257 /usr/libexec/$prog/$mod
258
259 %pre
260 # Check if webmin/usermin is installed
261 if [ ! -r /etc/$prog/config -o ! -d /usr/libexec/$prog ]; then
262         echo "$ucprog does not appear to be installed on your system."
263         echo "This RPM cannot be installed unless the RPM version of $ucprog"
264         echo "is installed first."
265         exit 1
266 fi
267 if [ "$depends" != "" -a "$rpmdepends" != 1 ]; then
268         # Check if depended webmin/usermin modules are installed
269         for d in $depends; do
270                 if [ ! -r /usr/libexec/$prog/\$d/module.info ]; then
271                         echo "This $ucprog module depends on the module \$d, which is"
272                         echo "not installed on your system."
273                         exit 1
274                 fi
275         done
276 fi
277 # Check if this module is already installed
278 if [ -d /usr/libexec/$prog/$mod -a "\$1" = "1" -a "$allow_overwrite" != "1" ]; then
279         echo "This $ucprog module is already installed on your system."
280         exit 1
281 fi
282
283 %post
284 if [ "$post_config" = "1" ]; then
285         # Copy config file to /etc/webmin or /etc/usermin
286         os_type=`grep "^os_type=" /etc/$prog/config | sed -e 's/os_type=//g'`
287         os_version=`grep "^os_version=" /etc/$prog/config | sed -e 's/os_version=//g'`
288         /usr/bin/perl /usr/libexec/$prog/copyconfig.pl \$os_type \$os_version /usr/libexec/$prog /etc/$prog $mod
289
290         # Update the ACL for the root user, or the first user in the ACL
291         grep "^root:" /etc/$prog/webmin.acl >/dev/null
292         if [ "\$?" = "0" ]; then
293                 user=root
294         else
295                 user=`head -1 /etc/$prog/webmin.acl | cut -f 1 -d :`
296         fi
297         mods=`grep \$user: /etc/$prog/webmin.acl | cut -f 2 -d :`
298         echo \$mods | grep " $mod" >/dev/null
299         if [ "\$?" != "0" ]; then
300                 grep -v ^\$user: /etc/$prog/webmin.acl > /tmp/webmin.acl.tmp
301                 echo \$user: \$mods $mod > /etc/$prog/webmin.acl
302                 cat /tmp/webmin.acl.tmp >> /etc/$prog/webmin.acl
303                 rm -f /tmp/webmin.acl.tmp
304         fi
305 fi
306 if [ "$force_theme" != "" -a "$istheme" = "1" ]; then
307         # Activate this theme
308         grep -v "^preroot=" /etc/$prog/miniserv.conf >/etc/$prog/miniserv.conf.tmp
309         (cat /etc/$prog/miniserv.conf.tmp ; echo preroot=$mod) > /etc/$prog/miniserv.conf
310         rm -f /etc/$prog/miniserv.conf.tmp
311         grep -v "^theme=" /etc/$prog/config >/etc/$prog/config.tmp
312         (cat /etc/$prog/config.tmp ; echo theme=$mod) > /etc/$prog/config
313         rm -f /etc/$prog/config.tmp
314         (/etc/$prog/stop && /etc/$prog/start) >/dev/null 2>&1
315 fi
316 rm -f /etc/$prog/module.infos.cache
317
318 # Run post-install function
319 if [ "$prog" = "webmin" ]; then
320         cd /usr/libexec/$prog
321         WEBMIN_CONFIG=/etc/$prog WEBMIN_VAR=/var/$prog /usr/libexec/$prog/run-postinstalls.pl $mod
322 fi
323
324 # Run post-install shell script
325 if [ -r "/usr/libexec/$prog/$mod/postinstall.sh" ]; then
326         cd /usr/libexec/$prog
327         WEBMIN_CONFIG=/etc/$prog WEBMIN_VAR=/var/$prog /usr/libexec/$prog/$mod/postinstall.sh
328 fi
329
330 %preun
331 # De-activate this theme, if in use and if we are not upgrading
332 if [ "$istheme" = "1" -a "\$1" = "0" ]; then
333         grep "^preroot=$mod" /etc/$prog/miniserv.conf >/dev/null
334         if [ "\$?" = "0" ]; then
335                 grep -v "^preroot=$mod" /etc/$prog/miniserv.conf >/etc/$prog/miniserv.conf.tmp
336                 (cat /etc/$prog/miniserv.conf.tmp) > /etc/$prog/miniserv.conf
337                 rm -f /etc/$prog/miniserv.conf.tmp
338                 grep -v "^theme=$mod" /etc/$prog/config >/etc/$prog/config.tmp
339                 (cat /etc/$prog/config.tmp) > /etc/$prog/config
340                 rm -f /etc/$prog/config.tmp
341                 (/etc/$prog/stop && /etc/$prog/start) >/dev/null 2>&1
342         fi
343 fi
344 # Run the pre-uninstall script, if we are not upgrading
345 if [ "$prog" = "webmin" -a "\$1" = "0" -a -r "/usr/libexec/$prog/$mod/uninstall.pl" ]; then
346         cd /usr/libexec/$prog
347         WEBMIN_CONFIG=/etc/$prog WEBMIN_VAR=/var/$prog /usr/libexec/$prog/run-uninstalls.pl $mod
348 fi
349 /bin/true
350
351 %postun
352 EOF
353 close(SPEC);
354
355 # Build the actual RPM
356 $cmd = -x "/usr/bin/rpmbuild" ? "/usr/bin/rpmbuild" : "/bin/rpm";
357 system("$cmd -ba $spec_dir/$prefix$mod.spec") && exit;
358 unlink("$rpm_source_dir/$mod.tar.gz");
359
360 # Sign if requested
361 if ($sign) {
362         system("rpm --resign $rpm_dir/$prefix$mod-$ver-$release.noarch.rpm $source_rpm_dir/$prefix$mod-$ver-$release.src.rpm");
363         }
364
365 if ($target_dir =~ /:/) {
366         # scp to dest
367         system("scp $rpm_dir/$prefix$mod-$ver-$release.noarch.rpm $target_dir/$prefix$mod-$ver-$release.noarch.rpm");
368         }
369 else {
370         # Just copy
371         system("/bin/cp $rpm_dir/$prefix$mod-$ver-$release.noarch.rpm $target_dir/$prefix$mod-$ver-$release.noarch.rpm");
372         }
373
374 # read_file(file, &assoc, [&order], [lowercase])
375 # Fill an associative array with name=value pairs from a file
376 sub read_file
377 {
378 open(ARFILE, $_[0]) || return 0;
379 while(<ARFILE>) {
380         s/\r|\n//g;
381         if (!/^#/ && /^([^=]+)=(.*)$/) {
382                 $_[1]->{$_[3] ? lc($1) : $1} = $2;
383                 push(@{$_[2]}, $1) if ($_[2]);
384                 }
385         }
386 close(ARFILE);
387 return 1;
388 }
389  
390 sub untaint
391 {
392 $_[0] =~ /^(.*)$/;
393 return $1;
394 }
395