summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorMarc Espie <espie@cvs.openbsd.org>2010-06-05 12:30:37 +0000
committerMarc Espie <espie@cvs.openbsd.org>2010-06-05 12:30:37 +0000
commit1b3f92afa619cfd154471fde302432bf183ed20d (patch)
tree9dbc87a2efb5ea3ded85a0baa9adedf066d88d28 /usr.sbin
parent4d97f7c4940c5939d1a06c83c874d47551762adf (diff)
new command pkg_fsck, very incomplete for now. Runs only very basic checks.
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/pkg_add/Makefile9
-rw-r--r--usr.sbin/pkg_add/OpenBSD/PkgFsck.pm318
-rw-r--r--usr.sbin/pkg_add/pkg5
-rw-r--r--usr.sbin/pkg_add/pkg.12
-rw-r--r--usr.sbin/pkg_add/pkg_fsck.890
5 files changed, 419 insertions, 5 deletions
diff --git a/usr.sbin/pkg_add/Makefile b/usr.sbin/pkg_add/Makefile
index 06e31691b53..0714ca11abe 100644
--- a/usr.sbin/pkg_add/Makefile
+++ b/usr.sbin/pkg_add/Makefile
@@ -1,11 +1,12 @@
-# $OpenBSD: Makefile,v 1.62 2010/06/04 13:19:39 espie Exp $
+# $OpenBSD: Makefile,v 1.63 2010/06/05 12:30:36 espie Exp $
.include <bsd.own.mk>
MAN1=pkg_add.1 pkg_info.1 pkg_create.1 pkg_delete.1 pkg_merge.1 \
pkg.1 pkg_mklocatedb.1
MAN5=package.5
-MAN=${MAN1} ${MAN5}
+MAN8=pkg_fsck.8
+MAN=${MAN1} ${MAN5} ${MAN8}
NOPROG=
POD2MAN=/usr/bin/pod2man
@@ -45,6 +46,7 @@ PACKAGES= \
OpenBSD/PkgConfig.pm \
OpenBSD/PkgCreate.pm \
OpenBSD/PkgDelete.pm \
+ OpenBSD/PkgFsck.pm \
OpenBSD/PkgInfo.pm \
OpenBSD/PkgSpec.pm \
OpenBSD/ProgressMeter/Term.pm \
@@ -77,6 +79,7 @@ SCRIPTS_LNK = \
pkg pkg_add \
pkg pkg_create \
pkg pkg_delete \
+ pkg pkg_fsck \
pkg pkg_info
LIBBASE=/usr/libdata/perl5
@@ -117,9 +120,11 @@ $p.3p: pod/$p.pod
.ifndef NOMAN
MANALL+=${MAN1:S/.1$/.cat1/}
MANALL+=${MAN5:S/.5$/.cat5/}
+MANALL+=${MAN8:S/.8$/.cat8/}
. ifdef MANPS
PSALL+= ${MAN1:S/.1$/.ps1/}
PSALL+= ${MAN5:S/.5$/.ps5/}
+PSALL+= ${MAN8:S/.8$/.ps8/}
. endif
.endif
diff --git a/usr.sbin/pkg_add/OpenBSD/PkgFsck.pm b/usr.sbin/pkg_add/OpenBSD/PkgFsck.pm
new file mode 100644
index 00000000000..93d8f0eca89
--- /dev/null
+++ b/usr.sbin/pkg_add/OpenBSD/PkgFsck.pm
@@ -0,0 +1,318 @@
+#! /usr/bin/perl
+
+# ex:ts=8 sw=4:
+# $OpenBSD: PkgFsck.pm,v 1.1 2010/06/05 12:30:36 espie Exp $
+#
+# Copyright (c) 2003-2010 Marc Espie <espie@openbsd.org>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+use strict;
+use warnings;
+
+use OpenBSD::AddCreateDelete;
+
+package OpenBSD::PackingElement;
+sub thorough_check
+{
+ my ($self, $state) = @_;
+ $self->basic_check($state);
+}
+
+sub basic_check
+{
+}
+
+package OpenBSD::PackingElement::FileBase;
+use File::Basename;
+
+sub basic_check
+{
+ my ($self, $state) = @_;
+
+ my $name = $self->fullname;
+ $state->{known}{dirname($name)}{basename($name)} = 1;
+ if (!-e $name) {
+ $state->log("$name should exist\n");
+ }
+ if ($self->{symlink}) {
+ if (!-l $name) {
+ $state->log("$name is not a symlink\n");
+ }
+ return;
+ }
+ if (!-f _) {
+ $state->log("$name is not a file\n");
+ }
+}
+
+sub thorough_check
+{
+ my ($self, $state) = @_;
+ $self->basic_check($state);
+ return if $self->{link} or $self->{symlink} or $self->{nochecksum};
+ if (!-r $self->fullname) {
+ $state->log("can't read ", $self->fullname, "\n");
+ return;
+ }
+ my $d = $self->compute_digest($self->fullname);
+ if (!$d->equals($self->{d})) {
+ $state->log("checksum for ", $self->fullname, " does not match", "\n");
+ }
+}
+
+package OpenBSD::PackingElement::SpecialFile;
+sub basic_check
+{
+ &OpenBSD::PackingElement::FileBase::basic_check;
+}
+
+sub thorough_check
+{
+ &OpenBSD::PackingElement::FileBase::basic_check;
+}
+
+package OpenBSD::PackingElement::DirlikeObject;
+sub basic_check
+{
+ my ($self, $state) = @_;
+ my $name = $self->fullname;
+ $state->{known}{$name} //= {};
+ if (!-e $name) {
+ $state->log("$name should exist\n");
+ }
+ if (!-d _) {
+ $state->log("$name is not a directory\n");
+ }
+}
+
+package OpenBSD::PackingElement::Mandir;
+sub basic_check
+{
+ my ($self, $state) = @_;
+ $self->SUPER::basic_check($state);
+ $state->{known}{$self->fullname}{'whatis.db'} = 1;
+}
+
+package OpenBSD::PackingElement::Fontdir;
+sub basic_check
+{
+ my ($self, $state) = @_;
+ $self->SUPER::basic_check($state);
+ for my $i (qw(fonts.alias fonts.scale fonts.dir)) {
+ $state->{known}{$self->fullname}{$i} = 1;
+ }
+}
+
+package OpenBSD::PackingElement::Infodir;
+sub basic_check
+{
+ my ($self, $state) = @_;
+ $self->SUPER::basic_check($state);
+ $state->{known}{$self->fullname}{'dir'} = 1;
+}
+
+package OpenBSD::Log;
+use OpenBSD::Error;
+our @ISA = qw(OpenBSD::Error);
+
+sub set_context
+{
+ &OpenBSD::Error::set_pkgname;
+}
+
+sub dump
+{
+ &OpenBSD::Error::delayed_output;
+}
+
+package OpenBSD::PkgFsck::State;
+our @ISA = qw(OpenBSD::AddCreateDelete::State);
+
+sub init
+{
+ my $self = shift;
+ $self->{l} = OpenBSD::Log->new;
+ $self->SUPER::init;
+}
+
+sub log
+{
+ my $self = shift;
+ if (@_ == 0) {
+ return $self->{l};
+ } else {
+ $self->{l}->print(@_);
+ }
+}
+
+package OpenBSD::PkgFsck;
+our @ISA = qw(OpenBSD::AddCreateDelete);
+
+use OpenBSD::PackageInfo;
+use OpenBSD::PackingList;
+use File::Find;
+use OpenBSD::Paths;
+use OpenBSD::Mtree;
+
+sub remove
+{
+ my ($self, $state, $name) = @_;
+ $state->{removed}{$name} = 1;
+ my $dir = installed_info($name);
+ for my $i (@OpenBSD::PackageInfo::info) {
+ if (-e $dir.$i) {
+ if ($state->verbose) {
+ $state->say("unlink($dir.$i)");
+ }
+ unless ($state->{not}) {
+ unlink($dir.$i) or
+ $state->errsay("$name: Couldn't delete $dir.$i: $!");
+ }
+ }
+ }
+ if (-f $dir) {
+ if ($state->verbose) {
+ $state->say("unlink($dir)");
+ }
+ unless ($state->{not}) {
+ unlink($dir) or
+ $state->errsay("$name: Couldn't delete $dir: $!");
+ }
+ } elsif (-d $dir) {
+ if ($state->verbose) {
+ $state->say("rmdir($dir)");
+ }
+ unless ($state->{not}) {
+ rmdir($dir) or
+ $state->errsay("$name: Couldn't delete $dir: $!");
+ }
+ }
+}
+
+sub may_remove
+{
+ my ($self, $state, $name) = @_;
+ if ($state->{force}) {
+ $self->remove($state, $name);
+ } elsif ($state->{interactive}) {
+ require OpenBSD::Interactive;
+ if (OpenBSD::Interactive("Remove wrong package $name ?")) {
+ $self->remove($state, $name);
+ }
+ }
+}
+
+sub sanity_check
+{
+ my ($self, $state, $l) = @_;
+ $state->progress->set_header("Packing-list sanity");
+ my $i = 0;
+ for my $name (@$l) {
+ my $info = installed_info($name);
+ $state->progress->show(++$i, scalar @$l);
+ if (-f $info) {
+ $state->errsay("$name: $info should be a directory");
+ if ($info =~ m/\.core$/) {
+ $state->errsay("looks like a core dump, ",
+ "removing");
+ $self->remove($state, $name);
+ } else {
+ $self->may_remove($state, $name);
+ }
+ next;
+ }
+ my $contents = $info.OpenBSD::PackageInfo::CONTENTS;
+ unless (-f $contents) {
+ $state->errsay("$name: missing $contents");
+ $self->may_remove($state, $name);
+ next;
+ }
+ my $plist;
+ eval {
+ $plist = OpenBSD::PackingList->fromfile($contents);
+ };
+ if ($@) {
+ $state->errsay("$name: bad plist");
+ $self->may_remove($state, $name);
+ next;
+ }
+ if ($plist->pkgname ne $name) {
+ $state->errsay("$name: pkgname does not match");
+ $self->may_remove($state, $name);
+ }
+ }
+}
+
+sub package_files_check
+{
+ my ($self, $state, $l) = @_;
+ $state->progress->set_header("Files from packages");
+ my $i = 0;
+ for my $name (@$l) {
+ next if $state->{removed}{$name};
+ $state->progress->show(++$i, scalar @$l);
+ my $plist = OpenBSD::PackingList->from_installation($name);
+ $state->log->set_context($name);
+ if ($state->{quick}) {
+ $plist->basic_check($state);
+ } else {
+ $plist->thorough_check($state);
+ }
+ }
+}
+
+sub localbase_check
+{
+ my ($self, $state) = @_;
+ $state->{known} //= {};
+ # XXX
+ OpenBSD::Mtree::parse($state->{known}, OpenBSD::Paths->localbase,
+ "/etc/mtree/BSD.local.dist", 1);
+ $state->progress->set_header("Other files");
+ find(sub {
+ $state->progress->working(1024);
+ if (-d $_) {
+ return if defined $state->{known}{$File::Find::name};
+ } else {
+ return if $state->{known}{$File::Find::dir}{$_};
+ }
+ $state->say("Unknown object $File::Find::name");
+ }, OpenBSD::Paths->localbase);
+}
+
+sub run
+{
+ my ($self, $state) = @_;
+
+ my @list = installed_packages(1);
+ $self->sanity_check($state, \@list);
+ $self->package_files_check($state, \@list);
+ $self->localbase_check($state);
+}
+
+sub parse_and_run
+{
+ my $self = shift;
+
+ my $state = OpenBSD::PkgFsck::State->new;
+ $self->handle_options('fiq', $state,
+ 'pkg_fsck [-fimnqvx] [-D value]');
+ $state->{interactive} = $state->opt('i');
+ $state->{force} = $state->opt('f');
+ $state->{quick} = $state->opt('q');
+ $self->run($state);
+ $state->log->dump;
+}
+
+1;
diff --git a/usr.sbin/pkg_add/pkg b/usr.sbin/pkg_add/pkg
index 1d83e9cac87..16ea03fd0cd 100644
--- a/usr.sbin/pkg_add/pkg
+++ b/usr.sbin/pkg_add/pkg
@@ -1,6 +1,6 @@
#! /usr/bin/perl
# ex:ts=8 sw=4:
-# $OpenBSD: pkg,v 1.13 2010/06/04 13:19:39 espie Exp $
+# $OpenBSD: pkg,v 1.14 2010/06/05 12:30:36 espie Exp $
#
# Copyright (c) 2010 Marc Espie <espie@openbsd.org>
#
@@ -28,8 +28,9 @@ sub run
die $@;
}
$module->parse_and_run;
+ exit(0);
}
-my @l = qw(add create delete info);
+my @l = qw(add create delete fsck info);
for my $i (@l) {
if ($0 =~ m/\/?pkg_$i$/) {
diff --git a/usr.sbin/pkg_add/pkg.1 b/usr.sbin/pkg_add/pkg.1
index f603368d4e4..d3ce20f8127 100644
--- a/usr.sbin/pkg_add/pkg.1
+++ b/usr.sbin/pkg_add/pkg.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: pkg.1,v 1.5 2010/06/05 07:11:43 espie Exp $
+.\" $OpenBSD: pkg.1,v 1.6 2010/06/05 12:30:36 espie Exp $
.\"
.\" Copyright (c) 2010 Marc Espie <espie@openbsd.org>
.\"
diff --git a/usr.sbin/pkg_add/pkg_fsck.8 b/usr.sbin/pkg_add/pkg_fsck.8
new file mode 100644
index 00000000000..91660c214f9
--- /dev/null
+++ b/usr.sbin/pkg_add/pkg_fsck.8
@@ -0,0 +1,90 @@
+.\" $OpenBSD: pkg_fsck.8,v 1.1 2010/06/05 12:30:36 espie Exp $
+.\"
+.\" Copyright (c) 2010 Marc Espie <espie@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: June 5 2010 $
+.Dt PKG_FSCK 1
+.Os
+.Sh NAME
+.Nm pkg_fsck
+.Nd check consistency of installed packages
+.Sh SYNOPSIS
+.Nm pkg_fsck
+.Bk -words
+.Op Fl fimnqvx
+.Oo Fl D Ar name
+.Ns Oo Ns = Ns Ar value
+.Oc
+.Oc
+.Ek
+.Sh DESCRIPTION
+.Nm
+verifies as much information as it can about installed packages.
+.Pp
+.Nm
+is not needed under normal circumstances, but it can be used to recover after
+a catastrophic system failure in a middle of
+.Xr pkg_add 1 ,
+.Xr pkg_delete 1 .
+.Pp
+.Nm
+performs the following checks:
+.Bl -tag -width small
+.It Packing-list sanity
+Checks that
+.Pa /var/db/pkg
+only contains directories, that each directory holds a packing-list,
+and that said packing-list is an actual packing-list that matches the directory.
+.It Files from packages
+Checks that each file or directory in those packing-lists actually exist,
+and that their checksum matches what's recorded in the packing-list.
+.El
+.Pp
+Options are as follows:
+.Bl -tag -width flagq
+.It Xo
+.Fl D
+.Ar name Ns Op = Ns Ar value
+.Xc
+for consistency with other pkg commands.
+No relevant defines so far.
+.It Fl f
+Force the removal of bogus package information.
+.It Fl i
+Ask user whether to irrevocably remove bogus package information.
+.It Fl m
+Causes
+.Nm
+to always display the progress meter in cases it would not do so by default.
+.It Fl n
+Don't actually modify packages, just perform checks.
+.It Fl q
+Don't verify checksums for files, just check for their existence.
+.It Fl v
+Turn on verbose output.
+Several
+.Fl v
+may turn on more verbose output.
+.It Fl x
+Disable progress meter.
+.El
+.Sh SEE ALSO
+.Xr fsck 8
+.Sh BUGS
+Work in progress.
+More checks to be added.
+Use with caution.
+.Sh AUTHORS
+This program was written by Marc Espie.