This commit was manufactured by cvs2svn to create tag
[opensuse:installation-images.git] / lib / ReadConfig.pm
1 #! /usr/bin/perl -w
2
3 # Read the config file ('etc/config') and set up some useful variables.
4 # Exports some useful functions, too.
5 #
6 # Usage:
7 #
8 #   use ReadConfig;
9 #
10 #   exported functions:
11 #     Print2File(file_name, print_args);
12 #     SUSystem(command);
13 #
14 #   exported arrays:
15 #     %ConfigData
16 #
17 #   exported variables:
18 #     $Script, $BasePath, $LibPath, $BinPath, $CfgPath, $ImagePath,
19 #     $DataPath, $TmpBase, $MToolsCfg, $AutoBuild
20 #
21 #   symbols *not* exported by default:
22 #     $SUBinary, DebugInfo
23
24 =head1 ReadConfig
25
26 C<ReadConfig> is a perl module that reads config data from C<etc/config>
27 initializes a few global variables and exports some useful functions. It
28 should always be included in scripts operating within the C<bootdisk>
29 directory hierarchy.
30
31 It assumes that the script that included this library was either called from
32 the base directory or from the C<bin> subdirectory of the base directory.
33 The base directory itself may be located anywhere.
34
35 This is mainly to avoid an environment variable to hold the base directory
36 (like C<BOOTDISK_ROOT> or something similar).
37
38 For the curious: the regular expression used to find the base directory name
39 from the full script name is:
40
41 C<( $0 =~ /(.*?)((?<![^\/])bin\/)?([^\/]+)$/ )[0]>
42
43 =head2 Usage
44
45 C<BEGIN { unshift @INC, ( $0 =~ /(.*?)((?<![^\/])bin\/)?[^\/]+$/ )[0] . "lib" }>
46
47 C<use ReadConfig;>
48
49 =head2 Description
50
51 =over
52
53 =item *
54
55 C<Print2File(file_name, print_args)>
56
57 C<Print2File(file_name, print_args)> opens the file C<file_name> and prints
58 to it. C<print_args> are the arguments that would be given to a normal
59 C<print> command. It's mainly for convenience.
60
61 =for html <p>
62
63 =item *
64
65 C<SUSystem(command)>
66
67 C<SUSystem(command)> executes C<command> with root permissions. This
68 requires a special 'C<sudo>' command to be installed that can give you root
69 privileges without asking for a password. The name of this command is
70 C</usr/local/sw> and can only be changed by editing the C<ReadConfig.pm>
71 file.
72
73 This allows you to run the bootdisk scripts as a normal user.
74
75 If you don't have such a program or are running the scripts as root, C<SUSystem> is
76 I<identical> to the usual C<system> command.
77
78 You can check if this feature is actually available by looking at the
79 C<$ReadConfig::SUBinary> variable that holds the name of the 'C<sudo>'
80 command (or C<undef>).
81
82 =for html <p>
83
84 =item *
85
86 C<%ConfigData>
87
88 C<%ConfigData> is an hash table that holds the config info read from C<etc/config>.
89 C<etc/config> is a shell script that may contain I<only> variable assignments.
90
91 =for html <p>
92
93 =item *
94
95 exported variables
96
97 =over
98
99 =item *
100
101 C<$Script> is the name of the script that included this library (without the path).
102
103 =item *
104
105 C<$BasePath> holds the name of the base directory.
106
107 =item *
108
109 C<$LibPath = "$BasePath/lib">.
110
111 =item *
112
113 C<$BinPath = "$BasePath/bin">. The C<PATH> environment variable is
114 appropriately extended.
115
116 =item *
117
118 C<$CfgPath = "$BasePath/etc">.
119
120 =item *
121
122 C<$ImagePath = "$BasePath/images">.
123
124 =item *
125
126 C<$DataPath = "$BasePath/data">.
127
128 =item *
129
130 C<$TmpBase> is the name used for temporary file/directory names.
131
132 =item *
133
134 C<$MToolsCfg> is the name of a temporary C<mtools> config file. The
135 C<MTOOLSRC> environment variable is set to point to it.
136
137 =back
138
139 =for html <p>
140
141 =item *
142
143 symbols that are not exported
144
145 =over
146
147 =item *
148
149 C<DebugInfo()> prints the current values of some variables.
150
151 =item *
152
153 C<$SUBinary> (see C<SUSystem> above).
154
155 =back
156
157 =back
158
159 =cut
160
161
162 package ReadConfig;
163
164 require Exporter;
165 @ISA = qw ( Exporter );
166 @EXPORT = qw (
167   $Script $BasePath $LibPath $BinPath $CfgPath $ImagePath $DataPath
168   $TmpBase %ConfigData RPMFileName SUSystem Print2File $MToolsCfg $AutoBuild
169 );
170
171 use strict 'vars';
172 use vars qw (
173   $Script $BasePath $LibPath $BinPath $CfgPath $ImagePath $DataPath
174   $TmpBase %ConfigData $SUBinary &RPMFileName &SUSystem &Print2File $MToolsCfg $AutoBuild
175 );
176
177 sub DebugInfo
178 {
179   local $_;
180
181   print "Script = \"$Script\"\n";
182   print "BasePath = \"$BasePath\"\n";
183   print "LibPath = \"$LibPath\"\n";
184   print "BinPath = \"$BinPath\"\n";
185   print "CfgPath = \"$CfgPath\"\n";
186   print "ImagePath = \"$ImagePath\"\n";
187   print "DataPath = \"$DataPath\"\n";
188   print "TmpBase = \"$TmpBase\"\n";
189   print "MToolsCfg = \"$MToolsCfg\"\n";
190
191   print "ConfigData:\n";
192   for (sort keys %ConfigData) {
193     print "  $_ = \"$ConfigData{$_}\"\n"
194   }
195 }
196
197 #
198 #
199 #
200 sub RPMFileName
201 {
202   my ($rpm, $file, @f, $x);
203   local $_;
204
205   $rpm = shift;
206
207   $file = $ConfigData{'cache_dir'};
208
209   if($ConfigData{'use_cache'} && $file && -f "$file/$rpm.rpm") {
210
211     # print "*$rpm: $file/$rpm.rpm\n";
212
213     return "$file/$rpm.rpm";
214   }
215
216   $file = $ConfigData{'tmp_cache_dir'};
217
218   if($file && -d $file) {
219     $file .= "/.rpms";
220     mkdir $file, 0755 unless -d $file;
221     $file .= "/$rpm.rpm";
222
223     # print "#$rpm: $file\n" if -f $file;
224
225     return $file if -f $file;
226   }
227
228   undef $file;
229
230   for (`cat $ConfigData{'suse_base'}/find-name-rpm 2>/dev/null`) {
231     chomp;
232     s/^\.\///;
233     if(m#/(\Q$rpm\E|\Q$rpm\E\-[^\-]+\-[^\-]+\.[^.\-]+)\.rpm$#) {
234       $file = "$ConfigData{'suse_base'}/$_";
235       last;
236     }
237   }
238
239   if(!$file) {
240     @f = glob "$ConfigData{'suse_base'}/$rpm.rpm";
241     if($f[0] && -f $f[0]) {
242       $file = $f[0];
243     }
244   }
245
246   if(!$file) {
247     @f = glob "$ConfigData{'suse_base'}/$rpm-*-*.rpm";
248     for (@f) {
249       next if /\.src\.rpm$/;
250       if($_ && -f $_ && m#/\Q$rpm\E\-[^\-]+\-[^\-]+\.[^.\-]+\.rpm$#) {
251         $file = $_;
252         last;
253       }
254     }
255   }
256
257   $x = $ConfigData{'tmp_cache_dir'};
258
259   if($file && $x && -d($x)) {
260     $x .= "/.rpms";
261     mkdir $x, 0755 unless -d $x;
262     if(-d $x) {
263       symlink($file, "$x/$rpm.rpm");
264     }
265   }
266
267   # print "$rpm: $file\n" if $file;
268
269   return $file;
270 }
271
272
273 #
274 # execute string as root
275 #
276 sub SUSystem
277 {
278   if($SUBinary) {
279     return system "$SUBinary -q 0 $_[0]";
280   }
281   else {
282     return system @_;
283   }
284 }
285
286 #
287 # print to a file
288 #
289 sub Print2File
290 {
291   local $_ = shift;
292
293   open Print2File_F, ">$_" or return undef;
294   print Print2File_F @_;
295   close Print2File_F;
296
297   return 1;
298 }
299
300
301 #
302 # return list of kernel images
303 #
304 sub KernelImg
305 {
306   local $_;
307   my ($k_regexp, @k_files, @k_images, @kernels);
308
309   ($k_regexp, @k_files) = @_;
310
311   chomp @k_files;
312
313   for (@k_files) {
314     s#^/boot/##;
315     next if /autoconf|config|shipped|version/;          # skip obvious garbage
316     push @k_images, $_ if m#$k_regexp#;
317   }
318
319   return @k_images;
320 }
321
322
323 sub version_sort
324 {
325   my ($i, $j);
326
327   $i = $ConfigData{ini}{Version}{$a};
328   $j = $ConfigData{ini}{Version}{$b};
329
330   $i =~ s/,([^,]+)//;
331   $j =~ s/,([^,]+)//;
332
333   return $i <=> $j;
334 }
335
336
337 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
338 #
339 # initialization part
340 #
341
342 delete $ENV{'LANG'};
343 delete $ENV{'LANGUAGE'};
344
345 if($0 =~ /(.*?)((?<![^\/])bin\/)?([^\/]+)$/) {
346   $Script = $3;
347   $BasePath = $1;
348   $LibPath = $1 . "lib/";
349   $BinPath = $1 . "bin/";
350   $CfgPath = $1 . "etc/";
351   $ImagePath = $1 . "images/";
352   $DataPath = $1 . "data/";
353 }
354 else {
355   die "OOPS: don't invoke the script that way!\n"
356 }
357
358 if(!(
359   ($BasePath eq "" || -d $BasePath) &&
360   -d $LibPath &&
361   -d $BinPath &&
362   -d $CfgPath &&
363   -d $ImagePath &&
364   -d $DataPath
365 )) {
366   die "$Script: you got it all wrong!\n";
367 }
368
369 $| = 1;
370
371 $_ = $BinPath;
372 s:^(.+)/$:$1:;
373 $ENV{PATH} = "/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin:$_";
374
375 $TmpBase = "/tmp/${Script}_${$}";
376 $MToolsCfg = "$TmpBase.mtoolsrc";
377
378 $ENV{MTOOLSRC} = $MToolsCfg;
379
380 # The purpose of this is to allow to run the scripts without having root
381 # permissions.
382 #
383 # The $SUBinary must be a program that gives you superuser rights *without*
384 # a password.
385 #
386 # If you don't have such a program or *are* already root this feature is
387 # turned off.
388
389 if($<) {        # only if we are *not* already root
390   $SUBinary = "/usr/local/bin/sw";
391   $SUBinary = "/usr/bin/sw" if -x "/usr/bin/sw";
392   $SUBinary = undef unless -x $SUBinary && -u $SUBinary;
393 }
394
395
396 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
397 #
398 # set arch
399 #
400
401 my ($arch, $realarch, $susearch);
402
403 $arch = `uname -m`;
404 chomp $arch;
405 $arch = "i386" if $arch =~ /^i.86$/;
406 $realarch = $arch;
407 $arch = "sparc" if $arch eq 'sparc64';
408
409 $susearch = $arch;
410 $susearch = 'axp' if $arch eq 'alpha';
411
412 $ConfigData{arch} = $arch;
413
414
415 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
416 #
417 # read config file & .buildenv
418 #
419
420 {
421   my ($f, @f, $sect, $i, $j);
422
423   $f = $CfgPath . "config";
424   die "$Script: no config file \"$f\"\n" unless open(F, "$f.$arch") || open(F, $f);
425
426   while(<F>) {
427     chomp;
428     s/^\s*([#;].*)?//;
429     next if $_ eq "";
430     if(/^\[(.+)\]/) {
431       $sect = $1;
432       next;
433     }
434     if(/^\s*([^=]*?)\s*=\s*(.*?)\s*$/) {
435       $ConfigData{ini}{$sect}{$1} = $2 if defined $sect;
436       next;
437     }
438   }
439
440   close F;
441
442   $ConfigData{buildroot} = $ENV{buildroot} ? $ENV{buildroot} : "";
443
444   if(open F, "$ConfigData{buildroot}/.buildenv") {
445     while(<F>) {
446       chomp;
447       s/^\s*([#;].*)?//;
448       next if $_ eq "";
449       if(/^\s*([^=]*?)\s*=\s*(.*?)\s*$/) {
450         $i = $1;
451         $j = $2;
452         $j = $1 if $j =~ /^\"(.*)\"$/;
453         $ConfigData{buildenv}{$i} = $j;
454       }
455     }
456     close F;
457   }
458 }
459
460
461 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
462 # kernel image name
463 #
464
465 $ConfigData{kernel_img} = $ConfigData{ini}{KernelImage}{default}
466   if $ConfigData{ini}{KernelImage}{default};
467
468 $ConfigData{kernel_img} = $ConfigData{ini}{KernelImage}{$arch}
469   if $ConfigData{ini}{KernelImage}{$arch};
470
471 $ConfigData{kernel_img} = $ENV{kernel_img} if $ENV{kernel_img};
472
473
474 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
475 # kernel rpm name
476 #
477
478 $ConfigData{kernel_rpm} = $ConfigData{ini}{KernelRPM}{default}
479   if $ConfigData{ini}{KernelRPM}{default};
480
481 $ConfigData{kernel_rpm} = $ConfigData{ini}{KernelRPM}{$arch}
482   if $ConfigData{ini}{KernelRPM}{$arch};
483
484 $ConfigData{kernel_rpm} = $ENV{kernel} if $ENV{kernel};
485
486
487 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
488
489
490 # print STDERR "kernel_rpm = $ConfigData{kernel_rpm}, kernel_img = $ConfigData{kernel_img}\n";
491
492 # print STDERR "BUILD_DISTRIBUTION_NAME = $ConfigData{buildenv}{BUILD_DISTRIBUTION_NAME}\n";
493 # print STDERR "BUILD_BASENAME = $ConfigData{buildenv}{BUILD_BASENAME}\n";
494
495
496 {
497   # set suse_release, suse_base, suse_xrelease
498   # kernel_ver
499   # (used to be in etc/config)
500
501   my ( $r, $r0, $rx, $in_abuild, $a, $v, $kv, $rf, $ki, @f );
502   my ( $theme, $sles_release, $load_image, $yast_theme, $splash_theme, $product_name, $update_dir );
503
504   my ( $dist, $i, $j, $rel, $xrel );
505
506   $in_abuild = $ConfigData{buildenv}{BUILD_BASENAME} ? 1 : 0;
507
508   # print STDERR "abuild = $in_abuild\n";
509
510   if($in_abuild) {
511
512     $dist = $ConfigData{buildenv}{BUILD_BASENAME};
513
514     if(!-d("$ConfigData{buildroot}/.rpm-cache/$dist")) {
515       system "ls -la $ConfigData{buildroot}/.rpm-cache";
516       die "No usable /.rpm-cache (looking for \"$dist\")!\n"
517     }
518
519     $ConfigData{suse_base} = $AutoBuild = "$ConfigData{buildroot}/.rpm-cache/$dist"
520   }
521   else {
522     my ($work, $base, $xdist);
523
524     $dist = $susearch;
525
526     $work = $ENV{work};
527     $work = "/work" if !$work;
528     $work = "/mounts/work" if ! -d "$work/CDs";
529     $work .= "/CDs";
530     $work .= "/all" if -d "$work/all";
531
532     $xdist = $ENV{dist} ? $ENV{dist} : $ENV{suserelease};
533
534     if($xdist) {
535       $base = "$work/full-$xdist/suse";
536       $dist = $xdist if -d $base;
537       if(! -d $base) {
538         $base = "$work/full-$xdist-$dist/suse";
539         $dist = "$xdist-$dist" if -d $base;
540       }
541     }
542     else {
543       $base = "$work/full-$dist/suse";
544     }
545
546     die "Sorry, could not locate packages for \"$dist\".\n" unless -d $base;
547
548     $ConfigData{suse_base} = "$base/*";
549
550   }
551
552   $ConfigData{dist} = $dist;
553
554   # print STDERR "base = $ConfigData{suse_base}\n";
555
556   $i = $dist;
557
558   while(!($rel = $ConfigData{ini}{Version}{$i}) && $i =~ s/-[^\-]+$//) {}
559   $rel = $ConfigData{ini}{Version}{default} if !$rel && $dist !~ /-/;
560
561   die "Sorry, \"$ConfigData{dist}\" is not supported.\n" unless $rel;
562
563   $xrel = $1 if $rel =~ s/,([^,]+)//;
564
565   # print STDERR "rel = $rel ($xrel)\n";
566
567   $ConfigData{suse_release} = $rel;
568   $ConfigData{suse_xrelease} = $xrel;
569
570   my $cache_dir = `pwd`;
571   chomp $cache_dir;
572   my $tmp_cache_dir = $cache_dir;
573   $cache_dir .= "/${BasePath}cache/$ConfigData{dist}";
574   $ConfigData{'cache_dir'} = $cache_dir;
575   $tmp_cache_dir .= "/${BasePath}tmp/cache/$ConfigData{dist}";
576   $ConfigData{'tmp_cache_dir'} = $tmp_cache_dir;
577   system "mkdir -p $tmp_cache_dir" unless -d $tmp_cache_dir;
578   my $use_cache = 0;
579
580   $ENV{'cache'} = 4 unless exists $ENV{'cache'};
581   $use_cache = $ENV{'cache'} if exists $ENV{'cache'};
582   $ConfigData{'use_cache'} = $use_cache;
583
584   if($in_abuild) {
585     my (@k_images2, %k_rpms);
586
587     my @k_images = KernelImg $ConfigData{kernel_img}, (`find $ConfigData{buildroot}/boot -type f`);
588
589     if(!@k_images) {
590       die "Error: No kernel image identified! (Looking for \"$ConfigData{kernel_img}\" in \"$ConfigData{kernel_rpm}\".)\n\n";
591     }
592
593     $i = $ConfigData{buildroot} ? "-r $ConfigData{buildroot}" : "";
594
595     for (@k_images) {
596       $j = `rpm $i -qf /boot/$_ | head -n 1 | sed 's/-[^-]*-[^-]*\$//'` if -f "$ConfigData{buildroot}/boot/$_";
597       chomp $j;
598       undef $j if $j =~ /^file /;       # avoid "file ... not owned by any package"
599       $k_rpms{$_} = $j if $j;
600       if($j && $j eq $ConfigData{kernel_rpm}) {
601         push @k_images2, $_;
602       }
603     }
604
605     if(@k_images == 1) {
606       # ok, use just this one
607       $ConfigData{kernel_img} = $k_images[0];
608     }
609     else {
610       if(!@k_images2) {
611         die "Error: No kernel image identified! (Looking for \"$ConfigData{kernel_img}\" in \"$ConfigData{kernel_rpm}\".)\n\n";
612       }
613       elsif(@k_images2 > 1) {
614         warn
615           "Warning: Can't identify the real kernel image, choosing the first:\n",
616           join(", ", @k_images2), "\n\n";
617       }
618       $ConfigData{kernel_img} = $k_images2[0];
619     }
620     $ConfigData{kernel_rpm} = $k_rpms{$ConfigData{kernel_img}} if $k_rpms{$ConfigData{kernel_img}};
621
622     $kv = `rpm $i -ql $ConfigData{kernel_rpm} 2>/dev/null | grep modules | head -n 1 | cut -d / -f 4`;
623   }
624   else {
625     $i = RPMFileName $ConfigData{kernel_rpm};
626
627     my @k_images = KernelImg $ConfigData{kernel_img}, (`rpm -qlp $i 2>/dev/null | grep ^/boot`);
628
629     if(!@k_images) {
630       die "Error: No kernel image identified! (Looking for \"$ConfigData{kernel_img}\".)\n\n";
631     }
632
633     if(@k_images != 1) {
634       warn "Warning: Can't identify the real kernel image, choosing the first:\n", join(", ", @k_images), "\n\n";
635     }
636
637     $ConfigData{kernel_img} = $k_images[0];
638
639     $kv = `rpm -qlp $i 2>/dev/null | grep modules | head -n 1 | cut -d / -f 4`;
640   }
641   chomp $kv;
642
643   $ConfigData{kernel_ver} = $kv;
644
645   $ConfigData{module_type} = $kv =~ /^2\.[0-4]\./ ? "o" : "ko";
646
647   # print STDERR "kernel_img = $ConfigData{kernel_img}\n";
648   # print STDERR "kernel_rpm = $ConfigData{kernel_rpm}\n";
649   # print STDERR "kernel_ver = $ConfigData{kernel_ver}\n";
650
651   $theme = $ENV{theme} ? $ENV{theme} : "SuSE";
652
653   for $i (sort version_sort keys %{$ConfigData{ini}{Version}}) {
654     $j = $ConfigData{ini}{Version}{$i};
655     $j =~ s/,([^,]+)//;
656     if($j <= $ConfigData{suse_release}) {
657       $sles_release = $i if $i =~ /^sles/;
658     }
659   }
660
661   die "Oops, no SLES release number found\n" unless $sles_release;
662
663   # print STDERR "sles = $sles_release\n";
664
665   die "Don't know theme \"$theme\"\n" unless exists $ConfigData{ini}{"Theme $theme"};
666
667   if($ENV{themes}) {
668     my %t;
669     @t{split ' ', $ENV{themes}} = ();
670     die "Theme \"$theme\" not supported\n" unless exists $t{$theme};
671   }
672
673   $yast_theme = $ConfigData{ini}{"Theme $theme"}{yast};
674   $splash_theme = $ConfigData{ini}{"Theme $theme"}{splash};
675   $product_name = $ConfigData{ini}{"Theme $theme"}{product};
676   my $full_product_name = $product_name;
677   $full_product_name .= (" " . $ConfigData{ini}{"Theme $theme"}{version}) if $ConfigData{ini}{"Theme $theme"}{version};
678   $update_dir = $ConfigData{ini}{"Theme $theme"}{update};
679   $update_dir =~ s/<sles>/$sles_release/g;
680   $update_dir =~ s/<rel>/$rel/g;
681   $update_dir =~ s/<arch>/$realarch/g;
682   $load_image = $ConfigData{ini}{"Theme $theme"}{image};
683   $load_image = $load_image * 1024 if $load_image;
684
685   $ConfigData{theme} = $theme;
686   $ConfigData{yast_theme} = $yast_theme;
687   $ConfigData{splash_theme} = $splash_theme;
688   $ConfigData{product_name} = $product_name;
689   $ConfigData{full_product_name} = $full_product_name;
690   $ConfigData{update_dir} = $update_dir;
691   $ConfigData{load_image} = $load_image;
692
693   $ConfigData{min_memory} = $ConfigData{ini}{"Theme $theme"}{memory};
694
695   # print STDERR "yast_theme = $ConfigData{yast_theme}\n";
696   # print STDERR "splash_theme = $ConfigData{splash_theme}\n";
697   # print STDERR "product_name = $ConfigData{product_name}\n";
698   # print STDERR "update_dir = $ConfigData{update_dir}\n";
699   # print STDERR "load_image = $ConfigData{load_image}\n";
700
701   $ConfigData{kernel_mods} = $ConfigData{kernel_ver};
702   $ConfigData{kernel_mods} =~ s/-(.+?)-/-override-/;
703
704   if(!$ENV{silent}) {
705     my $r;
706
707     $r = $ConfigData{suse_release};
708     $r .= " $ConfigData{suse_xrelease}" if $ConfigData{suse_xrelease};
709
710     print "--- Building for $product_name $r $ConfigData{arch} ($sles_release), theme $ConfigData{theme}\n";
711     print "--- Kernel: $ConfigData{kernel_rpm}, $ConfigData{kernel_img}, $ConfigData{kernel_ver}\n";
712
713     $r = $ConfigData{suse_base};
714     $r =~ s/\/\*$//;
715     print "--- Source: $r\n";
716   }
717 }
718
719 1;