diff options
Diffstat (limited to 'perl-install/printer/detect.pm')
-rw-r--r-- | perl-install/printer/detect.pm | 249 |
1 files changed, 182 insertions, 67 deletions
diff --git a/perl-install/printer/detect.pm b/perl-install/printer/detect.pm index 71adef0cf..fcb8316dd 100644 --- a/perl-install/printer/detect.pm +++ b/perl-install/printer/detect.pm @@ -8,17 +8,23 @@ use printer::data; sub local_detect() { modules::get_probeall("usb-interface") and eval { modules::load($usbprintermodule) }; - eval { modules::unload(qw(lp parport_pc parport)) }; #- on kernel 2.4 parport has to be unloaded to probe again - eval { modules::load(qw(parport_pc lp)) }; #- take care as not available on 2.4 kernel (silent error). - whatPrinter(); + # Reload parallel port modules only when we were not called by + # automatic setup of print queues, to avoid recursive calls + if ($::autoqueue) { + whatUsbport(); + } else { + eval { modules::unload(qw(lp parport_pc ppdev parport)) }; #- on kernel 2.4 parport has to be unloaded to probe again + eval { modules::load(qw(ppdev parport_pc lp)) }; #- take care as not available on 2.4 kernel (silent error). + whatPrinter(); + } } -sub net_detect() { whatNetPrinter(1, 0) } +sub net_detect { whatNetPrinter(1, 0, @_) } -sub net_smb_detect() { whatNetPrinter(0, 1) } +sub net_smb_detect { whatNetPrinter(0, 1, @_) } -sub detect() { - local_detect(), whatNetPrinter(1, 1); +sub detect { + local_detect(), whatNetPrinter(1, 1, @_); } @@ -34,26 +40,32 @@ sub whatPrinter() { sub whatParport() { my @res; - foreach (0..3) { + my $i = 0; + foreach (sort { $a =~ /(\d+)/; my $m = $1; $b =~ /(\d+)/; my $n = $1; $m <=> $n } `ls -1d /proc/parport/[0-9]* /proc/sys/dev/parport/parport[0-9]* 2>/dev/null`) { + chomp; my $elem = {}; my $F; - open $F, "/proc/parport/$_/autoprobe" or open $F, "/proc/sys/dev/parport/parport$_/autoprobe" or next; + open $F, "$_/autoprobe" or next; { local $_; my $itemfound = 0; - while (<$F>) { + while (<$F>) { + chomp; if (/(.*):(.*);/) { #-# $elem->{$1} = $2; $elem->{$1} =~ s/Hewlett[-\s_]Packard/HP/; $elem->{$1} =~ s/HEWLETT[-\s_]PACKARD/HP/; $itemfound = 1; + # Add IEEE-1284 device ID string + $elem->{IEEE1284} .= $_; } } # Some parallel printers miss the "CLASS" field $elem->{CLASS} = 'PRINTER' if $itemfound && !defined($elem->{CLASS}); } - push @res, { port => "/dev/lp$_", val => $elem }; + push @res, { port => "/dev/lp$i", val => $elem }; + $i ++; } @res; } @@ -99,6 +111,10 @@ sub whatUsbport() { next; }; close $PORT; + # Cut resulting string to its real length + my $length = ord(substr($idstr, 1, 1)) + + (ord(substr($idstr, 0, 1)) << 8); + $idstr = substr($idstr, 2, $length-2); # Remove non-printable characters $idstr =~ tr/[\x00-\x1f]/./; # If we do not find any item in the ID string, we try to read @@ -108,6 +124,9 @@ sub whatUsbport() { my ($manufacturer, $model, $serialnumber, $description, $commandset) = ("", "", "", "", ""); my ($sku); + if ($idstr =~ /CLS:([^;]+);/ || $idstr =~ /CLASS:([^;]+);/) { + $itemfound = 1; + } if ($idstr =~ /MFG:([^;]+);/ || $idstr =~ /MANUFACTURER:([^;]+);/) { $manufacturer = $1; $manufacturer =~ s/Hewlett[-\s_]Packard/HP/; @@ -141,12 +160,12 @@ sub whatUsbport() { $itemfound = 1; } # Nothing found? Try again if not in the third attempt, - # in the third attempt always accept. - next if !$itemfound && $j < 3; + # after the third attempt give up + next if !$itemfound; # Was there a manufacturer and a model in the string? if ($manufacturer eq "" || $model eq "") { $manufacturer = ""; - $model = N("Unknown Model"); + $model = N("Unknown model"); } # No description field? Make one out of manufacturer and model. if ($description eq "") { @@ -160,7 +179,8 @@ sub whatUsbport() { DESCRIPTION => $description, SERIALNUMBER => $serialnumber, 'COMMAND SET' => $commandset, - SKU => $sku + SKU => $sku, + IEEE1284 => $idstr, } }; last; } @@ -169,10 +189,14 @@ sub whatUsbport() { } sub whatNetPrinter { - my ($network, $smb) = @_; + my ($network, $smb, $timeout) = @_; my (@res); + # Set timeouts for "nmap" + $timeout = 4000 if !$timeout; + my $irtimeout = $timeout / 2; + # Which ports should be scanned? my @portstoscan; push @portstoscan, "139" if $smb; @@ -180,12 +204,13 @@ sub whatNetPrinter { return () if $#portstoscan < 0; my $portlist = join ",", @portstoscan; - + # Which hosts should be scanned? - # (Applying nmap to a whole network is very time-consuming, because nmap - # waits for a certain timeout period on non-existing hosts, so we get a - # lists of existing hosts by pinging the broadcast addresses for existing - # hosts and then scanning only them, which is much faster) + # (Applying nmap to a whole network is very time-consuming, + # because nmap waits for a certain timeout period on non-existing + # hosts, so we get a lists of existing hosts by pinging the + # broadcast addresses for existing hosts and then scanning only + # them, which is much faster) my @hostips = getIPsInLocalNetworks(); return () if $#hostips < 0; my $hostlist = join " ", @hostips; @@ -194,25 +219,36 @@ sub whatNetPrinter { # delays caused by machines blocking their ports with a firewall local *F; open F, ($::testing ? "" : "chroot $::prefix/ ") . - qq(/bin/sh -c "export LC_ALL=C; nmap -r -P0 --host_timeout 400 --initial_rtt_timeout 200 -p $portlist $hostlist" |) + qq(/bin/sh -c "export LC_ALL=C; nmap -r -P0 --host_timeout $timeout --initial_rtt_timeout $irtimeout -p $portlist $hostlist" 2> /dev/null |) or return @res; - my ($host, $ip, $port, $modelinfo) = ("", "", "", ""); + my ($host, $ip, $port, $modelinfo, $namechecked) = ("", "", "", "", 0); while (my $line = <F>) { chomp $line; # head line of the report of a host with the ports in question open - #if ($line =~ m/^\s*Interesting\s+ports\s+on\s+(\S*)\s*\(([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\)\s*:\s*$/i) { - if ($line =~ m/^\s*Interesting\s+ports\s+on\s+(\S*)\s*\((\S+)\)\s*:\s*$/i) { + if (($line =~ m/^\s*Interesting\s+ports\s+on\s+(\S*)\s*\((\S+)\)\s*:\s*$/i) || + ($line =~ m/^\s*Interesting\s+ports\s+on\s+(\S+)\s*:\s*$/i)) { ($host, $ip) = ($1, $2); + $ip = $host if !$ip; $host = $ip if $host eq ""; $port = ""; + $namechecked = 0; undef $modelinfo; } elsif ($line =~ m!^\s*(\d+)/\S+\s+open\s+!i) { next if $ip eq ""; $port = $1; - + + # Check integrity of the host name (work around DNS problems + # by using IP if host name is broken) + if (!$namechecked && ($host ne $ip)) { + $namechecked = 1; # Do not check more than once + my $packedip = gethostbyname("$host"); + my ($a,$b,$c,$d) = unpack('C4',$packedip); + my $ipfromdns = sprintf("%d.%d.%d.%d", $a, $b, $c, $d); + $host = $ip if $ip ne $ipfromdns; + } # Now we have all info for one printer # Store this auto-detection result in the data structure @@ -224,7 +260,7 @@ sub whatNetPrinter { foreach my $share (@shares) { push @res, { port => "smb://$host/$share->{name}", val => { CLASS => 'PRINTER', - MODEL => N("Unknown Model"), + MODEL => N("Unknown model"), MANUFACTURER => "", DESCRIPTION => $share->{description}, SERIALNUMBER => "" @@ -260,7 +296,7 @@ sub getNetworkInterfaces() { local *IFCONFIG_OUT; open IFCONFIG_OUT, ($::testing ? "" : "chroot $::prefix/ ") . - '/bin/sh -c "export LC_ALL=C; ifconfig" |' or return (); + '/bin/sh -c "export LC_ALL=C; ifconfig" 2> /dev/null |' or return (); while (my $readline = <IFCONFIG_OUT>) { # New entry ... if ($readline =~ /^(\S+)\s/) { @@ -291,7 +327,7 @@ sub getIPsOfLocalMachine() { local *IFCONFIG_OUT; open IFCONFIG_OUT, ($::testing ? "" : "chroot $::prefix/ ") . - '/bin/sh -c "export LC_ALL=C; ifconfig" |' or return (); + '/bin/sh -c "export LC_ALL=C; ifconfig" 2> /dev/null |' or return (); while (my $readline = <IFCONFIG_OUT>) { # New entry ... if ($readline =~ /^(\S+)\s/) { @@ -328,57 +364,90 @@ sub getIPsInLocalNetworks() { # Read the output of "ifconfig" to determine the broadcast addresses of # the local networks my $dev_is_localnet = 0; - my @local_bcasts; - my $current_bcast = ""; - + my $local_nets = {}; + my $dev; local *IFCONFIG_OUT; open IFCONFIG_OUT, ($::testing ? "" : "chroot $::prefix/ ") . - '/bin/sh -c "export LC_ALL=C; ifconfig" |' or return (); + '/bin/sh -c "export LC_ALL=C; ifconfig" 2> /dev/null |' or return (); while (my $readline = <IFCONFIG_OUT>) { # New entry ... if ($readline =~ /^(\S+)\s/) { - my $dev = $1; + $dev = $1; # ... for a local network (eth = ethernet, # vmnet = VMWare, # ethernet card connected to ISP excluded)? $dev_is_localnet = $dev =~ /^eth/ || $dev =~ /^vmnet/; - # delete previous address - $current_bcast = ""; } - # Are we in the important line now? - if ($readline =~ /\sBcast:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\s/) { - # Rip out the broadcast IP address - $current_bcast = $1; - - # Are we in an entry for a local network? - if ($dev_is_localnet == 1) { - # Store current IP address - push @local_bcasts, $current_bcast; + if ($dev_is_localnet) { + # Are we in the important line now? + if ($readline =~ /\saddr:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\s/) { + # Rip out the broadcast IP address + $local_nets->{$dev}{ip} = $1; + } + if ($readline =~ /\sBcast:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\s/) { + # Rip out the broadcast IP address + $local_nets->{$dev}{bcast} = $1; + } + if ($readline =~ /\sMask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\s/) { + # Rip out the broadcast IP address + $local_nets->{$dev}{mask} = $1; } } } close(IFCONFIG_OUT); + # Now find all addresses in the local networks which we will investigate my @addresses; - # Now ping all broadcast addresses and additionally "nmblookup" the - # networks (to find Windows servers which do not answer to ping) - foreach my $bcast (@local_bcasts) { - local *F; - open F, ($::testing ? "" : "chroot $::prefix/ ") . - qq(/bin/sh -c "export LC_ALL=C; ping -w 1 -b -n $bcast | cut -f 4 -d ' ' | sed s/:// | egrep '^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+' | uniq | sort" |) - or next; - local $_; - while (<F>) { chomp; push @addresses, $_ } - close F; - if (-x "/usr/bin/nmblookup") { + foreach $dev (keys %{$local_nets}) { + my $ip = $local_nets->{$dev}{ip}; + my $bcast = $local_nets->{$dev}{bcast}; + my $mask = $local_nets->{$dev}{mask}; + if ($mask =~ /255.255.255.(\d+)/) { + # Small network, never more than 255 boxes, so we return + # all addresses belonging to this network, without pinging + my $lastnumber = $1; + my $masknumber; + if ($lastnumber < 128) { + $masknumber = 24; + } elsif ($lastnumber < 192) { + $masknumber = 25; + } elsif ($lastnumber < 224) { + $masknumber = 26; + } elsif ($lastnumber < 240) { + $masknumber = 27; + } elsif ($lastnumber < 248) { + $masknumber = 28; + } elsif ($lastnumber < 252) { + $masknumber = 29; + } elsif ($lastnumber < 254) { + $masknumber = 30; + } elsif ($lastnumber < 255) { + $masknumber = 31; + } else { + $masknumber = 32; + } + push @addresses, "$ip/$masknumber"; + } else { + # Big network, probably more than 255 boxes, so ping the + # broadcast address and additionally "nmblookup" the + # networks (to find Windows servers which do not answer to ping) local *F; open F, ($::testing ? "" : "chroot $::prefix/ ") . - qq(/bin/sh -c "export LC_ALL=C; nmblookup -B $bcast \\* | cut -f 1 -d ' ' | egrep '^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+' | uniq | sort" |) + qq(/bin/sh -c "export LC_ALL=C; ping -w 1 -b -n $bcast 2> /dev/null | cut -f 4 -d ' ' | sed s/:// | egrep '^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+' | uniq | sort" |) or next; local $_; - while (<F>) { - chomp; - push @addresses, $_ if !(member($_,@addresses)); + while (<F>) { chomp; push @addresses, $_ } + close F; + if (-x "/usr/bin/nmblookup") { + local *F; + open F, ($::testing ? "" : "chroot $::prefix/ ") . + qq(/bin/sh -c "export LC_ALL=C; nmblookup -B $bcast \\* 2> /dev/null | cut -f 1 -d ' ' | egrep '^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+' | uniq | sort" |) + or next; + local $_; + while (<F>) { + chomp; + push @addresses, $_ if !(member($_,@addresses)); + } } } } @@ -392,7 +461,7 @@ sub getSMBPrinterShares { # SMB request to auto-detect shares local *F; open F, ($::testing ? "" : "chroot $::prefix/ ") . - qq(/bin/sh -c "export LC_ALL=C; smbclient -N -L $host" |) or return (); + qq(/bin/sh -c "export LC_ALL=C; smbclient -N -L $host" 2> /dev/null |) or return (); my $insharelist = 0; my @shares; while (my $l = <F>) { @@ -424,9 +493,9 @@ sub getSNMPModel { # SNMP request to auto-detect model local *F; open F, ($::testing ? $::prefix : "chroot $::prefix/ ") . - qq(/bin/sh -c "scli -v 1 -c 'show printer info' $host" |) or + qq(/bin/sh -c "scli -v 1 -c 'show printer info' $host" 2> /dev/null |) or return { CLASS => 'PRINTER', - MODEL => N("Unknown Model"), + MODEL => N("Unknown model"), MANUFACTURER => "", DESCRIPTION => "", SERIALNUMBER => "" @@ -453,7 +522,43 @@ sub getSNMPModel { # Was there a manufacturer and a model in the output? # If not, get them from the description if ($manufacturer eq "" || $model eq "") { - if ($description =~ /^\s*(\S*)\s+(\S.*)$/) { + # Replace bad description + if ((length($description) < 5) && + (length($description) >= 5)) { + $description = $model; + } + # Guess manufacturer by model name + if ($description =~ + /^\s*(DeskJet|LaserJet|OfficeJet|PSC|PhotoSmart)\b/i) { + # HP printer + $manufacturer = "HP"; + $model = $description; + } elsif ($description =~ + /^\s*(Stylus|EPL|AcuLaser)\b/i) { + # Epson printer + $manufacturer = "Epson"; + $model = $description; + } elsif ($description =~ + /^\s*(Aficio)\b/i) { + # Ricoh printer + $manufacturer = "Ricoh"; + $model = $description; + } elsif ($description =~ + /^\s*(Optra|Color\s+JetPrinter)\b/i) { + # Lexmark printer + $manufacturer = "Lexmark"; + $model = $description; + } elsif ($description =~ + /^\s*(imageRunner|Pixma|Pixus|BJC|LBP)\b/i) { + # Canon printer + $manufacturer = "Canon"; + $model = $description; + } elsif ($description =~ + /^\s*(Phaser|DocuPrint|(Work|Document)\s*(Home|)Centre)\b/i) { + # Xerox printer + $manufacturer = "Xerox"; + $model = $description; + } elsif ($description =~ /^\s*(\S*)\s+(\S.*)$/) { $manufacturer = $1 if $manufacturer eq ""; $model = $2 if $model eq ""; } @@ -463,7 +568,7 @@ sub getSNMPModel { } # We couldn't determine a model - $model = N("Unknown Model") if $model eq ""; + $model = N("Unknown model") if $model eq ""; # Remove trailing spaces $manufacturer =~ s/(\S+)\s+$/$1/; @@ -485,7 +590,7 @@ sub network_running() { # If the network is not running return 0, otherwise 1. local *F; open F, ($::testing ? $::prefix : "chroot $::prefix/ ") . - '/bin/sh -c "export LC_ALL=C; /sbin/ifconfig" |' or + '/bin/sh -c "export LC_ALL=C; /sbin/ifconfig" 2> /dev/null |' or die 'Could not run "ifconfig"!'; while (my $line = <F>) { if ($line !~ /^lo\s+/ && # The loopback device can have been @@ -506,8 +611,18 @@ sub parport_addr { $device =~ m!^/dev/lp(\d+)$! or $device =~ m!^/dev/printers/(\d+)$!; my $portnumber = $1; + my $i = 0; + my $parportdir; + foreach (sort { $a =~ /(\d+)/; my $m = $1; $b =~ /(\d+)/; my $n = $1; $m <=> $n } `ls -1d /proc/parport/[0-9]* /proc/sys/dev/parport/parport[0-9]* 2>/dev/null`) { + chomp; + if ($i == $portnumber) { + $parportdir = $_; + last; + } + $i++; + } my $parport_addresses = - `cat /proc/sys/dev/parport/parport$portnumber/base-addr`; + `cat $parportdir/base-addr`; my $address_arg; if ($parport_addresses =~ /^\s*(\d+)\s+(\d+)\s*$/) { $address_arg = sprintf(" -base 0x%x -basehigh 0x%x", $1, $2); |