1#! /usr/bin/perl 2# Copyright (c) 2005-2010 Marc Espie <espie@openbsd.org> 3# $OpenBSD: pkg_mklocatedb,v 1.41 2014/03/18 18:53:29 espie Exp $ 4# 5# Permission to use, copy, modify, and distribute this software for any 6# purpose with or without fee is hereby granted, provided that the above 7# copyright notice and this permission notice appear in all copies. 8# 9# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 17use strict; 18use warnings; 19 20use OpenBSD::PackageInfo; 21use OpenBSD::PackingList; 22use OpenBSD::Getopt; 23use OpenBSD::Error; 24use OpenBSD::Paths; 25use OpenBSD::AddCreateDelete; 26 27package OpenBSD::Pkgmklocatedb::State; 28our @ISA = qw(OpenBSD::AddCreateDelete::State); 29 30sub handle_options 31{ 32 my $state = shift; 33 $state->{no_exports} = 1; 34 $state->SUPER::handle_options('aCd:Knqs:x:r:p:Pu', 35 '[-aCKnPqu] [-d repository] [-p portsdir] [-r release] [-s src] ', 36 '[-x X11src] [pkg-name [...]]'); 37 $state->{srcdir} = $state->opt('s'); 38 $state->{xdir} = $state->opt('x'); 39 $state->{releasedir} = $state->opt('r'); 40 $state->{portsdir} = $state->opt('p'); 41 $state->{pkgdir} = $state->opt('d'); 42 $state->{quiet} = $state->opt('q'); 43 $state->{pkgpath} = $state->opt('P'); 44 $state->{allinfo} = $state->opt('a'); 45 $state->{nopipe} = $state->opt('n'); 46 $state->{check} = $state->opt('C'); 47 $state->{full} = $state->opt('K'); 48 $state->{update} = $state->opt('u'); 49 if ($state->{check}) { 50 unless ($state->{srcdir} or $state->{portsdir}) { 51 $state->usage("-C without -s dir or -x dir"); 52 } 53 } 54} 55 56 57package OpenBSD::PackingElement; 58sub print_name {} 59sub set_header {} 60 61package OpenBSD::PackingElement::Name; 62sub set_header 63{ 64 my ($self, $state) = @_; 65 $state->{currentheader} = $self->{name}.':'; 66} 67 68package OpenBSD::PackingElement::ExtraInfo; 69sub set_header 70{ 71 my ($self, $state) = @_; 72 if ($state->{allinfo}) { 73 $state->{currentheader} .= $self->{subdir}.':'; 74 } elsif ($state->{pkgpath}) { 75 $state->{currentheader} = $self->{subdir}.':'; 76 } 77 $state->{done}{$self->{subdir}} = 1; 78 $state->errsay($state->{currentheader}) unless $state->{quiet}; 79} 80 81package OpenBSD::PackingElement::FileObject; 82sub object_name 83{ 84 my ($self, $state) = @_; 85 if ($state->{full}) { 86 if ($self->needs_keyword) { 87 return "\@".$self->keyword." ".$self->fullname; 88 } 89 } 90 return $self->fullname; 91} 92 93sub print_name 94{ 95 my ($self, $state) = @_; 96 print {$state->{out}} $state->{currentheader}, 97 $self->object_name($state), "\n"; 98} 99 100package OpenBSD::PackingElement::Action; 101sub print_name 102{ 103 my ($self, $state) = @_; 104 print {$state->{out}} $state->{currentheader}, $self->fullstring, "\n"; 105} 106 107package OpenBSD::PackingElement::ExeclikeAction; 108sub print_name 109{ 110 my ($self, $state) = @_; 111 print {$state->{out}} $state->{currentheader}, "\@". 112 $self->keyword, " ", $self->{expanded}, "\n"; 113} 114 115package OpenBSD::PackingElement::DirBase; 116sub print_name 117{ 118 my ($self, $state) = @_; 119 print {$state->{out}} $state->{currentheader}, 120 $self->object_name($state), "/\n"; 121} 122 123package main; 124sub tag 125{ 126 my ($state, $dir, $set, $rev) = @_; 127 my $r; 128 if ($state->{allinfo}) { 129 $r = "$dir/$set:$set$rev"; 130 } elsif ($state->{pkgpath}) { 131 $r = "$dir/$set"; 132 } else { 133 $r = "$set$rev"; 134 } 135 $state->errsay($r) unless $state->{quiet}; 136 return $r; 137} 138 139my ($rev, $arch); 140sub findos 141{ 142 my $cmd = OpenBSD::Paths->uname." -mr"; 143 ($rev, $arch) = split(/\s+/o, `$cmd`); 144 chomp $arch; 145 $rev =~ s/\.//; 146} 147 148sub open_output 149{ 150 my $state = shift; 151 152 153 if ($state->{nopipe} or -t STDOUT) { 154 $state->{out} = \*STDOUT; 155 } else { 156 my $MKLOCATEDB = OpenBSD::Paths->mklocatedb; 157 158 open $state->{out}, "|-", $MKLOCATEDB, $MKLOCATEDB or 159 $state->fatal("couldn't open pipe to mklocatedb: #1", $!); 160 } 161} 162 163sub sync_error 164{ 165 my ($state, $e, $set) = @_; 166 if ($set =~ m/etc/) { 167 $state->errsay("Couldn't find #1 from set #2:\n\tDid you run sysmerge recently ?", $e, $set); 168 } else { 169 $state->errsay("Couldn't find #1 from set #2:\n\tsrc and installation out of synch ?", $e, $set); 170 $state->{fatals}++; 171 } 172} 173 174sub do_source 175{ 176 my ($state, $src, $tag, @sets) = @_; 177 findos() if !defined $arch; 178 my $dir = "$src/distrib/sets/lists"; 179 for my $set (@sets) { 180 my $tag = tag($state, $tag, $set, $rev); 181 my $output = 0; 182 for my $f ("$dir/$set/mi", "$dir/$set/md.$arch") { 183 open my $l, '<', $f or next; 184 while (my $e = <$l>) { 185 chomp $e; 186 $e =~ s/^\.//; 187 if ($state->{check} && !-e $e) { 188 sync_error($state, $e, $set); 189 } 190 print {$state->{out}} "$tag:$e\n"; 191 $output = 1; 192 } 193 } 194 if (!$output) { 195 $state->fatal("Couldn't find set #1", $set); 196 } 197 } 198 if ($state->{fatals}) { 199 $state->fatal("Files not found, can't continue"); 200 } 201} 202 203sub do_release 204{ 205 my $state = shift; 206 207 require OpenBSD::Ustar; 208 209 opendir(my $dir, $state->{releasedir}) or return; 210 while (my $e = readdir $dir) { 211 if ($e =~ m/^(\w+\d\d)\.tgz$/o) { 212 my $set = $1; 213 open my $arc, '-|', OpenBSD::Paths->gzip, '-c', '-d', 214 "--", $state->{releasedir}."/".$e or 215 $state->fatal("couldn't open pipe from gzip: #1", $!); 216 217 my $u = OpenBSD::Ustar->new($arc, $state, '/'); 218 while (my $f = $u->next) { 219 my $name = $f->{name}; 220 $name =~ s/^\.//o; 221 print {$state->{out}} "$set:$name\n"; 222 } 223 close $arc; 224 } 225 } 226 closedir($dir); 227} 228 229sub print_out 230{ 231 my ($plist, $state) = @_; 232 233 $plist->set_header($state); 234 $plist->print_name($state); 235} 236 237sub do_portsdir 238{ 239 my $state = shift; 240 my $make = $ENV{MAKE} || 'make'; 241 my $target = defined $ENV{SUBDIRLIST} ? 242 'print-plist' : 'print-plist-all'; 243 delete $ENV{FLAVOR}; 244 delete $ENV{SUBPACKAGE}; 245 open my $in, "cd $state->{portsdir} && $make $target |"; 246 my $done = 0; 247 while (!$done) { 248 my $plist = OpenBSD::PackingList->read($in, 249 sub { 250 my ($fh, $cont) = @_; 251 while (<$fh>) { 252 return if m/^\=\=\=\> /o; 253 &$cont($_); 254 } 255 $done = 1; 256 }); 257 if (defined $plist && defined $plist->pkgname) { 258 print_out($plist, $state); 259 } 260 } 261 close($in); 262} 263 264sub do_pkgdir 265{ 266 my $state = shift; 267 268 require File::Find; 269 no warnings qw(once); 270 $state->fatal("Bad argument: #1 is not a directory", $state->{pkgdir}) 271 unless -d $state->{pkgdir}; 272 File::Find::find( 273 sub { 274 return unless -f $_; 275 my $plist = $state->repo->grabPlist($File::Find::name); 276 return unless defined $plist; 277 print_out($plist, $state); 278 }, $state->{pkgdir}); 279} 280 281sub copy_stdin 282{ 283 my $state = shift; 284 while (<STDIN>) { 285 # if we find something that looks like a pkgpath we've done 286 # assume we were updating it 287 if (m,([^:]*/[^:]*)\:,) { 288 next if defined $state->{done}{$1}; 289 } 290 print {$state->{out}} $_; 291 } 292} 293 294my $state = OpenBSD::Pkgmklocatedb::State->new("pkg_mklocatedb"); 295$state->handle_options; 296 297open_output($state); 298 299if ($state->{srcdir}) { 300 do_source($state, $state->{srcdir}, 'src', 301 qw(base comp etc game)); 302} 303if ($state->{xdir}) { 304 do_source($state, $state->{xdir}, 'xenocara', 305 qw(xbase xetc xfont xserv xshare)); 306} 307if ($state->{releasedir}) { 308 do_release($state); 309} 310 311if ($state->{portsdir}) { 312 do_portsdir($state); 313} elsif ($state->{pkgdir}) { 314 do_pkgdir($state); 315} elsif (@ARGV == 0) { 316 if (!$state->{update}) { 317 $state->progress->for_list("Scanning installation", 318 [installed_packages()], sub { 319 my $pkgname = shift; 320 my $plist = 321 OpenBSD::PackingList->from_installation($pkgname); 322 return unless defined $plist; 323 print_out($plist, $state); 324 }); 325 } 326} else { 327 $state->progress->for_list("Scanning packages", \@ARGV, 328 sub { 329 my $pkgname = shift; 330 my $plist = $state->repo->grabPlist($pkgname); 331 next unless $plist; 332 print_out($plist, $state); 333 }); 334} 335if ($state->{update}) { 336 copy_stdin($state); 337} 338