summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'sys-apps/yard/files/yard-2.0/sbin/check_root_fs')
-rw-r--r--sys-apps/yard/files/yard-2.0/sbin/check_root_fs605
1 files changed, 605 insertions, 0 deletions
diff --git a/sys-apps/yard/files/yard-2.0/sbin/check_root_fs b/sys-apps/yard/files/yard-2.0/sbin/check_root_fs
new file mode 100644
index 000000000000..9cfc2b1923e7
--- /dev/null
+++ b/sys-apps/yard/files/yard-2.0/sbin/check_root_fs
@@ -0,0 +1,605 @@
+#! /usr/bin/perl
+# -*- Mode: Perl -*-
+# This script created automatically from scripts/check_root_fs.in
+# $Header: /var/cvsroot/gentoo-x86/sys-apps/yard/files/yard-2.0/sbin/check_root_fs,v 1.1 2001/04/09 03:01:00 achim Exp $
+##############################################################################
+##
+## CHECK_ROOT_FS
+## Copyright (C) 1996,1997,1998 Tom Fawcett (fawcett@croftj.net)
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+##
+##
+##############################################################################
+use strict;
+use File::Basename;
+use File::Path;
+use FileHandle;
+use English;
+use lib "/etc/yard", "/usr/lib/yard";
+use yardconfig;
+use File::Find;
+
+BEGIN { require "yard_utils.pl" }
+require "Config.pl";
+
+### GLOBAL VARIABLES
+my(%Termcap); # Defs from /etc/termcap
+my($checked_for_getty_files); # Scalar -- have we checked getty files yet?
+my(%checked); # Hash table of files we've already checked
+# This is a little crude. Technically we should read /etc/conf.getty
+# to make sure we're not supposed to be using a different login binary.
+my($login_binary) = "$CFG::mount_point/bin/login";
+
+
+STDOUT->autoflush(1);
+
+start_logging_output();
+info 0, "check_root_fs 2.0\n";
+
+mount_device_if_necessary();
+
+# This goes first so we define %Termcap for use in children
+check_termcap();
+
+##### Here are the tests.
+fork_chroot_and(\&check_fstab);
+fork_chroot_and(\&check_inittab);
+fork_chroot_and(\&check_scripts);
+check_links();
+check_passwd();
+check_pam();
+check_nss();
+
+info 0, "All done.\n";
+info 0, "If this is acceptable, continue with write_rescue_disk\n";
+exit;
+
+
+##############################################################################
+sub warning {
+ info 0, "\n", @_;
+# $::Warnings++;
+}
+
+
+# This takes a procedure call, forks off a subprocess, chroots to
+# $CFG::mount_point and runs the procedure.
+sub fork_chroot_and {
+ my($call) = @_;
+
+ my($Godot) = fork;
+ die "Can't fork: $!" unless defined $Godot;
+
+ if (!$Godot) {
+ # Child process
+ chdir($CFG::mount_point);
+ chroot($CFG::mount_point); ##### chroot to the root filesystem
+ &$call;
+ exit;
+
+ } else {
+ # Parent here
+ waitpid($Godot, 0);
+ }
+}
+
+
+sub check_fstab {
+ my($FSTAB) = "/etc/fstab";
+ my($proc_seen);
+
+ open(FSTAB, "<$FSTAB") or error "$FSTAB: $!";
+ info 0, "\nChecking $FSTAB\n";
+
+ while (<FSTAB>) {
+ chomp;
+ next if /^\#/ or /^\s*$/;
+
+ my($dev, $mp, $type, $opts) = split;
+ next if $mp eq 'none' or $type eq 'swap';
+ next if $dev eq 'none';
+
+ if (!-e $mp) {
+ info 0, "$FSTAB($.): $_\n\tCreating $mp on root filesystem\n";
+ mkpath($mp);
+ }
+
+ if ($dev !~ /:/ and !-e $dev) {
+ warning "$FSTAB($.): $_\n\tDevice $dev does not exist "
+ . "on root filesystem\n";
+ }
+
+ ##### If you use the file created by create_fstab, these tests
+ ##### are superfluous.
+
+ if ($dev =~ m|^/dev/hd| and $opts !~ /noauto/) {
+ warning "\t($.): You probably should include \"noauto\" option\n",
+ "\tin the fstab entry of a hard disk. When the rescue floppy\n",
+ "\tboots, the \"mount -a\" will try to mount $dev\n";
+
+ } elsif ($dev eq $CFG::floppy and $type ne 'ext2' and $type ne 'auto') {
+ warning "\t($.): You've declared your floppy drive $CFG::floppy",
+ " to hold\n",
+ "\ta $type filesystem, which is not ext2. The rescue floppy\n",
+ "\tis ext2, which may confuse 'mount -a' during boot.\n";
+
+ } elsif ($type eq 'proc') {
+ $proc_seen = 1;
+
+ }
+ }
+ close(FSTAB);
+ warning "\tNo /proc filesystem defined.\n" unless $proc_seen;
+ info 0, "Done with $FSTAB\n";
+}
+
+
+sub check_inittab {
+ my($INITTAB) = "/etc/inittab";
+ info 0, "\nChecking $INITTAB\n";
+
+ if (!open(INITTAB, "<$INITTAB")) {
+ warning "$INITTAB: $!\n";
+ return
+ }
+
+ my($default_rl, $saw_line_for_default_rl);
+
+ while (<INITTAB>) {
+ chomp;
+ my($line) = $_; # Copy for errors
+ s/\#.*$//; # Delete comments
+ next if /^\s*$/; # Skip empty lines
+
+ my($code, $runlevels, $action, $command) = split(':');
+
+ if ($action eq 'initdefault') { ##### The initdefault runlevel
+ $default_rl = $runlevels;
+ next;
+ }
+ if ($runlevels =~ /$default_rl/) {
+ $saw_line_for_default_rl = 1;
+ }
+ if ($command) {
+ my($exec, @args) = split(' ', $command);
+
+ if (!-f $exec) {
+ warning "$INITTAB($.): $line\n",
+ "\t$exec: non-existent or non-executable\n";
+
+ } elsif (!-x $exec) {
+ info 0, "$INITTAB($.): $line\n",
+ info 0, "\tMaking $exec executable\n";
+ chmod(0777, $exec) or error "chmod failed: $!";
+
+ } else {
+ ##### executable but not binary ==> script
+ scan_command_file($exec, @args) if !-B $exec;
+ }
+
+ if ($exec =~ m|getty|) { # matches *getty* call
+ check_getty_type_call($exec, @args);
+ }
+ }
+ }
+ close(INITTAB) or error "close(INITTAB): $!";
+
+ if (!$saw_line_for_default_rl) {
+ warning "\tDefault runlevel is $default_rl, but no entry for it.\n";
+ }
+ info 0, "Done with $INITTAB\n";
+}
+
+
+##### This could be made much more complete, but for typical rc type
+##### files it seems to catch the common problems.
+sub scan_command_file {
+ my($cmdfile, @args) = @_;
+ my(%warned, $line);
+
+ return if $checked{$cmdfile};
+ info 0, "\nScanning $cmdfile\n";
+ open(CMDFILE, "<$cmdfile") or error "$cmdfile: $!";
+
+ while ($line = <CMDFILE>) {
+ chomp($line);
+ next if $line =~ /^\#/ or /^\s*$/;
+
+ next if $line =~ /^\w+=/;
+
+ while ($line =~ m!(/(usr|var|bin|sbin|etc|dev)/\S+)(\s|$)!g) {
+ my($abs_file) = $1;
+ # next if $abs_file =~ m/[*?]/; # Skip meta chars - we don't trust glob
+ next if $warned{$abs_file}; # Only warn once per file
+ if (!-e $abs_file) {
+ warning "$cmdfile($.): $line\n\t$1: missing on root filesystem\n";
+ $warned{$abs_file} = 1;
+ }
+ }
+ }
+ close(CMDFILE) or error "close($cmdfile): $!";
+
+ $checked{$cmdfile} = 1;
+ info 0, "Done scanning $cmdfile\n";
+}
+
+
+##### Check_passwd is NOT run under chroot.
+sub check_passwd {
+ my($passwd_file) = "$CFG::mount_point/etc/passwd";
+ open(PASSWD, "<$passwd_file") or error "Can't read passwd file: $!\n";
+ info 0, "\nChecking passwd file $passwd_file\n";
+
+ while (<PASSWD>) {
+ chomp;
+ next if /^\s*$/; # Skip blank/empty lines
+ my($line) = $_;
+ my($login_name, $passwd, $UID, $GID, $user_name, $home, $shell) =
+ split(':');
+
+ next if $passwd eq "*"; # Skip warnings if user can't login
+
+ -d ($CFG::mount_point . $home) or
+ warning "$passwd_file($.): $line\n",
+ "\tHome directory of $login_name ($CFG::mount_point$home) is missing\n";
+ -e ($CFG::mount_point . $shell) or
+ warning "$passwd_file($.): $line\n",
+ "\tShell of $login_name ($CFG::mount_point$shell) doesn't exist\n";
+
+ check_init_files($login_name, $home, $shell);
+ }
+ close(PASSWD);
+ info 0, "Done checking $passwd_file\n";
+}
+
+
+##### Simple PAM configuration checks.
+##### Tests whether PAM is needed, and whether the configuration libraries exist.
+##### Check_pam is NOT run under chroot.
+sub check_pam {
+ my($pam_configured) = 0; # Have we seen some pam config file yet?
+ info 0, "Checking for PAM\n";
+
+ my($pamd_dir) = "$CFG::mount_point/etc/pam.d";
+ my($pam_conf) = "$CFG::mount_point/etc/pam.conf";
+
+ if (-e $pam_conf) {
+ info 0, "Checking $pam_conf\n";
+ $pam_configured = 1;
+ open(PAM, $pam_conf) or error "Can't open pam.conf: $!\n";
+ while (<PAM>) {
+ chomp;
+ next if /^\#/ or /^\s*$/; # Skip comments and empty lines
+ my($file) = (split)[3]; # Get fourth field
+ if (!-e "$CFG::mount_point/$file") {
+ warning "$pam_conf($.): $_\n",
+ "\tLibrary $file does not exist on root fs\n";
+ }
+ # That's all we check for now
+ }
+ close(PAM) or die "Closing PAM: $!";
+ info 0, "Done with $pam_conf\n";
+ }
+
+
+ if (-e $pamd_dir) {
+ info 0, "Checking files in $pamd_dir\n";
+ opendir(PAMD, $pamd_dir) or error "Can't open $pamd_dir: $!";
+ my($file);
+ while (defined($file = readdir(PAMD))) {
+ my($file2) = "$pamd_dir/$file";
+ next unless -f $file2; # Skip directories, etc.
+ open(PF, $file2) or error "$file2: $!";
+ while (<PF>) {
+ chomp;
+ next if /^\#/ or /^\s*$/; # Skip comments and empty lines
+ my($file) = (split)[3]; # Get fourth field
+ $pam_configured = 1;
+ if (!-e "$CFG::mount_point/$file") {
+ warning "$file2($.): $_\n",
+ "\tLibrary $file does not exist on root fs\n";
+ }
+ }
+ close(PF);
+ }
+ closedir(PAMD);
+ }
+
+ # Finally, see whether PAM configuration is needed
+ if (!$pam_configured and -e $login_binary) {
+ my($dependencies) = scalar(`ldd $login_binary`);
+ if (defined($dependencies) and $dependencies =~ /libpam/) {
+ warning "Warning: login ($login_binary) needs PAM, but you haven't\n",
+ "\tconfigured it (in /etc/pam.conf or /etc/pam.d/)\n",
+ "\tYou probably won't be able to login.\n";
+ }
+ }
+ info 0, "Done with PAM\n";
+}
+
+
+
+##### Basic checks for nsswitch.conf.
+##### check_nss is NOT run under chroot.
+##### From the nsswitch.conf(5) manpage:
+##### For glibc, you must have a file called /lib/libnss_SERVICE.so.X for
+##### every SERVICE you are using. On a standard installation, you could
+##### use `files', `db', `nis' and `nisplus'. For hosts, you could specify
+##### `dns' as extra service, for passwd, group and shadow `compat'. These
+##### services will not be used by libc5 with NYS. The version number X
+##### is 1 for glibc 2.0 and 2 for glibc 2.1.
+
+sub check_nss {
+ my($nss_conf) = "$CFG::mount_point/etc/nsswitch.conf";
+ info 0, "Checking for NSS\n";
+
+ my($libc) = yard_glob("$CFG::mount_point/lib/libc-2*");
+ my($libc_version) = $libc =~ m|/lib/libc-2.(\d)|;
+ if (!defined($libc_version)) {
+ warning "Can't determine your libc version\n";
+ } else {
+ info 0, "You're using $libc\n";
+ }
+ my($X) = $libc_version;
+
+ if (-e $nss_conf) {
+ open(NSS, "<$nss_conf") or die "open($nss_conf): $!";
+
+ my($line);
+ while (defined($line = <NSS>)) {
+ chomp $line;
+ next if $line =~ /^\#/;
+ next if $line =~ /^\s*$/;
+ my($db, $entries) = $line =~ m/^(\w+):\s*(.+)$/;
+ # Remove bracketed expressions (action specifiers)
+ $entries =~ s/\[[^\]]*\]//g;
+ my(@entries) = split(' ', $entries);
+ my($entry);
+ for $entry (@entries) {
+ next if $entry =~ /^\[/; # ignore action specifiers
+ my($lib) = "$CFG::mount_point/lib/libnss_${entry}.so.${X}";
+ if (!-e $lib) {
+ warning "$nss_conf($.):\n$line\n",
+ "\tRoot filesystem needs $lib to support $entry\n";
+ }
+ }
+ }
+
+ } else {
+ # No nsswitch.conf is present, figure out if maybe there should be one.
+ if (-e $login_binary) {
+ my($dependencies) = scalar(`ldd $login_binary`);
+ my($libc_version) = ($dependencies =~ /libc\.so\.(\d+)/m);
+ if ($libc_version > 5) {
+ # Needs libc 6 or greater
+ warning "Warning: $login_binary on rescue disk needs libc.so.$libc_version,\n"
+ . "\tbut there is no NSS configuration file ($nss_conf)\n"
+ . "\ton root filesystem.\n";
+ }
+ }
+ }
+ info 0, "Done with NSS\n";
+}
+
+
+
+sub check_links {
+ info 0, "\nChecking links relative to $CFG::mount_point\n";
+
+ sub wanted {
+ if (-l $File::Find::name) {
+ local($::raw_link) = readlink($File::Find::name);
+ local($::target) = make_link_absolute($File::Find::name, $::raw_link);
+
+ # I added this next test for /dev/stdout link hair.
+ # This really should be more complicated to handle link chains,
+ # but as a hack this works for three.
+ if (onto_proc_filesystem($File::Find::name)) {
+
+ } elsif (-l $::target) {
+ chase_link($::target, 16);
+
+ } elsif (!-e $::target) {
+ warning "Warning: Unresolved link: $File::Find::name -> $::raw_link\n";
+ }
+ }
+ };
+
+ finddepth(\&wanted, $CFG::mount_point);
+}
+
+
+sub chase_link {
+ my($file, $link_depth) = @_;
+
+ if ($link_depth == 0) {
+ warning "Warning: Probable link circularity involving $file\n";
+
+ } elsif (-l $file) {
+ chase_link(make_link_absolute($file, readlink($file)),
+ $link_depth-1);
+ }
+}
+
+
+sub check_scripts {
+ info 0, "\nChecking script interpreters\n";
+ local($::prog);
+
+ sub check_interpreter {
+ if (-x $File::Find::name and -f _ and -T _) {
+ open(SCRIPT, $File::Find::name) or error "$File::Find::name: $!";
+ my($prog, $firstline);
+ chomp($firstline = <SCRIPT>);
+ if (($prog) = $firstline =~ /^\#!\s*(\S+)/) {
+ if (!-e $prog) {
+ warning "Warning: $File::Find::name needs $prog, which is missing\n";
+ } elsif (!-x $prog) {
+ warning "Warning: $File::Find::name needs $prog, " .
+ "which is not executable.\n";
+ }
+ }
+ close(SCRIPT);
+ }
+ }; # End of sub check_interpreter
+
+ find(\&check_interpreter, "/");
+}
+
+sub check_getty_type_call {
+ my($prog, @args) = @_;
+
+ if ($prog eq 'getty') {
+ my($tty, $speed, $type) = @args;
+
+ if (!-e "$CFG::mount_point/dev/$tty") {
+ warning "\tLine $.: $prog for $tty, but /dev/$tty doesn't exist.\n";
+ }
+ if (!defined($Termcap{$type})) {
+ warning "\tLine $.: Type $type not defined in termcap\n";
+ }
+ }
+ ## If getty or getty_ps, look for /etc/gettydefs, /etc/issue
+ ## Check that term type matches one in termcap db.
+
+ if ($prog =~ /^getty/) {
+ if (!$checked_for_getty_files) {
+ warning "\tLine $.: $prog expects /etc/gettydefs, which is missing.\n"
+ unless -e "$CFG::mount_point/etc/gettydefs";
+ warning "\tLine $.: $prog expects /etc/issue, which is missing.\n"
+ unless -e "$CFG::mount_point/etc/issue";
+ $checked_for_getty_files = 1;
+ }
+ }
+}
+
+
+###
+### NB. This is *not* run under chroot
+###
+sub check_init_files {
+ my($user, $home, $shell) = @_;
+
+ info 0, "Checking init files of $user (homedir= $home)\n";
+
+ my($shellname) = basename($shell);
+ my @init_files;
+
+ ##### Try to infer the list of init files to be run for the shell
+ ##### of this user. Order is somewhat important here because of
+ ##### the search path.
+
+ if ($shellname =~ /^(bash|sh)$/) {
+ @init_files = ("/etc/profile", "/etc/bashrc",
+ "$home/.profile", "$home/.bash_login", "$home/.bashrc",
+ "$home/.shrc");
+
+ } elsif ($shellname eq "ash") {
+ @init_files = ("/etc/profile", "$home/.profile");
+
+ } elsif ($shellname =~ /^(tcsh|csh)$/) {
+ @init_files = ("/etc/csh.cshrc", "/etc/.cshrc", "/etc/csh.login",
+ "$home/.cshrc", "$home/.tcshrc", "$home/.login");
+ }
+
+ ##### The path to be searched. This may be error prone.
+ my(@path) = ();
+ my($init_file);
+
+ foreach $init_file (@init_files) {
+ $init_file = $CFG::mount_point . $init_file;
+
+ next if $checked{$init_file} or !-r $init_file;
+
+ info 0, "Checking $init_file\n";
+
+ open(INITF, "<$init_file") or die "$init_file: $!";
+
+ while (<INITF>) {
+ chomp;
+ next if /^\#/ or /^\s*$/; # Skip comments, whitespace
+
+ my($var, $val);
+ if (($var, $val) = /^\s*(\w+)\s*=\s*(.*)\s*$/) { # Variable assignment
+ ##### Look for PATH assignment
+ if ($var eq "PATH") {
+ $val =~ s/^[\"\'](.*)[\"\']$/$1/; # Strip quotes
+ @path = split(':', $val);
+ info 1, "Using PATH: ", join(':', @path), "\n";
+ } else {
+ next; # Skip other assignments
+ }
+ }
+
+ my($cmd, $hd_abs);
+
+ ##### Check for commands that aren't present
+ ($cmd) = /^(\w+)\b/; # Pick up cmd name
+ if ($cmd and ($hd_abs = find_file_in_path($cmd, @path))) {
+ # If it's here, see if it's on the rescue disk
+ if (!(-e "$CFG::mount_point/$hd_abs" and -x _)) {
+ warning "$init_file($.): $_\n\t\t$cmd looks like a command but\n",
+ "\t\tdoes not exist on the root filesystem.\n";
+ }
+ }
+
+ # Check for commands in backticks that aren't present
+ ($cmd) = /\`(\w+)\b/;
+ if ($cmd and ($hd_abs=find_file_in_path($cmd))) {
+ # If it's here, see if it's on the rescue disk
+ # Note that this could mislead if the user moved it to a different
+ # dir on the root fs.
+ if (!-e "$CFG::mount_point/$hd_abs") {
+ warning "${init_file}($.): $_\n\t$cmd: missing from root fs.\n";
+ } elsif (!-x _) {
+ warning "$init_file($.): $_\n\t$cmd: not executable on root fs.\n";
+ }
+ }
+ }
+ close(INITF);
+ info 0, "Done with $init_file\n";
+ $checked{$init_file} = 1;
+ } # end of foreach
+}
+
+
+
+sub check_termcap {
+ open(TERMCAP, "<$CFG::mount_point/etc/termcap") or
+ warning "No file $CFG::mount_point/etc/termcap";
+ while (<TERMCAP>) {
+ chomp;
+ next unless $_;
+ next if /^\#/; # Skip comments
+ next if /^\s+/; # Skip non-head lines
+
+ ##### Get complete logical line
+ my($def) = $_;
+ while (/\\$/) { # Trailing backslash => continued
+ chomp($def); # Discard backslash
+ chomp($_ = <TERMCAP>); # Get a line, w/o newline char
+ $def .= $_;
+ }
+
+ ##### Extract terminal names from line
+ my($names) = $def =~ /^([^:]+):/;
+ my(@terms) = split(/\|/, $names);
+ @Termcap{@terms} = (1) x ($#terms + 1);
+ }
+ close(TERMCAP);
+}
+
+##### END OF CHECK_ROOT_FS