1# ex:ts=8 sw=4: 2# $OpenBSD: State.pm,v 1.74 2023/06/13 09:07:17 espie Exp $ 3# 4# Copyright (c) 2007-2014 Marc Espie <espie@openbsd.org> 5# 6# Permission to use, copy, modify, and distribute this software for any 7# purpose with or without fee is hereby granted, provided that the above 8# copyright notice and this permission notice appear in all copies. 9# 10# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17# 18 19use v5.36; 20 21package OpenBSD::PackageRepositoryFactory; 22sub new($class, $state) 23{ 24 return bless {state => $state}, $class; 25} 26 27sub locator($self) 28{ 29 return $self->{state}->locator; 30} 31 32sub installed($self, $all = 0) 33{ 34 require OpenBSD::PackageRepository::Installed; 35 36 return OpenBSD::PackageRepository::Installed->new($all, $self->{state}); 37} 38 39sub path_parse($self, $pkgname) 40{ 41 return $self->locator->path_parse($pkgname, $self->{state}); 42} 43 44sub find($self, $pkg) 45{ 46 return $self->locator->find($pkg, $self->{state}); 47} 48 49sub reinitialize($) 50{ 51} 52 53sub match_locations($self, @p) 54{ 55 return $self->locator->match_locations(@p, $self->{state}); 56} 57 58sub grabPlist($self, $url, $code) 59{ 60 return $self->locator->grabPlist($url, $code, $self->{state}); 61} 62 63sub path($self) 64{ 65 require OpenBSD::PackageRepositoryList; 66 67 return OpenBSD::PackageRepositoryList->new($self->{state}); 68} 69 70# common routines to everything state. 71# in particular, provides "singleton-like" access to UI. 72package OpenBSD::State; 73use OpenBSD::Subst; 74use OpenBSD::Error; 75use parent qw(OpenBSD::BaseState Exporter); 76our @EXPORT = (); 77 78sub locator($) 79{ 80 require OpenBSD::PackageLocator; 81 return "OpenBSD::PackageLocator"; 82} 83 84sub cache_directory($) 85{ 86 return undef; 87} 88 89sub new($class, $cmd = undef, @p) 90{ 91 if (!defined $cmd) { 92 $cmd = $0; 93 $cmd =~ s,.*/,,; 94 } 95 my $o = bless {cmd => $cmd}, $class; 96 $o->init(@p); 97 return $o; 98} 99 100sub init($self) 101{ 102 $self->{subst} = OpenBSD::Subst->new; 103 $self->{repo} = OpenBSD::PackageRepositoryFactory->new($self); 104 $self->{export_level} = 1; 105 $SIG{'CONT'} = sub { 106 $self->handle_continue; 107 } 108} 109 110sub repo($self) 111{ 112 return $self->{repo}; 113} 114 115sub handle_continue($self) 116{ 117 $self->find_window_size; 118 # invalidate cache so this runs again after continue 119 delete $self->{can_output}; 120} 121 122OpenBSD::Auto::cache(can_output, 123 sub($) { 124 require POSIX; 125 126 return 1 if !-t STDOUT; 127 # XXX uses POSIX semantics so fd, we can hardcode stdout ;) 128 my $s = POSIX::tcgetpgrp(1); 129 # note that STDOUT may be redirected 130 # (tcgetpgrp() returns 0 for pipes and -1 for files) 131 # (we shouldn't be there because of the tty test) 132 return $s <= 0 || getpgrp() == $s; 133 }); 134 135OpenBSD::Auto::cache(installpath, 136 sub($self) { 137 return undef if $self->defines('NOINSTALLPATH'); 138 require OpenBSD::Paths; 139 open(my $fh, '<', OpenBSD::Paths->installurl) or return undef; 140 while (<$fh>) { 141 chomp; 142 next if m/^\s*\#/; 143 next if m/^\s*$/; 144 return "$_/%c/packages/%a/"; 145 } 146 }); 147 148OpenBSD::Auto::cache(shlibs, 149 sub($self) { 150 require OpenBSD::SharedLibs; 151 return $self->{shlibs} //= OpenBSD::SharedLibs->new($self); 152 }); 153 154sub usage_is($self, @usage) 155{ 156 $self->{usage} = \@usage; 157} 158 159sub verbose($self) 160{ 161 return $self->{v}; 162} 163 164sub opt($self, $k) 165{ 166 return $self->{opt}{$k}; 167} 168 169sub usage($self, @p) 170{ 171 my $code = 0; 172 if (@p) { 173 print STDERR "$self->{cmd}: ", $self->f(@p), "\n"; 174 $code = 1; 175 } 176 print STDERR "Usage: $self->{cmd} ", shift(@{$self->{usage}}), "\n"; 177 for my $l (@{$self->{usage}}) { 178 print STDERR " $l\n"; 179 } 180 exit($code); 181} 182 183sub do_options($state, $sub) 184{ 185 # this could be nicer... 186 187 try { 188 &$sub(); 189 } catch { 190 $state->usage("#1", $_); 191 }; 192} 193 194sub handle_options($state, $opt_string, @usage) 195{ 196 require OpenBSD::Getopt; 197 198 $state->{opt}{v} = 0 unless $opt_string =~ m/v/; 199 $state->{opt}{h} = 200 sub() { 201 $state->usage; 202 } unless $opt_string =~ m/h/; 203 $state->{opt}{D} = 204 sub($opt) { 205 $state->{subst}->parse_option($opt); 206 } unless $opt_string =~ m/D/; 207 $state->usage_is(@usage); 208 $state->do_options(sub() { 209 OpenBSD::Getopt::getopts($opt_string.'hvD:', $state->{opt}); 210 }); 211 $state->{v} = $state->opt('v'); 212 213 if ($state->defines('unsigned')) { 214 $state->{signature_style} //= 'unsigned'; 215 } elsif ($state->defines('oldsign')) { 216 $state->fatal('old style signature no longer supported'); 217 } else { 218 $state->{signature_style} //= 'new'; 219 } 220 221 return if $state->{no_exports}; 222 # TODO make sure nothing uses this 223 no strict "refs"; 224 no strict "vars"; 225 for my $k (keys %{$state->{opt}}) { 226 ${"opt_$k"} = $state->opt($k); 227 push(@EXPORT, "\$opt_$k"); 228 } 229 local $Exporter::ExportLevel = $state->{export_level}; 230 OpenBSD::State->import; 231} 232 233sub defines($self, $k) 234{ 235 return $self->{subst}->value($k); 236} 237 238sub width($self) 239{ 240 if (!defined $self->{width}) { 241 $self->find_window_size; 242 } 243 return $self->{width}; 244} 245 246sub height($self) 247{ 248 if (!defined $self->{height}) { 249 $self->find_window_size; 250 } 251 return $self->{height}; 252} 253 254sub find_window_size($self) 255{ 256 require Term::ReadKey; 257 my @l = Term::ReadKey::GetTermSizeGWINSZ(\*STDOUT); 258 # default to sane values 259 $self->{width} = 80; 260 $self->{height} = 24; 261 if (@l == 4) { 262 # only use what we got if sane 263 $self->{width} = $l[0] if $l[0] > 0; 264 $self->{height} = $l[1] if $l[1] > 0; 265 $SIG{'WINCH'} = sub { 266 $self->find_window_size; 267 }; 268 } 269} 270 271OpenBSD::Auto::cache(signer_list, 272 sub($self) { 273 if ($self->defines('SIGNER')) { 274 return [split /,/, $self->{subst}->value('SIGNER')]; 275 } else { 276 if ($self->defines('FW_UPDATE')) { 277 return [qr{^.*fw$}]; 278 } else { 279 return [qr{^.*pkg$}]; 280 } 281 } 282 }); 283 2841; 285