summaryrefslogtreecommitdiffstats
path: root/perl-install/fs.pm
diff options
context:
space:
mode:
Diffstat (limited to 'perl-install/fs.pm')
-rw-r--r--perl-install/fs.pm245
1 files changed, 245 insertions, 0 deletions
diff --git a/perl-install/fs.pm b/perl-install/fs.pm
new file mode 100644
index 000000000..cf29fe014
--- /dev/null
+++ b/perl-install/fs.pm
@@ -0,0 +1,245 @@
+package fs;
+
+use diagnostics;
+use strict;
+
+use common qw(:common :file :system);
+use log;
+use devices;
+use partition_table qw(:types);
+use run_program;
+use nfs;
+use swap;
+use detect_devices;
+use commands;
+
+1;
+
+
+sub read_fstab($) {
+ my ($file) = @_;
+
+ local *F;
+ open F, $file or return;
+
+ map {
+ my ($dev, $mntpoint, @l) = split ' ';
+ $dev =~ s,/(tmp|dev)/,,;
+ while (@l > 4) { $mntpoint .= " " . shift @l; }
+ { device => $dev, mntpoint => $mntpoint, type => $l[0], options => $l[1] }
+ } <F>;
+}
+
+sub check_mounted($) {
+ my ($fstab) = @_;
+
+ local (*F, *G, *H);
+ open F, "/etc/mtab";
+ open G, "/proc/mounts";
+ open H, "/proc/swaps";
+ foreach (<F>, <G>, <H>) {
+ foreach my $p (@$fstab) {
+ /$p->{device}\s/ and $p->{isMounted} = 1;
+ }
+ }
+}
+
+sub get_mntpoints_from_fstab($) {
+ my ($fstab) = @_;
+
+ foreach (read_fstab('/etc/fstab')) {
+ foreach my $p (@$fstab) {
+ $p->{device} eq $_->{device} or next;
+ $p->{mntpoint} ||= $_->{mntpoint};
+ $p->{options} ||= $_->{options};
+ $_->{type} ne 'auto' && $_->{type} ne type2fs($p->{type}) and
+ log::l("err, fstab and partition table do not agree for $_->{device} type: " . (type2fs($p->{type}) || type2name($p->{type})) . " vs $_->{type}");
+ }
+ }
+}
+
+sub format_ext2($;$) {
+ my ($dev, $bad_blocks) = @_;
+ my @options;
+
+ $dev =~ m,(rd|ida)/, and push @options, qw(-b 4096 -R stride=16); # For RAID only.
+ $bad_blocks and push @options, "-c";
+
+ run_program::run("mke2fs", devices::make($dev), @options) or die "ext2 formatting of $dev failed";
+}
+
+sub format_dos($;$) {
+ my ($dev, $bad_blocks) = @_;
+
+ run_program::run("mkdosfs", devices::make($dev), $bad_blocks ? "-c" : ()) or die "dos formatting of $dev failed";
+}
+
+sub format_part($;$) {
+ my ($part, $bad_blocks) = @_;
+
+ $part->{isFormatted} and return;
+
+ if (isExt2($part)) {
+ format_ext2($part->{device}, $bad_blocks);
+ } elsif (isDos($part)) {
+ format_dos($part->{device}, $bad_blocks);
+ } elsif (isSwap($part)) {
+ swap::make($part->{device}, $bad_blocks);
+ } else {
+ die "don't know how to format $_->{device} in type " . type2name($_->{type});
+ }
+ $part->{isFormatted} = 1;
+}
+
+sub mount($$$;$) {
+ my ($dev, $where, $fs, $rdonly) = @_;
+ log::l("mounting $dev on $where as type $fs");
+
+ $::testing and return;
+
+ -d $where or commands::mkdir_('-p', $where);
+
+ if ($fs eq 'nfs') {
+ log::l("calling nfs::mount($dev, $where)");
+ nfs::mount($dev, $where) or die "nfs mount failed";
+ } elsif ($fs eq 'smb') {
+ die "no smb yet...";
+ }
+ $dev = devices::make($dev);
+
+ my $flag = 0;#c::MS_MGC_VAL();
+ $flag |= c::MS_RDONLY() if $rdonly;
+ my $mount_opt = $fs eq 'vfat' ? "check=relaxed" : "";
+
+ log::l("calling mount($dev, $where, $fs, $flag, $mount_opt)");
+ syscall_('mount', $dev, $where, $fs, $flag, $mount_opt) or die "mount failed: $!";
+
+ local *F;
+ open F, ">>/etc/mtab" or return; # fail silently, must be read-only /etc
+ print F "$dev $where $fs defaults 0 0\n";
+}
+
+# takes the mount point to umount (can also be the device)
+sub umount($) {
+ my ($mntpoint) = @_;
+ syscall_('umount', $mntpoint) or die "error unmounting $mntpoint: $!";;
+
+ my @mtab = cat_('/etc/mtab'); # don't care about error, if we can't read, we won't manage to write... (and mess mtab)
+ local *F;
+ open F, ">/etc/mtab" or return;
+ foreach (@mtab) { print F $_ unless /(^|\s)$mntpoint\s/; }
+}
+
+sub mount_part($;$) {
+ my ($part, $prefix) = @_;
+
+ $part->{isMounted} and return;
+ $part->{mntpoint} or die "missing mount point";
+
+ isSwap($part) ?
+ swap::swapon($part->{device}) :
+ mount(devices::make($part->{device}), ($prefix || '') . $part->{mntpoint}, type2fs($part->{type}), 0);
+ $part->{isMounted} = 1;
+}
+
+sub umount_part($;$) {
+ my ($part, $prefix) = @_;
+
+ $part->{isMounted} or return;
+
+ isSwap($part) ?
+ swap::swapoff($part->{device}) :
+ umount(($prefix || '') . ($part->{mntpoint} || "/dev/$part->{device}"));
+ $part->{isMounted} = 0;
+}
+
+sub mount_all($;$) {
+ my ($fstab, $prefix) = @_;
+
+ log::l("mounting all filesystems");
+
+ # order mount by alphabetical ordre, that way / < /home < /home/httpd...
+ foreach (sort { $a->{mntpoint} cmp $b->{mntpoint} } @$fstab) {
+ $_->{mntpoint} and mount_part($_, $prefix);
+ }
+}
+
+sub umount_all($;$) {
+ my ($fstab, $prefix) = @_;
+
+ log::l("unmounting all filesystems");
+
+ foreach (sort { $b->{mntpoint} cmp $a->{mntpoint} } @$fstab) {
+ $_->{mntpoint} and umount_part($_, $prefix);
+ }
+}
+
+# do some stuff before calling write_fstab
+sub write($$) {
+ my ($prefix, $fstab) = @_;
+ my @cd_drives = detect_devices::cdroms();
+
+ log::l("scanning /proc/mounts for iso9660 filesystems");
+ unshift @cd_drives, grep { $_->{type} eq 'iso9660' } read_fstab("/proc/mounts");
+ log::l("found cdrom drive(s) " . join(', ', map { $_->{device} } @cd_drives));
+
+ # cd-rom rooted installs have the cdrom mounted on /dev/root which
+ # is not what we want to symlink to /dev/cdrom.
+ my $cddev = first(grep { $_ ne 'root' } map { $_->{device} } @cd_drives);
+
+ $::testing and return 1;
+
+ log::l("resetting /etc/mtab");
+ local *F;
+ open F, "> $prefix/etc/mtab" or die "error resetting $prefix/etc/mtab";
+
+ if ($cddev) {
+ mkdir "$prefix/mnt/cdrom", 0755 or log::l("failed to mkdir $prefix/mnt/cdrom: $!");
+ symlink $cddev, "$prefix/dev/cdrom" or log::l("failed to symlink $prefix/dev/cdrom: $!");
+ }
+ write_fstab($fstab, $prefix, $cddev);
+}
+
+
+sub write_fstab($;$$) {
+ my ($fstab, $prefix, $cddev) = @_;
+ $prefix ||= '';
+
+ my @to_add =
+ map {
+ my ($dir, $options, $freq, $passno) = qw(/dev/ defaults 0 0);
+ $options ||= $_->{options};
+
+ isExt2($_) and ($freq, $passno) = (1, ($_->{mntpoint} eq '/') ? 1 : 2);
+ isNfs($_) and ($dir, $options) = ('', 'ro');
+
+ [ "$dir$_->{device}", $_->{mntpoint}, type2fs($_->{type}), $options, $freq, $passno ];
+
+ } grep { $_->{mntpoint} && type2fs($_->{type}) } @$fstab;
+
+ {
+ push @to_add, [ split ' ', '/dev/fd0 /mnt/floppy auto sync,user,noauto,nosuid,nodev,unhide 0 0' ];
+ push @to_add, [ split ' ', '/dev/cdrom /mnt/cdrom auto user,noauto,nosuid,exec,nodev,ro 0 0' ] if $cddev;
+ push @to_add, [ split ' ', 'none /proc proc defaults 0 0' ];
+ push @to_add, [ split ' ', 'none /dev/pts devpts mode=0620 0 0' ];
+ }
+
+ # get the list of devices and mntpoint
+ my @new = grep { $_ ne 'none' } map { @$_[0,1] } @to_add;
+ my %new; @new{@new} = undef;
+
+ my @current = cat_("$prefix/etc/fstab");
+
+ log::l("writing $prefix/etc/fstab");
+ local *F;
+ open F, "> $prefix/etc/fstab" or die "error writing $prefix/etc/fstab";
+ foreach (@current) {
+ my ($a, $b) = split;
+ # if we find one line of fstab containing either the same device or mntpoint, do not write it
+ exists $new{$a} || exists $new{$b} and next;
+ print F $_;
+ }
+ foreach (@to_add) {
+ print F join(" ", @$_), "\n";
+ }
+}