1# ex:ts=8 sw=4: 2# $OpenBSD: Error.pm,v 1.30 2010/12/24 09:04:14 espie Exp $ 3# 4# Copyright (c) 2004-2010 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 17use strict; 18use warnings; 19 20package OpenBSD::Auto; 21sub cache(*&) 22{ 23 my ($sym, $code) = @_; 24 my $callpkg = caller; 25 my $actual = sub { 26 my $self = shift; 27 return $self->{$sym} //= &$code($self); 28 }; 29 no strict 'refs'; 30 *{$callpkg."::$sym"} = $actual; 31} 32 33package OpenBSD::Handler; 34 35my $list = []; 36 37sub register 38{ 39 my ($class, $code) = @_; 40 push(@$list, $code); 41} 42 43my $handler = sub { 44 my $sig = shift; 45 for my $c (@$list) { 46 &$c($sig); 47 } 48 $SIG{$sig} = 'DEFAULT'; 49 kill $sig, $$; 50}; 51 52sub reset 53{ 54 $SIG{'INT'} = $handler; 55 $SIG{'QUIT'} = $handler; 56 $SIG{'HUP'} = $handler; 57 $SIG{'KILL'} = $handler; 58 $SIG{'TERM'} = $handler; 59} 60 61__PACKAGE__->reset; 62 63package OpenBSD::Error; 64require Exporter; 65our @ISA=qw(Exporter); 66our @EXPORT=qw(Copy Unlink try throw catch catchall rethrow); 67 68our ($FileName, $Line, $FullMessage); 69 70my @signal_name = (); 71 72use Carp; 73 74sub fillup_names 75{ 76 { 77 # XXX force autoload 78 package verylocal; 79 80 require POSIX; 81 POSIX->import(qw(signal_h)); 82 } 83 84 for my $sym (keys %POSIX::) { 85 next unless $sym =~ /^SIG([A-Z].*)/; 86 $signal_name[eval "&POSIX::$sym()"] = $1; 87 } 88 # extra BSD signals 89 $signal_name[5] = 'TRAP'; 90 $signal_name[7] = 'IOT'; 91 $signal_name[10] = 'BUS'; 92 $signal_name[12] = 'SYS'; 93 $signal_name[16] = 'URG'; 94 $signal_name[23] = 'IO'; 95 $signal_name[24] = 'XCPU'; 96 $signal_name[25] = 'XFSZ'; 97 $signal_name[26] = 'VTALRM'; 98 $signal_name[27] = 'PROF'; 99 $signal_name[28] = 'WINCH'; 100 $signal_name[29] = 'INFO'; 101} 102 103sub find_signal 104{ 105 my $number = shift; 106 107 if (@signal_name == 0) { 108 fillup_names(); 109 } 110 111 return $signal_name[$number] || $number; 112} 113 114sub child_error 115{ 116 my $error = $?; 117 118 my $extra = ""; 119 120 if ($error & 128) { 121 $extra = " (core dumped)"; 122 } 123 if ($error & 127) { 124 return "killed by signal ". find_signal($error & 127).$extra; 125 } else { 126 return "exit(". ($error >> 8) . ")$extra"; 127 } 128} 129 130sub Copy 131{ 132 require File::Copy; 133 134 my $r = File::Copy::copy(@_); 135 if (!$r) { 136 print "copy(", join(',', @_),") failed: $!\n"; 137 } 138 return $r; 139} 140 141sub Unlink 142{ 143 my $verbose = shift; 144 my $r = unlink @_; 145 if ($r != @_) { 146 print "rm @_ failed: removed only $r targets, $!\n"; 147 } elsif ($verbose) { 148 print "rm @_\n"; 149 } 150 return $r; 151} 152 153sub dienow 154{ 155 my ($error, $handler) = @_; 156 if ($error) { 157 if ($error =~ m/^(.*?)(?:\s+at\s+(.*)\s+line\s+(\d+)\.?)?$/o) { 158 local $_ = $1; 159 $FileName = $2; 160 $Line = $3; 161 $FullMessage = $error; 162 163 $handler->exec($error, '', $1, $2, $3); 164 } else { 165 die "Fatal error: can't parse $error"; 166 } 167 } 168} 169 170sub try(&@) 171{ 172 my ($try, $catch) = @_; 173 eval { &$try }; 174 dienow($@, $catch); 175} 176 177sub throw 178{ 179 croak @_; 180 181} 182 183sub rethrow 184{ 185 my $e = shift; 186 die $e if $e; 187} 188 189sub catch(&) 190{ 191 bless $_[0], "OpenBSD::Error::catch"; 192} 193 194sub catchall(&) 195{ 196 bless $_[0], "OpenBSD::Error::catchall"; 197} 198 199package OpenBSD::Error::catch; 200sub exec 201{ 202 my ($self, $full, $e) = @_; 203 if ($e) { 204 &$self; 205 } else { 206 die $full; 207 } 208} 209 210package OpenBSD::Error::catchall; 211sub exec 212{ 213 my ($self, $full, $e) = @_; 214 &$self; 215} 216 2171; 218