summaryrefslogtreecommitdiffstats
path: root/perl-install/loopback.pm
blob: 3be5a87bb3af2f6263198c83f5c27264d9b1c778 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package loopback; # $Id$

use diagnostics;
use strict;

#-######################################################################################
#- misc imports
#-######################################################################################
use MDK::Common::System;
use common;
use fs::type;
use fs;
use log;


sub carryRootLoopback {
    my ($part) = @_;
    $_->{mntpoint} eq '/' and return 1 foreach @{$part->{loopback} || []};
    0;
}

sub check_circular_mounts {
    my ($_hd, $part, $all_hds) = @_;

    my $fstab = [ fs::get::fstab($all_hds), $part ]; # no pb if $part is already in $all_hds

    my $base_mntpoint = $part->{mntpoint};
    my $check; $check = sub {
	my ($part, @seen) = @_;
	push @seen, $part->{mntpoint} || return;
	@seen > 1 && $part->{mntpoint} eq $base_mntpoint and die N("Circular mounts %s\n", join(", ", @seen));
	if (my $part = fs::get::up_mount_point($part->{mntpoint}, $fstab)) {
	    #- '/' carrier is a special case, it will be mounted first
	    $check->($part, @seen) if !carryRootLoopback($part);
	}
	if (isLoopback($part)) {
	    $check->($part->{loopback_device}, @seen);
	}
    };
    $check->($part) if !($base_mntpoint eq '/' && isLoopback($part)); #- '/' is a special case, no loop check
}

sub carryRootCreateSymlink {
    my ($part, $prefix) = @_;

    carryRootLoopback($part) or return;

    my $mntpoint = "$prefix$part->{mntpoint}";
    unless (-e $mntpoint) {
	eval { mkdir_p(dirname($mntpoint)) };
	#- do non-relative link for install, should be changed to relative link before rebooting
	symlink "/initrd/loopfs", $mntpoint;

	mkdir_p("/initrd/loopfs/lnx4win/boot");
	symlink "/initrd/loopfs/lnx4win/boot", "$prefix/boot";
    }
    #- indicate kernel to keep initrd
    mkdir_p("$prefix/initrd");
}


sub format_part {
    my ($part, $prefix) = @_;
    fs::mount_part($part->{loopback_device}, $prefix);
    create($part, $prefix);
    fs::format::part_raw($part);
}

sub create {
    my ($part, $prefix) = @_;
    my $f = $part->{device} = "$prefix$part->{loopback_device}{mntpoint}$part->{loopback_file}";
    return if -e $f;

    eval { mkdir_p(dirname($f)) };

    log::l("creating loopback file $f ($part->{size} sectors)");

    my $block_size = 128;
    my $s = "\0" x (512 * $block_size);
    sysopen(my $F, $f, 2 | c::O_CREAT()) or die "failed to create loopback file";
    for (my $i = 0; $i < $part->{size}; $i += $block_size) {
	syswrite $F, $s or die "failed to create loopback file";
    }
}

sub getFree {
    my ($dir, $part) = @_;
    my $freespace = $dir ? 
      2 * (MDK::Common::System::df($dir))[1] : #- df in KiB
      $part->{size};

    $freespace - sum map { $_->{size} } @{$part->{loopback} || []};
}

#- returns the size of the loopback file if it already exists
#- returns -1 is the loopback file can't be used
sub verifFile {
    my ($dir, $file, $part) = @_;
    -e "$dir$file" and return -s "$dir$file";

    $_->{loopback_file} eq $file and return -1 foreach @{$part->{loopback} || []};

    undef;
}

sub prepare_boot() {
    my $r = readlink "$::prefix/boot"; 
    unlink "$::prefix/boot"; 
    mkdir_p("$::prefix/boot");
    [$r, $::prefix];
}

sub save_boot {
    my ($loop_boot, $prefix) = @{$_[0]};
    
    $loop_boot or return;

    my @files = glob_("$prefix/boot/*");
    cp_af(@files, $loop_boot) if @files;
    rm_rf("$prefix/boot");
    symlink $loop_boot, "$prefix/boot";
}


1;

="hl slc"># 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # pbs/TODO: # - scsi mis-configuration (should work better now) # - with 2 scanners same manufacturer -> will overwrite previous conf -> only 1 conf !! (should work now) # - lp: see printerdrake # - install: prefix --> done (partially) use common; use detect_devices; use log; use handle_configs; my $sanedir = "$::prefix/etc/sane.d"; my $scannerDBdir = "$::prefix$ENV{SHARE_PATH}/ldetect-lst"; our $scannerDB = readScannerDB("$scannerDBdir/ScannerDB"); sub confScanner { my ($model, $port, $vendor, $product, $firmware) = @_; $port ||= "$::prefix/dev/scanner"; my $a = $scannerDB->{$model}{server}; #print "file:[$a]\t[$model]\t[$port]\n| ", (join "\n| ", @{$scannerDB->{$model}{lines}}),"\n"; my @driverconf = cat_("$sanedir/$a.conf"); my @configlines = @{$scannerDB->{$model}{lines}}; foreach my $line (@configlines) { $line =~ s/\$DEVICE/$port/g if $port; next if $line =~ /\$DEVICE/; $line =~ s/\$VENDOR/$vendor/g if $vendor; next if $line =~ /\$VENDOR/; $line =~ s/\$PRODUCT/$product/g if $product; next if $line =~ /\$PRODUCT/; $line =~ s/\$FIRMWARE/$firmware/g if $firmware; next if $line =~ /\$FIRMWARE/; my $linetype; if ($line =~ /^(\S*)LINE\s+(.*?)$/) { $linetype = $1; $line = $2; } next if !$line; if (!$linetype || ($linetype eq "USB" && ($port =~ /usb/i || $vendor)) || ($linetype eq "PARPORT" && !$vendor && $port =~ /(parport|pt_drv|parallel)/i) || ($linetype eq "SCSI" && !$vendor && $port =~ m!(/sg|scsi|/scanner)!i)) { handle_configs::set_directive(\@driverconf, $line, 1); } elsif ($linetype eq "FIRMWARE" && $firmware) { handle_configs::set_directive(\@driverconf, $line, 0); } } output("$sanedir/$a.conf", @driverconf); add2dll($a); } sub add2dll { return if member($_[0], chomp_(cat_("$sanedir/dll.conf"))); my @dllconf = cat_("$sanedir/dll.conf"); handle_configs::add_directive(\@dllconf, $_[0]); output("$sanedir/dll.conf", @dllconf); } sub setfirmware { my ($backend, $firmwareline) = @_; my @driverconf = cat_("$sanedir/$backend.conf"); handle_configs::set_directive(\@driverconf, $firmwareline, 0); output("$sanedir/$backend.conf", @driverconf); } sub installfirmware { # Install the firmware file in /usr/share/sane/firmware my ($firmware, $backend) = @_; return "" if !$firmware; # Install firmware run_program::rooted($::prefix, "mkdir", "-p", "/usr/share/sane/firmware") || do { $in->ask_warn(N("Error"), N("Could not create directory /usr/share/sane/firmware!")); return ""; }; # Link /usr/share/sane/firmware to /usr/share/sane/<backend name> as # some backends ignore the supplied absolute path to the firmware file # and always search their own directory if ($backend) { run_program::rooted($::prefix, "ln", "-sf", "/usr/share/sane/firmware", "/usr/share/sane/$backend") || do { $in->ask_warn(N("Error"), N("Could not create link /usr/share/sane/%s!", $backend)); return ""; }; } run_program::rooted($::prefix, "cp", "-f", "$firmware", "/usr/share/sane/firmware") || do { $in->ask_warn(N("Error"), N("Could not copy firmware file %s to /usr/share/sane/firmware!", $firmware)); return ""; }; $firmware =~ s!^(.*)(/[^/]+)$!/usr/share/sane/firmware$2!; run_program::rooted($::prefix, "chmod", "644", $firmware) || do { $in->ask_warn(N("Error"), N("Could not set permissions of firmware file %s!", $firmware)); return ""; }; return $firmware; } sub configured { my ($in) = @_; my @res; my $parportscannerfound = 0; # Run "scanimage -L", to find the scanners which are already working local *LIST; open LIST, "LC_ALL=C scanimage -L |"; while (my $line = <LIST>) { if ($line =~ /^\s*device\s*`([^`']+)'\s+is\s+a\s+(\S.*)$/) { # Extract port and description my $port = $1; my $description = $2; # Remove duplicate scanners appearing through saned and the # "net" backend next if $port =~ /^net:(localhost|127.0.0.1):/; # Is the scanner hooked to a parallel or serial port? if ($port =~ /(parport|pt_drv|parallel|ttys)/i) { $parportscannerfound = 1; } # Determine which SANE backend the scanner in question uses $port =~ /^([^:]+):/; my $backend = $1; # Does the scanner need a firmware file my $firmwareline = firmwareline($backend); # Store collected data push @res, { port => $port, val => { DESCRIPTION => $description, ($backend ? (BACKEND => $backend) : ()), ($firmwareline ? (FIRMWARELINE => $firmwareline) : ()), } }; } } close LIST; # We have a parallel port scanner, make it working for non-root users nonroot_access_for_parport($parportscannerfound, $in); return @res; } sub nonroot_access_for_parport { # This function configures a non-root access for parallel port # scanners by running saned as root, exporting the scanner to # localhost and letting the user's frontend use the "net" backend # to access the scanner through the loopback network device. # See also # http://www.linuxprinting.org/download/digitalimage/Scanning-as-Normal-User-on-Wierd-Scanner-Mini-HOWTO.txt # Desired state of this facility: 1: Enable, 0: Disable my ($enable, $in) = @_; # Is saned running? my $sanedrunning = services::starts_on_boot("saned"); # Is the "net" SANE backend active my $netbackendactive = grep { /^\s*net\s*$/ } cat_("/etc/sane.d/dll.conf"); # Set this to 1 to tell the caller that the list of locally available # scanners has changed (Here if the SANE client configuration has # changed) my $changed = 0; my $importschanged = 0; if ($enable) { # Enable non-root access # Install/start saned if (!$sanedrunning) { # Make sure saned and xinetd is installed and # running if (!files_exist('/usr/sbin/xinetd', '/usr/sbin/saned')) { if (!$in->do_pkgs->install('xinetd', 'saned')) { $in->ask_warn(N("Scannerdrake"), N("Could not install the packages needed to share your scanner(s).") . " " . N("Your scanner(s) will not be available for non-root users.")); } return 0; } } # Modify /etc/xinetd.d/saned to let saned run as root my @sanedxinetdconf = cat_("/etc/xinetd.d/saned"); s/(user\s*=\s*).*$/$1root/ foreach @sanedxinetdconf; s/(group\s*=\s*).*$/$1root/ foreach @sanedxinetdconf; output("/etc/xinetd.d/saned", @sanedxinetdconf); # Read list of hosts to where to export the local scanners my @exports = cat_("/etc/sane.d/saned.conf"); # Read list of hosts from where to import scanners my @imports = cat_("/etc/sane.d/net.conf"); # Add "localhost" to the machines which saned exports handle_configs::set_directive(\@exports, "localhost") if !member("localhost\n", @exports); # Add "localhost" to the machines which "net" imports handle_configs::set_directive(\@imports, "localhost") if !member("localhost\n", @imports); # Write /etc/sane.d/saned.conf output("/etc/sane.d/saned.conf", @exports); # Write /etc/sane.d/net.conf output("/etc/sane.d/net.conf", @imports); # Make sure that the "net" backend is active scanner::add2dll("net"); # (Re)start saned and make sure that it gets started on # every boot services::start_service_on_boot("saned"); services::start_service_on_boot("xinetd"); services::restart("xinetd"); } else { # Disable non-root access if (-r "/etc/xinetd.d/saned") { # Modify /etc/xinetd.d/saned to let saned run as saned my @sanedxinetdconf = cat_("/etc/xinetd.d/saned"); s/(user\s*=\s*).*$/$1saned/ foreach @sanedxinetdconf; s/(group\s*=\s*).*$/$1saned/ foreach @sanedxinetdconf; output("/etc/xinetd.d/saned", @sanedxinetdconf); # Restart xinetd services::restart("xinetd") if $sanedrunning; } } return 1; } sub detect { my @configured = @_; my @res; # Run "sane-find-scanner", this also detects USB scanners which only # work with libusb. my @devices = detect_devices::probeall(); local *DETECT; open DETECT, "LC_ALL=C sane-find-scanner -q |"; while (my $line = <DETECT>) { my ($vendorid, $productid, $make, $model, $description, $port, $driver); if ($line =~ /^\s*found\s+USB\s+scanner/i) { # Found an USB scanner if ($line =~ /vendor=(0x[0-9a-f]+)[^0-9a-f\[]+[^\[]*\[([^\[\]]+)\].*prod(|uct)=(0x[0-9a-f]+)[^0-9a-f\[]+[^\[]*\[([^\[\]]+)\]/) { # Scanner connected via libusb $vendorid = $1; $make = $2; $productid = $4; $model = $5; $description = "$make|$model"; } elsif ($line =~ /vendor=(0x[0-9a-f]+)[^0-9a-f]+.*prod(|uct)=(0x[0-9a-f]+)[^0-9a-f]+/) { # Scanner connected via scanner.o kernel module $vendorid = $1; $productid = $3; } if ($vendorid && $productid) { my ($vendor) = ($vendorid =~ /0x([0-9a-f]+)/); my ($id) = ($productid =~ /0x([0-9a-f]+)/); my ($device) = grep { sprintf("%04x", $_->{vendor}) eq $vendor && sprintf("%04x", $_->{id}) eq $id } @devices; if ($device) { $driver = $device->{driver}; } else { #warn "Failed to lookup $vendorid and $productid!\n"; }