1d7240732Sespie# ex:ts=8 sw=4: 2*1bd70b3dSespie# $OpenBSD: BaseState.pm,v 1.4 2023/08/30 12:04:09 espie Exp $ 3d7240732Sespie# 4d7240732Sespie# Copyright (c) 2007-2022 Marc Espie <espie@openbsd.org> 5d7240732Sespie# 6d7240732Sespie# Permission to use, copy, modify, and distribute this software for any 7d7240732Sespie# purpose with or without fee is hereby granted, provided that the above 8d7240732Sespie# copyright notice and this permission notice appear in all copies. 9d7240732Sespie# 10d7240732Sespie# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11d7240732Sespie# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12d7240732Sespie# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13d7240732Sespie# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14d7240732Sespie# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15d7240732Sespie# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16d7240732Sespie# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17d7240732Sespie# 18d7240732Sespie 19039cbdaaSespieuse v5.36; 20d7240732Sespie 21d7240732Sespiepackage OpenBSD::BaseState; 22d7240732Sespieuse Carp; 23d7240732Sespie 24039cbdaaSespiesub can_output($) 25d7240732Sespie{ 26d7240732Sespie 1; 27d7240732Sespie} 28039cbdaaSespiesub sync_display($) 29d7240732Sespie{ 30d7240732Sespie} 31d7240732Sespie 32d7240732Sespiemy $forbidden = qr{[^[:print:]\s]}; 33d7240732Sespie 34039cbdaaSespiesub safe($self, $string) 35d7240732Sespie{ 36d7240732Sespie $string =~ s/$forbidden/?/g; 37d7240732Sespie return $string; 38d7240732Sespie} 39d7240732Sespie 40039cbdaaSespiesub f($self, @p) 41d7240732Sespie{ 42039cbdaaSespie if (@p == 0) { 43d7240732Sespie return undef; 44d7240732Sespie } 45039cbdaaSespie my ($fmt, @l) = @p; 46d7240732Sespie 47d7240732Sespie # is there anything to format, actually ? 48d7240732Sespie if ($fmt =~ m/\#\d/) { 49d7240732Sespie # encode any unknown chars as ? 50d7240732Sespie for (@l) { 51d7240732Sespie s/$forbidden/?/g if defined; 52d7240732Sespie } 53d7240732Sespie # make it so that #0 is # 54d7240732Sespie unshift(@l, '#'); 55d7240732Sespie $fmt =~ s,\#(\d+),($l[$1] // "<Undefined #$1>"),ge; 56d7240732Sespie } 57d7240732Sespie return $fmt; 58d7240732Sespie} 59d7240732Sespie 60039cbdaaSespiesub _fatal($self, @p) 61d7240732Sespie{ 62d7240732Sespie # implementation note: to print "fatal errors" elsewhere, 63d7240732Sespie # the way is to eval { croak @_}; and decide what to do with $@. 64d7240732Sespie delete $SIG{__DIE__}; 65d7240732Sespie $self->sync_display; 66039cbdaaSespie croak @p, "\n"; 67d7240732Sespie} 68d7240732Sespie 69039cbdaaSespiesub fatal($self, @p) 70d7240732Sespie{ 71039cbdaaSespie $self->_fatal($self->f(@p)); 72d7240732Sespie} 73d7240732Sespie 74039cbdaaSespiesub _fhprint($self, $fh, @p) 75d7240732Sespie{ 76d7240732Sespie $self->sync_display; 77039cbdaaSespie print $fh @p; 78d7240732Sespie} 79039cbdaaSespiesub _print($self, @p) 80d7240732Sespie{ 81039cbdaaSespie $self->_fhprint(\*STDOUT, @p) if $self->can_output; 82d7240732Sespie} 83d7240732Sespie 84039cbdaaSespiesub _errprint($self, @p) 85d7240732Sespie{ 86039cbdaaSespie $self->_fhprint(\*STDERR, @p); 87d7240732Sespie} 88d7240732Sespie 89039cbdaaSespiesub fhprint($self, $fh, @p) 90d7240732Sespie{ 91039cbdaaSespie $self->_fhprint($fh, $self->f(@p)); 92d7240732Sespie} 93d7240732Sespie 94039cbdaaSespiesub fhsay($self, $fh, @p) 95d7240732Sespie{ 96039cbdaaSespie if (@p == 0) { 97d7240732Sespie $self->_fhprint($fh, "\n"); 98d7240732Sespie } else { 99039cbdaaSespie $self->_fhprint($fh, $self->f(@p), "\n"); 100d7240732Sespie } 101d7240732Sespie} 102d7240732Sespie 103039cbdaaSespiesub print($self, @p) 104d7240732Sespie{ 105039cbdaaSespie $self->fhprint(\*STDOUT, @p) if $self->can_output; 106d7240732Sespie} 107d7240732Sespie 108039cbdaaSespiesub say($self, @p) 109d7240732Sespie{ 110039cbdaaSespie $self->fhsay(\*STDOUT, @p) if $self->can_output; 111d7240732Sespie} 112d7240732Sespie 113039cbdaaSespiesub errprint($self, @p) 114d7240732Sespie{ 115039cbdaaSespie $self->fhprint(\*STDERR, @p); 116d7240732Sespie} 117d7240732Sespie 118039cbdaaSespiesub errsay($self, @p) 119d7240732Sespie{ 120039cbdaaSespie $self->fhsay(\*STDERR, @p); 121d7240732Sespie} 122d7240732Sespie 123d7240732Sespiemy @signal_name = (); 124039cbdaaSespiesub fillup_names($) 125d7240732Sespie{ 126d7240732Sespie { 127d7240732Sespie # XXX force autoload 128d7240732Sespie package verylocal; 129d7240732Sespie 130d7240732Sespie require POSIX; 131d7240732Sespie POSIX->import(qw(signal_h)); 132d7240732Sespie } 133d7240732Sespie 134d7240732Sespie for my $sym (keys %POSIX::) { 135d7240732Sespie next unless $sym =~ /^SIG([A-Z].*)/; 136d7240732Sespie my $value = eval "&POSIX::$sym()"; 137d7240732Sespie # skip over POSIX stuff we don't have like SIGRT or SIGPOLL 138d7240732Sespie next unless defined $value; 139d7240732Sespie $signal_name[$value] = $1; 140d7240732Sespie } 141d7240732Sespie # extra BSD signals 142d7240732Sespie $signal_name[5] = 'TRAP'; 143d7240732Sespie $signal_name[7] = 'IOT'; 144d7240732Sespie $signal_name[10] = 'BUS'; 145d7240732Sespie $signal_name[12] = 'SYS'; 146d7240732Sespie $signal_name[16] = 'URG'; 147d7240732Sespie $signal_name[23] = 'IO'; 148d7240732Sespie $signal_name[24] = 'XCPU'; 149d7240732Sespie $signal_name[25] = 'XFSZ'; 150d7240732Sespie $signal_name[26] = 'VTALRM'; 151d7240732Sespie $signal_name[27] = 'PROF'; 152d7240732Sespie $signal_name[28] = 'WINCH'; 153d7240732Sespie $signal_name[29] = 'INFO'; 154d7240732Sespie} 155d7240732Sespie 156039cbdaaSespiesub find_signal($self, $number) 157d7240732Sespie{ 158d7240732Sespie if (@signal_name == 0) { 159d7240732Sespie $self->fillup_names; 160d7240732Sespie } 161d7240732Sespie 162d7240732Sespie return $signal_name[$number] || $number; 163d7240732Sespie} 164d7240732Sespie 165039cbdaaSespiesub child_error($self, $error = $?) 166d7240732Sespie{ 167d7240732Sespie my $extra = ""; 168d7240732Sespie 169d7240732Sespie if ($error & 128) { 170d7240732Sespie $extra = $self->f(" (core dumped)"); 171d7240732Sespie } 172d7240732Sespie if ($error & 127) { 173d7240732Sespie return $self->f("killed by signal #1#2", 174*1bd70b3dSespie $self->find_signal($error & 127), $extra); 175d7240732Sespie } else { 176d7240732Sespie return $self->f("exit(#1)#2", ($error >> 8), $extra); 177d7240732Sespie } 178d7240732Sespie} 179d7240732Sespie 180039cbdaaSespiesub _system($self, @p) 181d7240732Sespie{ 182d7240732Sespie $self->sync_display; 183d7240732Sespie my ($todo, $todo2); 184039cbdaaSespie if (ref $p[0] eq 'CODE') { 185039cbdaaSespie $todo = shift @p; 186d7240732Sespie } else { 187039cbdaaSespie $todo = sub() {}; 188d7240732Sespie } 189039cbdaaSespie if (ref $p[0] eq 'CODE') { 190039cbdaaSespie $todo2 = shift @p; 191d7240732Sespie } else { 192039cbdaaSespie $todo2 = sub() {}; 193d7240732Sespie } 194d7240732Sespie my $r = fork; 195d7240732Sespie if (!defined $r) { 196d7240732Sespie return 1; 197d7240732Sespie } elsif ($r == 0) { 198d7240732Sespie $DB::inhibit_exit = 0; 1998a55ea89Sespie &$todo(); 200039cbdaaSespie exec {$p[0]} @p or 201d7240732Sespie exit 1; 202d7240732Sespie } else { 2038a55ea89Sespie &$todo2(); 204d7240732Sespie waitpid($r, 0); 205d7240732Sespie return $?; 206d7240732Sespie } 207d7240732Sespie} 208d7240732Sespie 209039cbdaaSespiesub system($self, @p) 210d7240732Sespie{ 211039cbdaaSespie my $r = $self->_system(@p); 212d7240732Sespie if ($r != 0) { 213039cbdaaSespie if (ref $p[0] eq 'CODE') { 214039cbdaaSespie shift @p; 215d7240732Sespie } 216039cbdaaSespie if (ref $p[0] eq 'CODE') { 217039cbdaaSespie shift @p; 218d7240732Sespie } 219d7240732Sespie $self->errsay("system(#1) failed: #2", 220039cbdaaSespie join(", ", @p), $self->child_error); 221d7240732Sespie } 222d7240732Sespie return $r; 223d7240732Sespie} 224d7240732Sespie 225039cbdaaSespiesub verbose_system($self, @p) 226d7240732Sespie{ 227d7240732Sespie if (ref $p[0]) { 228d7240732Sespie shift @p; 229d7240732Sespie } 230d7240732Sespie if (ref $p[0]) { 231d7240732Sespie shift @p; 232d7240732Sespie } 233d7240732Sespie 234d7240732Sespie $self->print("Running #1", join(' ', @p)); 235039cbdaaSespie my $r = $self->_system(@p); 236d7240732Sespie if ($r != 0) { 237d7240732Sespie $self->say("... failed: #1", $self->child_error); 238d7240732Sespie } else { 239d7240732Sespie $self->say; 240d7240732Sespie } 241d7240732Sespie} 242d7240732Sespie 243039cbdaaSespiesub copy_file($self, @p) 244d7240732Sespie{ 245d7240732Sespie require File::Copy; 246d7240732Sespie 247039cbdaaSespie my $r = File::Copy::copy(@p); 248d7240732Sespie if (!$r) { 249039cbdaaSespie $self->say("copy(#1) failed: #2", join(',', @p), $!); 250d7240732Sespie } 251d7240732Sespie return $r; 252d7240732Sespie} 253d7240732Sespie 254039cbdaaSespiesub unlink($self, $verbose, @p) 255d7240732Sespie{ 256039cbdaaSespie my $r = unlink @p; 257039cbdaaSespie if ($r != @p) { 258d7240732Sespie $self->say("rm #1 failed: removed only #2 targets, #3", 259039cbdaaSespie join(' ', @p), $r, $!); 260d7240732Sespie } elsif ($verbose) { 261039cbdaaSespie $self->say("rm #1", join(' ', @p)); 262d7240732Sespie } 263d7240732Sespie return $r; 264d7240732Sespie} 265d7240732Sespie 266039cbdaaSespiesub copy($self, @p) 267d7240732Sespie{ 268d7240732Sespie require File::Copy; 269d7240732Sespie 270039cbdaaSespie my $r = File::Copy::copy(@p); 271d7240732Sespie if (!$r) { 272039cbdaaSespie $self->say("copy(#1) failed: #2", join(',', @p), $!); 273d7240732Sespie } 274d7240732Sespie return $r; 275d7240732Sespie} 276d7240732Sespie 277d7240732Sespie1; 278