update mkbaselibs broken by previous debuginfo change
[opensuse:build.git] / mkbaselibs
1 #!/usr/bin/perl -w
2
3 use POSIX;
4 use strict;
5
6 my %STAG = (
7         "NAME"          => 1000,
8         "VERSION"       => 1001,
9         "RELEASE"       => 1002,
10         "EPOCH"         => 1003,
11         "SERIAL"        => 1003,
12         "SUMMARY"       => 1004,
13         "DESCRIPTION"   => 1005,
14         "BUILDTIME"     => 1006,
15         "BUILDHOST"     => 1007,
16         "INSTALLTIME"   => 1008,
17         "SIZE"          => 1009,
18         "DISTRIBUTION"  => 1010,
19         "VENDOR"        => 1011,
20         "GIF"           => 1012,
21         "XPM"           => 1013,
22         "LICENSE"       => 1014,
23         "COPYRIGHT"     => 1014,
24         "PACKAGER"      => 1015,
25         "GROUP"         => 1016,
26         "SOURCE"        => 1018,
27         "PATCH"         => 1019,
28         "URL"           => 1020,
29         "OS"            => 1021,
30         "ARCH"          => 1022,
31         "PREIN"         => 1023,
32         "POSTIN"        => 1024,
33         "PREUN"         => 1025,
34         "POSTUN"        => 1026,
35         "OLDFILENAMES"  => 1027,
36         "FILESIZES"     => 1028,
37         "FILESTATES"    => 1029,
38         "FILEMODES"     => 1030,
39         "FILERDEVS"     => 1033,
40         "FILEMTIMES"    => 1034,
41         "FILEMD5S"      => 1035,
42         "FILELINKTOS"   => 1036,
43         "FILEFLAGS"     => 1037,
44         "FILEUSERNAME"  => 1039,
45         "FILEGROUPNAME" => 1040,
46         "ICON"          => 1043,
47         "SOURCERPM"     => 1044,
48         "FILEVERIFYFLAGS"       => 1045,
49         "ARCHIVESIZE"   => 1046,
50         "PROVIDENAME"   => 1047,
51         "PROVIDES"      => 1047,
52         "REQUIREFLAGS"  => 1048,
53         "REQUIRENAME"   => 1049,
54         "REQUIREVERSION"        => 1050,
55         "NOSOURCE"      => 1051,
56         "NOPATCH"       => 1052,
57         "CONFLICTFLAGS" => 1053,
58         "CONFLICTNAME"  => 1054,
59         "CONFLICTVERSION"       => 1055,
60         "EXCLUDEARCH"   => 1059,
61         "EXCLUDEOS"     => 1060,
62         "EXCLUSIVEARCH" => 1061,
63         "EXCLUSIVEOS"   => 1062,
64         "RPMVERSION"    => 1064,
65         "TRIGGERSCRIPTS"        => 1065,
66         "TRIGGERNAME"   => 1066,
67         "TRIGGERVERSION"        => 1067,
68         "TRIGGERFLAGS"  => 1068,
69         "TRIGGERINDEX"  => 1069,
70         "VERIFYSCRIPT"  => 1079,
71         "CHANGELOGTIME" => 1080,
72         "CHANGELOGNAME" => 1081,
73         "CHANGELOGTEXT" => 1082,
74         "PREINPROG"     => 1085,
75         "POSTINPROG"    => 1086,
76         "PREUNPROG"     => 1087,
77         "POSTUNPROG"    => 1088,
78         "BUILDARCHS"    => 1089,
79         "OBSOLETENAME"  => 1090,
80         "OBSOLETES"     => 1090,
81         "VERIFYSCRIPTPROG"      => 1091,
82         "TRIGGERSCRIPTPROG"     => 1092,
83         "COOKIE"        => 1094,
84         "FILEDEVICES"   => 1095,
85         "FILEINODES"    => 1096,
86         "FILELANGS"     => 1097,
87         "PREFIXES"      => 1098,
88         "INSTPREFIXES"  => 1099,
89         "SOURCEPACKAGE" => 1106,
90         "PROVIDEFLAGS"  => 1112,
91         "PROVIDEVERSION"        => 1113,
92         "OBSOLETEFLAGS" => 1114,
93         "OBSOLETEVERSION"       => 1115,
94         "DIRINDEXES"    => 1116,
95         "BASENAMES"     => 1117,
96         "DIRNAMES"      => 1118,
97         "OPTFLAGS"      => 1122,
98         "DISTURL"       => 1123,
99         "PAYLOADFORMAT" => 1124,
100         "PAYLOADCOMPRESSOR"     => 1125,
101         "PAYLOADFLAGS"  => 1126,
102         "INSTALLCOLOR"  => 1127,
103         "INSTALLTID"    => 1128,
104         "REMOVETID"     => 1129,
105         "RHNPLATFORM"   => 1131,
106         "PLATFORM"      => 1132,
107         "PATCHESNAME"   => 1133,
108         "PATCHESFLAGS"  => 1134,
109         "PATCHESVERSION"        => 1135,
110         "CACHECTIME"    => 1136,
111         "CACHEPKGPATH"  => 1137,
112         "CACHEPKGSIZE"  => 1138,
113         "CACHEPKGMTIME" => 1139,
114         "FILECOLORS"    => 1140,
115         "FILECLASS"     => 1141,
116         "CLASSDICT"     => 1142,
117         "FILEDEPENDSX"  => 1143,
118         "FILEDEPENDSN"  => 1144,
119         "DEPENDSDICT"   => 1145,
120         "SOURCEPKGID"   => 1146,
121         "PRETRANS"      => 1151,
122         "POSTTRANS"     => 1152,
123         "PRETRANSPROG"  => 1153,
124         "POSTTRANSPROG" => 1154,
125         "DISTTAG"       => 1155,
126         "SUGGESTSNAME"  => 1156,
127         "SUGGESTSVERSION"       => 1157,
128         "SUGGESTSFLAGS" => 1158,
129         "ENHANCESNAME"  => 1159,
130         "ENHANCESVERSION"       => 1160,
131         "ENHANCESFLAGS" => 1161,
132         "PRIORITY"      => 1162,
133         "CVSID"         => 1163,
134 );
135
136 # do not mix numeric tags with symbolic tags.
137 # special symbolic tag 'FILENAME' exists.
138 sub rpmq_many {
139   my $rpm = shift;
140   my @stags = @_;
141
142   my $need_filenames = grep { $_ eq 'FILENAMES' } @stags;
143   push @stags, 'BASENAMES', 'DIRNAMES', 'DIRINDEXES', 'OLDFILENAMES' if $need_filenames;
144   @stags = grep { $_ ne 'FILENAMES' } @stags if $need_filenames;
145   my %stags = map {0+($STAG{$_} or $_) => $_} @stags;
146
147   my ($magic, $sigtype, $headmagic, $cnt, $cntdata, $lead, $head, $index, $data, $tag, $type, $offset, $count);
148
149   local *RPM;
150   if (ref($rpm) eq 'ARRAY') {
151     ($headmagic, $cnt, $cntdata) = unpack('N@8NN', $rpm->[0]);
152     if ($headmagic != 0x8eade801) {
153       warn("Bad rpm\n");
154       return ();
155     }
156     if (length($rpm->[0]) < 16 + $cnt * 16 + $cntdata) {
157       warn("Bad rpm\n");
158       return ();
159     }
160     $index = substr($rpm->[0], 16, $cnt * 16);
161     $data = substr($rpm->[0], 16 + $cnt * 16, $cntdata);
162   } else {
163     return () unless open(RPM, "<$rpm");
164     if (read(RPM, $lead, 96) != 96) {
165       warn("Bad rpm $rpm\n");
166       close RPM;
167       return ();
168     }
169     ($magic, $sigtype) = unpack('N@78n', $lead);
170     if ($magic != 0xedabeedb || $sigtype != 5) {
171       warn("Bad rpm $rpm\n");
172       close RPM;
173       return ();
174     }
175     if (read(RPM, $head, 16) != 16) {
176       warn("Bad rpm $rpm\n");
177       close RPM;
178       return ();
179     }
180     ($headmagic, $cnt, $cntdata) = unpack('N@8NN', $head);
181     if ($headmagic != 0x8eade801) {
182       warn("Bad rpm $rpm\n");
183       close RPM;
184       return ();
185     }
186     if (read(RPM, $index, $cnt * 16) != $cnt * 16) {
187       warn("Bad rpm $rpm\n");
188       close RPM;
189       return ();
190     }
191     $cntdata = ($cntdata + 7) & ~7;
192     if (read(RPM, $data, $cntdata) != $cntdata) {
193       warn("Bad rpm $rpm\n");
194       close RPM;
195       return ();
196     }
197   }
198
199   my %res = ();
200
201   if (ref($rpm) eq 'ARRAY' && @stags && @$rpm > 1) {
202     my %res2 = &rpmq_many([ $rpm->[1] ], @stags);
203     %res = (%res, %res2);
204     return %res;
205   }
206
207   if (ref($rpm) ne 'ARRAY' && @stags) {
208     if (read(RPM, $head, 16) != 16) {
209       warn("Bad rpm $rpm\n");
210       close RPM;
211       return ();
212     }
213     ($headmagic, $cnt, $cntdata) = unpack('N@8NN', $head);
214     if ($headmagic != 0x8eade801) {
215       warn("Bad rpm $rpm\n");
216       close RPM;
217       return ();
218     }
219     if (read(RPM, $index, $cnt * 16) != $cnt * 16) {
220       warn("Bad rpm $rpm\n");
221       close RPM;
222       return ();
223     }
224     if (read(RPM, $data, $cntdata) != $cntdata) {
225       warn("Bad rpm $rpm\n");
226       close RPM;
227       return ();
228     }
229   }
230   close RPM if ref($rpm) ne 'ARRAY';
231
232   return %res unless @stags;    # nothing to do
233
234   while($cnt-- > 0) {
235     ($tag, $type, $offset, $count, $index) = unpack('N4a*', $index);
236     $tag = 0+$tag;
237     if ($stags{$tag}) {
238       eval {
239         my $otag = $stags{$tag};
240         if ($type == 0) {
241           $res{$otag} = [ '' ];
242         } elsif ($type == 1) {
243           $res{$otag} = [ unpack("\@${offset}c$count", $data) ];
244         } elsif ($type == 2) {
245           $res{$otag} = [ unpack("\@${offset}c$count", $data) ];
246         } elsif ($type == 3) {
247           $res{$otag} = [ unpack("\@${offset}n$count", $data) ];
248         } elsif ($type == 4) {
249           $res{$otag} = [ unpack("\@${offset}N$count", $data) ];
250         } elsif ($type == 5) {
251           $res{$otag} = [ undef ];
252         } elsif ($type == 6) {
253           $res{$otag} = [ unpack("\@${offset}Z*", $data) ];
254         } elsif ($type == 7) {
255           $res{$otag} = [ unpack("\@${offset}a$count", $data) ];
256         } elsif ($type == 8 || $type == 9) {
257           my $d = unpack("\@${offset}a*", $data);
258           my @res = split("\0", $d, $count + 1);
259           $res{$otag} = [ splice @res, 0, $count ];
260         } else {
261           $res{$otag} = [ undef ];
262         }
263       };
264       if ($@) {
265         warn("Bad rpm $rpm: $@\n");
266         return ();
267       }
268     }
269   }
270   
271   if ($need_filenames) {
272     if ($res{'OLDFILENAMES'}) {
273       $res{'FILENAMES'} = [ @{$res{'OLDFILENAMES'}} ];
274     } else {
275       my $i = 0;
276       $res{'FILENAMES'} = [ map {"$res{'DIRNAMES'}->[$res{'DIRINDEXES'}->[$i++]]$_"} @{$res{'BASENAMES'}} ];
277     }
278   }
279   return %res;
280 }
281
282 sub rpmq_add_flagsvers {
283   my $res = shift;
284   my $name = shift;
285   my $flags = shift;
286   my $vers = shift;
287
288   return unless $res;
289   my @flags = @{$res->{$flags} || []};
290   my @vers = @{$res->{$vers} || []};
291   for (@{$res->{$name}}) {
292     if (@flags && ($flags[0] & 0xe) && @vers) {
293       $_ .= ' ';
294       $_ .= '<' if $flags[0] & 2;
295       $_ .= '>' if $flags[0] & 4;
296       $_ .= '=' if $flags[0] & 8;
297       $_ .= " $vers[0]";
298     }
299     shift @flags;
300     shift @vers;
301   }
302 }
303
304 my @preamble = qw{
305   Name Version Release Epoch Summary Copyright License Distribution
306   Disturl Vendor Group Packager Url Icon Prefixes 
307 };
308
309 my $rpm;
310 my $arch;
311
312 my $config = '';
313
314 my $targettype;
315 my $targetarch;
316 my $prefix;
317 my $extension;
318 my $configdir;
319 my $targetname;
320 my $legacyversion;
321
322 my @baselib;
323 my @config;
324
325 my @provides;
326 my @obsoletes;
327 my @requires;
328 my @prerequires;
329 my @conflicts;
330 my @recommends;
331 my @supplements;
332
333 my @prein;
334 my @postin;
335 my @preun;
336 my @postun;
337 my $autoreqprov;
338
339 my $verbose;
340 my %target_matched;
341 my @filesystem;
342
343 sub parse_config {
344   my $target = shift;
345   my $pkgname = shift;
346   my $pkgver = shift;
347
348   my $pkghasmatched;
349
350   my $pkgmatches = 1;
351   $prefix = '';
352   $legacyversion = '';
353   $extension = '';
354   $configdir = '';
355   $targetname = '';
356   ($targetarch, $targettype) = split(':', $target, 2);
357   @baselib = ();
358   @config = ();
359   @provides = ();
360   @obsoletes = ();
361   @requires = ();
362   @recommends = ();
363   @supplements = ();
364   @prerequires = ();
365   @conflicts = ();
366   @prein = ();
367   @postin = ();
368   @preun = ();
369   @postun = ();
370   $autoreqprov = 'on';
371   my $match1 = '';
372
373   for (split("\n", $config)) {
374     s/^\s+//;
375     s/\s+$//;
376     next if $_ eq '' || $_ =~ /^#/;
377
378     s/\<targettype\>/$targettype/g;
379     s/\<targetarch\>/$targetarch/g;
380     s/\<name\>/$pkgname/g;
381     s/\<version\>/$pkgver/g;
382     s/\<prefix\>/$prefix/g;
383     s/\<extension\>/$extension/g;
384     s/\<configdir\>/$configdir/g;
385     s/\<match1\>/$match1/g;
386
387     if (/^arch\s+/) {
388       next unless s/^arch\s+\Q$arch\E\s+//;
389     }
390     next if /^targets\s+/;
391     if (/\s+package\s+[-+_a-zA-Z0-9]+$/) {
392       $pkgmatches = 0;  # XXX: hack
393     }
394     if (/\s+package\s+\/[-+_a-zA-Z0-9]+\/$/) {
395       $pkgmatches = 0;  # XXX: hack
396     }
397     if (/^targettype\s+/) {
398       next unless s/^targettype\s+\Q$targettype\E\s+//;
399     }
400     if (/^targetarch\s+/) {
401       next unless s/^targetarch\s+\Q$targetarch\E\s+//;
402     }
403     if (/^prefix\s+(.*?)$/) { $prefix = $1; next; }
404     if (/^legacyversion\s+(.*?)$/) { $legacyversion = $1; next; }
405     if (/^extension\s+(.*?)$/) { $extension = $1; next; }
406     if (/^configdir\s+(.*?)$/) { $configdir= $1; next; }
407     if (/^targetname\s+(.*?)$/) { $targetname = $1; next; }
408
409     $_ = "baselib $_" if /^[\+\-\"]/;
410     $_ = "package $_" if /^[-+_a-zA-Z0-9]+$/;
411     if (/^package\s+\/(.*?)\/$/) {
412       my $pm = $1;
413       $pkgmatches = $pkgname =~ /$pm/;
414       $match1 = $1 if defined $1;
415       $pkghasmatched |= $pkgmatches if $pkgname =~ /-debuginfo$/ && $target_matched{$target};
416       next;
417     }
418     if (/^package\s+(.*?)$/) {
419       $pkgmatches = $1 eq $pkgname;
420       $pkghasmatched |= $pkgmatches;
421       next;
422     }
423     next unless $pkgmatches;
424     return 0 if $_ eq 'block!';
425     if (/^provides\s+(.*?)$/) { push @provides, $1; next; }
426     if (/^requires\s+(.*?)$/) { push @requires, $1; next; }
427     if (/^recommends\s+(.*?)$/) { push @recommends, $1; next; }
428     if (/^supplements\s+(.*?)$/) { push @supplements, $1; next; }
429     if (/^prereq\s+(.*?)$/) { push @prerequires, $1; next; }
430     if (/^obsoletes\s+(.*?)$/) { push @obsoletes, $1; next; }
431     if (/^conflicts\s+(.*?)$/) { push @conflicts, $1; next; }
432     if (/^baselib\s+(.*?)$/) { push @baselib, $1; next; }
433     if (/^config\s+(.*?)$/) { push @config, $1; next; }
434     if (/^pre(in)?\s+(.*?)$/) { push @prein, $2; next; }
435     if (/^post(in)?\s+(.*?)$/) { push @postin, $2; next; }
436     if (/^preun\s+(.*?)$/) { push @preun, $1; next; }
437     if (/^postun\s+(.*?)$/) { push @preun, $1; next; }
438     if (/^autoreqprov\s+(.*?)$/) {$autoreqprov = $1; next; }
439     die("bad line: $_\n");
440   }
441   return $pkghasmatched;
442 }
443
444 sub read_config {
445   my $cfname = shift;
446   local *F;
447   open(F, "<$cfname") || die("$cfname: $!\n");
448   my @cf = <F>;
449   close F;
450   $config .= join('', @cf);
451   $config .= "\npackage __does_not_match__\n";
452 }
453
454 sub get_targets {
455   my %targets;
456   for (split("\n", $config)) {
457     if (/^arch\s+/) {
458       next unless s/^arch\s+\Q$arch\E\s+//;
459     }
460     if (/^targets\s+(.*?)$/) {
461       $targets{$_} = 1 for split(' ', $1);
462     }
463   }
464   my @targets = sort keys %targets;
465   return @targets;
466 }
467
468 sub get_pkgnames {
469   my %rpms;
470   for (split("\n", $config)) {
471     if (/^(.*\s+)?package\s+([-+_a-zA-Z0-9]+)\s*$/) {
472       $rpms{$2} = 1;
473     } elsif (/^\s*([-+_a-zA-Z0-9]+)\s*$/) {
474       $rpms{$1} = 1;
475     }
476   }
477   return sort keys %rpms;
478 }
479
480 sub handle_rpms {
481  for $rpm (@_) {
482
483   my @stags = map {uc($_)} @preamble;
484   push @stags, 'DESCRIPTION';
485   push @stags, 'FILENAMES', 'FILEMODES', 'FILEUSERNAME', 'FILEGROUPNAME', 'FILEFLAGS', 'FILEVERIFYFLAGS';
486   push @stags, 'CHANGELOGTIME', 'CHANGELOGNAME', 'CHANGELOGTEXT';
487   push @stags, 'ARCH', 'SOURCERPM', 'RPMVERSION';
488   push @stags, 'BUILDTIME';
489   my %res = rpmq_many($rpm, @stags);
490   die("$rpm: bad rpm\n") unless $res{'NAME'};
491
492   my $rname = $res{'NAME'}->[0];
493   my $sname = $res{'SOURCERPM'}->[0];
494   die("$rpm is a sourcerpm\n") unless $sname;
495   die("bad sourcerpm: $sname\n") unless $sname =~ /^(.*)-([^-]+)-([^-]+)\.(no)?src\.rpm$/;
496   $sname = $1;
497   my $sversion = $2;
498   my $srelease = $3;
499
500   $arch = $res{'ARCH'}->[0];
501   my @targets = get_targets();
502   if (!@targets) {
503     print "no targets for arch $arch, nothing to do\n";
504     exit(0);
505   }
506   for my $target (@targets) {
507
508     next unless parse_config($target, $res{'NAME'}->[0], $res{'VERSION'}->[0]);
509     die("targetname not set\n") unless $targetname;
510     $target_matched{$target} = 1;
511
512     my %ghosts;
513     my @rpmfiles = @{$res{'FILENAMES'}};
514     my @ff = @{$res{'FILEFLAGS'}};
515     for (@rpmfiles) {
516       $ghosts{$_} = 1 if $ff[0] & (1 << 6);
517       shift @ff;
518     }
519     my %files;
520     my %cfiles;
521     my %moves;
522     my %symlinks;
523     for my $r (@baselib) {
524       my $rr = substr($r, 1);
525       if (substr($r, 0, 1) eq '+') {
526         if ($rr =~ /^(.*?)\s*->\s*(.*?)$/) {
527           if (grep {$_ eq $1} @rpmfiles) {
528             $files{$1} = 1;
529             $moves{$1} = $2;
530           }
531         } else {
532           for (grep {/$rr/} @rpmfiles) {
533             $files{$_} = 1;
534             delete $moves{$_};
535           }
536         }
537       } elsif (substr($r, 0, 1) eq '-') {
538         delete $files{$_} for grep {/$rr/} keys %files;
539       } elsif (substr($r, 0, 1) eq '"') {
540         $rr =~ s/\"$//;
541         if ($rr =~ /^(.*?)\s*->\s*(.*?)$/) {
542           $symlinks{$1} = $2;
543         } else {
544           die("bad baselib string rule: $r\n");
545         }
546       } else {
547         die("bad baselib rule: $r\n");
548       }
549     }
550     if ($configdir) {
551       for my $r (@config) {
552         my $rr = substr($r, 1);
553         if (substr($r, 0, 1) eq '+') {
554           $cfiles{$_} = 1 for grep {/$rr/} grep {!$ghosts{$_}} @rpmfiles;
555         } elsif (substr($r, 0, 1) eq '-') {
556           delete $cfiles{$_} for grep {/$rr/} keys %cfiles;
557         } else {
558           die("bad config rule: $r\n");
559         }
560       }
561     }
562     $files{$_} = 1 for keys %cfiles;
563
564     if (!%files) {
565       print "$rname($target): empty filelist, skipping rpm\n";
566       next;
567     }
568
569     my $i = 0;
570     for (@{$res{'FILENAMES'}}) {
571       $files{$_} = $i if $files{$_};
572       $i++;
573     }
574
575     my %cpiodirs;
576     for (keys %files) {
577       next if $cfiles{$_} || $moves{$_};
578       my $fn = $_;
579       next unless $fn =~ s/\/[^\/]+$//;
580       $cpiodirs{$fn} = 1;
581     }
582
583     my %alldirs;
584     for (keys %files) {
585       next if $cfiles{$_};
586       my $fn = $_;
587       if ($moves{$fn}) {
588         $fn = $moves{$fn};
589         next unless $fn =~ s/\/[^\/]+$//;
590         $alldirs{$fn} = 1;
591       } else {
592         next unless $fn =~ s/\/[^\/]+$//;
593         $alldirs{"$prefix$fn"} = 1;
594       }
595     }
596     $alldirs{$_} = 1 for keys %symlinks;
597     $alldirs{$configdir} = 1 if %cfiles;
598     my $ad;
599     for $ad (keys %alldirs) {
600       $alldirs{$ad} = 1 while $ad =~ s/\/[^\/]+$//;
601     }
602     for (keys %files) {
603       next if $cfiles{$_};
604       my $fn = $_;
605       if ($moves{$fn}) {
606         delete $alldirs{$moves{$fn}};
607       } else {
608         delete $alldirs{"$prefix$fn"};
609       }
610     }
611     $ad = $prefix;
612     delete $alldirs{$ad};
613     delete $alldirs{$ad} while $ad =~ s/\/[^\/]+$//;
614     delete $alldirs{$_} for @filesystem;
615
616     my $specfile = "/usr/src/packages/SPECS/mkbaselibs$$.spec";
617     unlink($specfile);
618     print "$rname($target): writing specfile...\n";
619     open(SPEC, ">$specfile") || die("$specfile: $!\n");
620     for my $p (@preamble) {
621       my $pt = uc($p);
622       next unless $res{$pt};
623       my $d = $res{$pt}->[0];
624       $d =~ s/%/%%/g;
625       if ($p eq 'Name') {
626         print SPEC "Name: $sname\n";
627         next;
628       }
629       if ($p eq 'Version') {
630         print SPEC "Version: $sversion\n";
631         next;
632       }
633       if ($p eq 'Release') {
634         print SPEC "Release: $srelease\n";
635         next;
636       }
637       if ($p eq 'Disturl') {
638         print SPEC "%define disturl $d\n";
639         next;
640       }
641       print SPEC "$p: $d\n";
642     }
643     print SPEC "Source: $rpm\n";
644     print SPEC "NoSource: 0\n" if $res{'SOURCERPM'}->[0] =~ /\.nosrc\.rpm$/;
645     print SPEC "BuildRoot: %{_tmppath}/baselibs-%{name}-%{version}-build\n";
646     print SPEC "%define _target_cpu $targetarch\n";
647     print SPEC "%define __os_install_post %{nil}\n";
648     print SPEC "%description\nUnneeded main package. Ignore.\n\n";
649     print SPEC "%package -n $targetname\n";
650     for my $p (@preamble) {
651       next if $p eq 'Name' || $p eq 'Disturl';
652       my $pt = uc($p);
653       next unless $res{$pt};
654       my $d = $res{$pt}->[0];
655       $d =~ s/%/%%/g;
656       if ($pt eq 'VERSION' && $legacyversion) {
657         $d = $legacyversion;
658       } elsif ($pt eq 'RELEASE' && $legacyversion) {
659         my @bt = localtime($res{'BUILDTIME'}->[0]);
660         $bt[5] += 1900;
661         $bt[4] += 1;
662         $d = sprintf("%04d%02d%02d%02d%02d\n", @bt[5,4,3,2,1]);
663       }
664       print SPEC "$p: $d\n";
665     }
666     print SPEC "Autoreqprov: $autoreqprov\n";
667
668     for my $ar ([\@provides, 'provides'],
669                 [\@prerequires, 'prereq'],
670                 [\@requires, 'requires'],
671                 [\@recommends, 'recommends'],
672                 [\@supplements, 'supplements'],
673                 [\@obsoletes, 'obsoletes'],
674                 [\@conflicts, 'conflicts']) {
675         my @a = @{$ar->[0]};
676         my @na = ();
677         for (@a) {
678           if (substr($_, 0, 1) eq '"') {
679             die("bad $ar->[1] rule: $_\n") unless /^\"(.*)\"$/;
680             push @na, $1;
681           } elsif (substr($_, 0, 1) eq '-') {
682             my $ra = substr($_, 1);
683             @na = grep {!/$ra/} @na;
684           } else {
685             die("bad $ar->[1] rule: $_\n");
686           }
687         }
688       print SPEC ucfirst($ar->[1]).": $_\n" for @na;
689     }
690     my $cpiopre = '';
691     $cpiopre = './' if $res{'RPMVERSION'}->[0] !~ /^3/;
692     my $d = $res{'DESCRIPTION'}->[0];
693     $d =~ s/%/%%/g;
694     if ($legacyversion) {
695       $d = "This rpm was re-packaged from $res{'NAME'}->[0]-$res{'VERSION'}->[0]-$res{'RELEASE'}->[0]\n\n$d";
696     }
697     print SPEC "\n%description -n $targetname\n";
698     print SPEC "$d\n";
699     print SPEC "%prep\n";
700     print SPEC "%build\n";
701     print SPEC "%install\n";
702     print SPEC "rm -rf \$RPM_BUILD_ROOT\n";
703     print SPEC "mkdir \$RPM_BUILD_ROOT\n";
704     print SPEC "cd \$RPM_BUILD_ROOT\n";
705     my @cfl = grep {!$cfiles{$_} && !$moves{$_}} sort keys %files;
706     if (@cfl) {
707       if ($prefix ne '') {
708         print SPEC "mkdir -p \$RPM_BUILD_ROOT$prefix\n";
709         print SPEC "pushd \$RPM_BUILD_ROOT$prefix\n";
710       }
711       print SPEC "cat <<EOFL >.filelist\n";
712       print SPEC "$_\n" for map {$cpiopre.substr($_, 1)} @cfl;
713       print SPEC "EOFL\n";
714       print SPEC "mkdir -p \$RPM_BUILD_ROOT$prefix$_\n" for sort keys %cpiodirs;
715       print SPEC "rpm2cpio $rpm | cpio -i -d -v -E .filelist\n";
716       print SPEC "rm .filelist\n";
717       if (%ghosts) {
718         for my $fn (grep {$ghosts{$_}} @cfl) {
719           my $fnm = $fn;
720           $fnm = '.' unless $fnm =~ s/\/[^\/]+$//;
721           print SPEC "mkdir -p \$RPM_BUILD_ROOT$prefix$fnm\n";
722           print SPEC "touch \$RPM_BUILD_ROOT$prefix$fn\n";
723         }
724       }
725       if ($prefix ne '') {
726         print SPEC "popd\n";
727       }
728     }
729     if (%cfiles || %moves) {
730       print SPEC "mkdir -p .cfiles\n";
731       print SPEC "pushd .cfiles\n";
732       print SPEC "cat <<EOFL >.filelist\n";
733       print SPEC "$_\n" for map {$cpiopre.substr($_, 1)} grep {$cfiles{$_} || $moves{$_}} sort keys %files;
734       print SPEC "EOFL\n";
735       print SPEC "rpm2cpio $rpm | cpio -i -d -v -E .filelist\n";
736       print SPEC "popd\n";
737       if (%cfiles) {
738         print SPEC "mkdir -p \$RPM_BUILD_ROOT$configdir\n";
739         print SPEC "mv .cfiles$_ \$RPM_BUILD_ROOT$configdir\n" for sort keys %cfiles;
740       }
741       for my $fn (sort keys %moves) {
742         my $fnm = $moves{$fn};
743         $fnm = '.' unless $fnm =~ s/\/[^\/]+$//;
744         print SPEC "mkdir -p \$RPM_BUILD_ROOT$fnm\n";
745         print SPEC "mv .cfiles$fn \$RPM_BUILD_ROOT$moves{$fn}\n";
746       }
747       print SPEC "rm -rf .cfiles\n";
748     }
749     for my $fn (sort keys %symlinks) {
750       my $fnm = $fn;
751       $fnm = '.' unless $fnm =~ s/\/[^\/]+$//;
752       print SPEC "mkdir -p \$RPM_BUILD_ROOT$fnm\n";
753       print SPEC "ln -s $symlinks{$fn} \$RPM_BUILD_ROOT$fn\n";
754     }
755     if ($prefix ne '' && grep {/\.so.*$/} @cfl) {
756       @postin = () if @postin == 1 && $postin[0] =~ /^\"-p.*ldconfig/;
757       unshift @postin, "\"/sbin/ldconfig -r $prefix\"";
758     }
759
760     if (@prein) {
761       print SPEC "%pre -n $targetname";
762       print SPEC $prein[0] =~ /^\"-p/ ? " " : "\n";
763       for (@prein) {
764         die("bad prein rule: $_\n") unless /^\"(.*)\"$/;
765         print SPEC "$1\n";
766       }
767     }
768     if (@postin) {
769       print SPEC "%post -n $targetname";
770       print SPEC $postin[0] =~ /^\"-p/ ? " " : "\n";
771       for (@postin) {
772         die("bad postin rule: $_\n") unless /^\"(.*)\"$/;
773         print SPEC "$1\n";
774       }
775     }
776     if (@preun) {
777       print SPEC "%preun -n $targetname";
778       print SPEC $preun[0] =~ /^\"-p/ ? " " : "\n";
779       for (@preun) {
780         die("bad preun rule: $_\n") unless /^\"(.*)\"$/;
781         print SPEC "$1\n";
782       }
783     }
784     if (@postun) {
785       print SPEC "%postun -n $targetname";
786       print SPEC $postun[0] =~ /^\"-p/ ? " " : "\n";
787       for (@postun) {
788         die("bad postun rule: $_\n") unless /^\"(.*)\"$/;
789         print SPEC "$1\n";
790       }
791     }
792
793     print SPEC "\n%clean\n";
794     print SPEC "\nrm -rf \$RPM_BUILD_ROOT\n\n";
795     print SPEC "%files -n $targetname\n";
796     for my $file (sort keys %alldirs) {
797       print SPEC "%dir %attr(0755,root,root) $file\n";
798     }
799     for my $file (keys %files) {
800       my $fi = $files{$file};
801       my $fm = $res{'FILEMODES'}->[$fi];
802       my $fv = $res{'FILEVERIFYFLAGS'}->[$fi];
803       my $ff = $res{'FILEFLAGS'}->[$fi];
804       if (POSIX::S_ISDIR($fm)) {
805         print SPEC "%dir ";
806       }
807       if ($ff & ((1 << 3) | (1 << 4))) {
808         print SPEC "%config(missingok noreplace) ";
809       } elsif ($ff & (1 << 3)) {
810         print SPEC "%config(missingok) ";
811       } elsif ($ff & (1 << 4)) {
812         print SPEC "%config(noreplace) ";
813       } elsif ($ff & (1 << 0)) {
814         print SPEC "%config ";
815       }
816       print SPEC "%doc " if $ff & (1 << 1);
817       print SPEC "%ghost " if $ff & (1 << 6);
818       print SPEC "%license " if $ff & (1 << 7);
819       print SPEC "%readme " if $ff & (1 << 8);
820       if ($fv != 4294967295) {
821         print SPEC "%verify(";
822         if ($fv & 2147483648) {
823           print SPEC "not ";
824           $fv ^= 4294967295;
825         }
826         print SPEC "md5 " if $fv & (1 << 0);
827         print SPEC "size " if $fv & (1 << 1);
828         print SPEC "link " if $fv & (1 << 2);
829         print SPEC "user " if $fv & (1 << 3);
830         print SPEC "group " if $fv & (1 << 4);
831         print SPEC "mtime " if $fv & (1 << 5);
832         print SPEC "mode " if $fv & (1 << 6);
833         print SPEC "rdev " if $fv & (1 << 7);
834         print SPEC ") ";
835       }
836       #sigh, no POSIX::S_ISLNK ...
837       if (($fm & 0170000) == 0120000) {
838         printf SPEC "%%attr(-,%s,%s) ", $res{'FILEUSERNAME'}->[$fi], $res{'FILEGROUPNAME'}->[$fi];
839       } else {
840         printf SPEC "%%attr(%03o,%s,%s) ", $fm & 07777, $res{'FILEUSERNAME'}->[$fi], $res{'FILEGROUPNAME'}->[$fi];
841       }
842       if ($cfiles{$file}) {
843         my $fn = $file;
844         $fn =~ s/.*\///;
845         print SPEC "$configdir/$fn\n";
846       } else {
847         if ($moves{$file}) {
848           print SPEC "$moves{$file}\n";
849         } else {
850           print SPEC "$prefix$file\n";
851         }
852       }
853     }
854     for (keys %symlinks) {
855       printf SPEC "%%attr(-,root,root) $_\n";
856     }
857
858     if ($res{'CHANGELOGTEXT'}) {
859       print SPEC "\n%changelog -n $targetname\n";
860       my @ct = @{$res{'CHANGELOGTIME'}};
861       my @cn = @{$res{'CHANGELOGNAME'}};
862       my @wdays = qw{Sun Mon Tue Wed Thu Fri Sat};
863       my @months = qw{Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec};
864       for my $cc (@{$res{'CHANGELOGTEXT'}}) {
865         my @lt = localtime($ct[0]);
866         my $cc2 = $cc;
867         my $cn2 = $cn[0];
868         $cc2 =~ s/%/%%/g;
869         $cn2 =~ s/%/%%/g;
870         printf SPEC "* %s %s %02d %04d %s\n%s\n", $wdays[$lt[6]], $months[$lt[4]], $lt[3], 1900 + $lt[5], $cn2, $cc2;
871         shift @ct;
872         shift @cn;
873       }
874     }
875
876     close(SPEC) || die("$specfile: $!\n");
877     print "$rname($target): running build...\n";
878     if (system("rpmbuild -bb $specfile".($verbose ? '' : '>/dev/null 2>&1'))) {
879       print "rpmbuild failed: $?\n";
880       print "re-running in verbose mode:\n";
881       system("rpmbuild -bb $specfile 2>&1");
882       exit(1);
883     }
884     unlink($specfile);
885   }
886  }
887 }
888
889
890 die("Usage: mkbaselibs <rpms>\n") unless @ARGV;
891
892 if ($ARGV[0] eq '-v') {
893   $verbose = 1;
894   shift @ARGV;
895 }
896 while ($ARGV[0] eq '-c') {
897   shift @ARGV;
898   read_config($ARGV[0]);
899   shift @ARGV;
900 }
901
902 my %goodpkgs = map {$_ => 1} get_pkgnames();
903 my @rpms = @ARGV;
904 my @debugrpms;
905 for my $rpm (splice @rpms) {
906   my $rpmn = $rpm;
907   next if $rpm =~ /\.(no)?src\.rpm$/;
908   next if $rpm =~ /\.spm$/;
909   $rpmn =~ s/.*\///;
910   $rpmn =~ s/-[^-]+-[^-]+\.[^\.]+\.rpm$/\.rpm/;
911   $rpmn =~ s/\.rpm$//;
912   push @rpms, $rpm if $goodpkgs{$rpmn};
913   if ($rpmn =~ s/-debuginfo$//) {
914       push @debugrpms, $rpm if $goodpkgs{$rpmn};
915   }
916 }
917 for (@rpms) {
918   die("$_: need absolute path to rpm\n") unless /^\//;
919 }
920
921 exit 0 unless @rpms;
922
923 @filesystem = split("\n", `rpm -ql filesystem 2>/dev/null`);
924 die("filesystem rpm is not installed\n") unless @filesystem;
925
926 handle_rpms(@rpms);
927 handle_rpms(@debugrpms);
928
929