xref: /openbsd-src/usr.sbin/pkg_add/OpenBSD/BaseState.pm (revision 1bd70b3df4bd09cab0a6024bf10d8449eac33cab)
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