DrakX Specification for Linux-Mandrake 8.0

Current team of Install group is :

gc
damien
fpons
pixel


  Boot process (stage1)

    Installation begin by booting from CD-ROM or Diskette. From CD-ROM all
installation method are available (CD, HD, NFS, FTP, HTTP) on options. From
Diskette according to image selected, only some related method (network or cdrom
or hd) are available and module managed due to size limitation to 1.44Mb.
    Options are always available by pressing on F1.

  DrakX process (stage2)

    DrakX installation organized in steps (execution sequence described below).
Steps listed on left side and help available on bottom right side. most of the
screen is available for various dialog for interacting with the user. Steps
execution sequence is automated and described below.

Mouse is probed and if none has been found or if the mouse has not moved, a
specific mouse configuration is displayed at the begining.


Before the graphical steps, there is a detection step. It detects various
hardware, including modems (from tty0 to tty7), mouse (serial, usb, ps/2) and
tablets.

    Steps

      Choose Your language: step always displayed. default choice is previous one or
English. After choosing a language, a license splash screen translated in the
chosen language is displayed with Accept and Refuse buttons. Refuse should
stop installation. Accept validate language choice which are propagated to all
DrakX visible widget. Advanced mode allow to select other language available to
be installed. Advanced mode allow to select language which will be installed on
system.
      If step is redone, the license is no more displayed.

      Select Install Class: step always displayed. default choice is previous one
or Recommended. Only one other option available is Customized. Two buttons
available are Install or Upgrade. Available steps (left side) are changed
according to installation class selected, where the default is the one of
Recommended with Install.

      Hard Drive Detection: step always displayed. In recommended mode,
automatically done. In Customized mode, all modules that manage SCSI/IDE cards
are loaded automatically and a question asking for other module to load is
displayed.
      If clicked later or if to the question to load other module the
answer is Yes, a list of module is displayed (or if the question to other
module to load is. When a module is chosen, two options are available
Autoprobe and Specify options. Autoprobe try to load the module without any
other user options (default module parameter). Specify options allow user to
give module parameters individually in a list for all known parameters. At this
point Ok or Cancel are available, Cancel should stop the module installation
and go to next step. If any error occurs during module installation, a question
asking to try with other parameter is displayed, the same module is still used.

      Setup filesystems: step always displayed. display a list of available choice
accoding to what has been probed. May contains Use free space, "Use existing
partition, Use the window partition for loopback, Use the free space on the
Windows partition, Remove Windows(TM)|Erase entire disk" (according to disk
configuration => only one big fat for the first case only), "Custom disk
partitioning".
      If Use free space mode, auto allocation in available on available disk.
      If Use existing partition mode, a list of partition named in Linux
scheme are displayed with their approximate size in Mb and propose mount point
to choose in list boxes for each partitions available on hard drive.
      If Use the window partition for loopback mode, DrakX use available size
on the windows partition to create a root file and a swap file which will be
used in loopback, this means this is a lnx4win installation.
      If Use the free space on the Windows partition mode, DrakX will resize
the windows partition and allocate true linux filesystem (at least / and swap).
      If Remove Windows(TM)|Erase entire disk mode, DrakX clean the
partition table before auto allocating partition.
      If Custom disk partitioning mode, diskdrake is launch. TO BE DEFINED to
change make diskdrake use only advanced mode.
Diskdrake show all partition of all non-removable disk graphically. All special
partition are hidden, only user accessible partition are visible: this remove
extended partition, whole disk partition on sparc platform. Clicking on a disk
notebook tab show all his partitions. Clicking on a partition show all actions
available for this partition (depend if customized or advanced mode) as well as
information on this partition (depend if customized or advanced mode). Most
diskdrake operation are done without writing on disk (exception are Resizing
partitions) and everything is written once on the disk when exiting diskdrake,
at any time if writing partition table is necessary, there are always a dialog
box asking the user to confirm the write. If no operation are modifying
partition table, no dialog is displayed on exit (for example if giving mount
point to partition). General action are available too:
        Clear All: clear all partition of the given disk.
        Auto allocate: try to allocate partition in available disk (not the
seen disk).
        Undo: undo last operation.
        Done: quit and save changes.
Other operations are available in advanced mode:
        Rescue partition table: try to rescue a lost partition table,
absolutely no garantee to succeed and may destroy what could be saveable by
another tools.
        Reload: reload partition table from disk, erasing all changes in
memory done by the user.
        Wizard: go to partition wizard, that the partition filesystems default
behaviour on startup.
        Restore from floppy: restore a partition table from previously saved
partition table from diskdrake.
        Save to floppy: save partition table to floppy.
        Options: global options available for filesystem configuration. This
include Removable media automouting supermount check box disabled by default.
      Operation available on partition are:
        Mount point: change or define mount point for partition, only
available for true filesystem partition.
        Resize: resize partition, if a specific algorithm to keep data is
used no data may be lost, else all data are lost but nothing is written by
diskdrake on the partition data in this last case (this means data can be
restored by restoring original size and location).
        Delete: delete partition, if the same partition is created (same type,
location, size) all data can be restored as diskdrake doesn't write on partition
data.
      Operation available on partition table but in advanced mode are:
        Type: change type of partition, all data will be lost but diskdrake as
above does not destroy them, and everyting can be restored.
        Format: format partition, at this point, all data ARE LOST.
        Mount: mount partition now, usefull for swap to increase memory
capacity for machine low on resource that are not available to complete setup
filesystem step correctly (problably if a resize partition is used on FAT fs).
allow Mounting swap on customized mode too.
      A legend for partition type colors is available
(Ext2,ReiserFS,Swap,FAT,Other,Empty). It has additionnal features to create a
partition or change its type (only available in advanced mode).

      Format partitions: step always displayed. display list of partition to
format with click boxes. Some are defined according to type of partitions and if
the partition has been created or taken back.
If a partition has already been formated, it is not proposed, or if it should
not be proposed (alrady existing partition like /mnt/windows).
On Advanced tag, an additional dialog is displayed to select partition to format
(all available partition listed) and to format them with bad block checking.

      Choose packages: step always displayed. default selection done to be
correct according to size available, Install or Upgrade, Hardware available.
This selection is done according to Mandrake first choice of packages.
On all mode, display groups and main desktop used (KDE or Gnome), an
individual package selection check box is available to allow selecting package
individually. In this case, a dialog displaying a tree with groups, (Mandrake
first choice/alternatives) and packages is shown on the left part, a description
window for each packages is shown on the right part.

      Install system: step always displayed. no interactive and display
installation progression. include if available and on a CD basis a spash screen
of advertising and other (pub!).

      Hardware panel: step always displayed. show current configuration for
Mouse, Keyboard, TimeZone, Graphic/TV Card, Monitor.
At each values chosen (list boxes displayed a
synthesis description) the current dialog is removed from screen and specific
configuration panels are displayed (like currently for mouse, keyboard ...).
And end of these specific configuration panels, this one is remapped on screen
to be accepted in general.

      Sub steps of Hardware panel:

        Configure mouse: displayed on request or if the mouse has not been
moved (so unsafe detection), but have to be displayed earlier. A mouse tree
selection for type is displayed with default case as what is probed or
serial/Generic 2 button Mouse if none has been probed. Cancel disable mouse
modification and Ok allow next mouse configuration dialog. Then comes a serial
port dialog for serial mice (default mouse connected to COM1 if nothing found).
Then a mouse screen control is chown (according to mouse capacity: 3 buttons
with or without mouse, need 7 buttons checking ?). Here Ok validate to go to
next step and Cancel to first mouse dialog displayed (mouse tree selection for
type).

        Configure keyboard: displayed on request. default is set according to
TimeZone definition (itself defaulting to language selection at the beginning).
A list of keyboard is shown to the user and Ok validates change and return to
Hardware panel dialog with enabled change. Cancel abort any modification and
return to the same Hardware panel dialog.

        Configure timezone: displayed on request. default is set according to
language selection. A timezone tree selection is shown with only the subtree
corresponding to the current selection expanded (as other tree dialog). Ok
validates change and return to Hardware panel dialog whereas Cancel avoid
the change before returning to the same main dialog.

        Graphic Card: display graphic card probed. No change available.

        TV Card: display TV/Tuner card probed. No change available.

        Monitor: need execution of ddcxinfos at this point. Only Size, Max
resolution and depth displayed. No change available.


      Miscellaneous step have been removed and dispatched to other steps. "Use
hard drive optimisation and Enable num lock at startup are removed. Choose
security level is moved to security step. Precise RAM size if needed" and
Clean /tmp at each boot are moved to bootloader step.
Removable media automouting is moved to diskdrake options.

      Security: step displayed only in customized mode. TO BE DEFINED. should
display at least securty level to choose. level are Low, Medium, High and
for advanced there are Welcome To Crackers, Poor, Paranoid too.

      Configure networking: step always displayed. dialog always displayed in
both Recommended and Customized mode. A list of network configuration
entries are shown with the following:
        Configure a normal modem connection
        Configure an ISDN connection
        "Configure a DSL (or ADSL) connection
        Configure a cable connection
        Configure local network|Reconfigure local network
        Disable networking|Enable networking
        Done
      By cliking on a specific item, another dialog is displayed to configure
some specific part of the network.
        Configure a normal modem connection: display a question to probe for a
modem if not already detected, then if none are found or probe has been refused
a list of possible serial device are listed (in the form ttySx / COM(x+1) with
the current mouse device removed if it is serial). After that a dialog including
all parameters than can be used is shown. This includes Connection Name,
Phone number, Login ID, Password, Authentication, Domain name, DNS 1
and DNS 2. Authentication is a combo of PAP, Termina-Based and
Script-Based (It seems necessary to get CHAP back on this one, no way of
testing TO BE DEFINED). If no DNS are given, the connection is configured to try
using provider DNS. Ok and Cancel button are available.
        Configure an ISDN connection:
Try to detect some PCI card. If not detected, asks if it's a ISA/pcmcia or PCI
card, and gives the list of the cards. Information are then asked: 
Card IRQ only if ISA/pcmcia
Card mem (DMA) only if ISA/pcmcia
Card IO only if ISA/pcmcia
Card IO_0 only if ISA/pcmcia with io0
Card IO_1 only if ISA/pcmcia with io1
Your personal phone number phone
Provider name (ex provider.net)
Provider phone number
Provider dns 1
Provider dns 2
Dialing mode auto or manual
Account Login (user name)
Account Password hided
Confirm Password again
        Configure a DLS (or ADSL) connection:
The user chooses between pptp, pppoe and dhcp. If dhcp, redirection to LAN.
If there is more than one ethernet card, The user must choose the card to use
(displayed with the module). After that, some informations are asked:
Provider name (ex provider.net)
Provider dns 1
Provider dns 2
Account Login (user name)
Account Password hided
Confirm Password again
        Configure a cable connection: redirection to LAN
        Configure local network: display what has been probed with a question
about using another module and Yes, No and See hardware info buttons.
No is the default. If Yes is clicked a list of modules is displayed with
Ok or Cancel buttons available. Cancel should go back to previous
question. If See hardware info is clicked a list of probed hardware is
displayed. If Yes is clicked, for each ethernet interface, a dialog asking for
IP address, Netmask and Automatic IP check box (DHCP/BOOTP) is displayed. Then
if DHCP has been chosen, only a dialog asking for Host name and another for HTTP
proxy and FTP proxy if any. If DHCP has not been chosen, an IP address has to be
defined and a dialog including Host name, DNS server, Gateway and "Gateway
device" is displayed. Then the same HTTP proxy and FTP proxy dialog as above. As
network configuration may to have been reworked a bit it has TO BE DEFINED if
this is kept like that or not.
        Disable networking|Enable networking is just a way to toggle
networking on or off, may be to be accessible only for advanced mode.
        Quit exit the network step.

NETWORK ADVANCED DOCUMENTATION:
Here is a list of entry points available in post install without using the ugly
install graphic toolkit:

http://www.mandrakesoft.com/~damien/html/draknet_advanced_doc.txt>http://www.mandrakesoft.com/~damien/html/draknet_advanced_doc.txt

      Configure Printer: step always displayed. In recommended mode, only
activated if a local printer is detected, else no printer are configured by
default. In customized mode or if the step has been clicked a list of printer
already configured is displayed and the possibility to add or exit the
configuration. It allow configuration of printers for both LPR and CUPS
individually (available by advanced mode when adding a printer). Printer
protocol managed are local/usb/samba/ncp/lpd for LPR and
local/usb/serial/samba/lpd/cups_network for CUPS.

      Set root password: step always displayed for Install only. In
recommended mode display only a Password entry and a Password (again) entry
to select the root password. In advanced mode, a Use NIS (yellow pages) check
boxes and Use MD5 check box are available. Ok validate root password and "No
password avoid setting a password. No password is only available in Low"
security level or less. The length of the minimal password depend upon security level.

In corporate firewall :
      Set admin password: step always displayed for Install only. It only
      displays a Password entry and a Password (again) entry
to select the admin password. 
The length of the minimal password depend upon security level. (double of the
      security level)

      Add a user: step always displayed for Install Only. In recommend mode
display Real name, User name, Password, Password (again) and icon
choices as graphical. For customized mode a shell combo is available to choose a
specific shell for the user depending on the package installed. The real name is
the user friendly name of the user whereas user name is its login id name. The
box display user that have already been added below the title. Accept user
button allow the creation of the user and Done finish this step. High or
higher security level implies the creation of at least one user. Password length
are subject to same restriction according to security level. In advanced mode,
allow to choose the user in auto login mode.

      Create a boot disk: step always displayed. In recommended mode this
step is automatically done by doing nothing. If clicked or customized mode, the
user is prompted to allow building a boot disk (default is yes). In advanced
mode allow selection of floppy drive.

      Install boot loader: step always displayed. In recommended mode this
step is automatically done. In customized mode, a combo Boot device list the
various boot device that can be used where the bootloader can be installed. The
boot device can the Linux description of the whole disk available (ex: /dev/hda)
or partition available in these disk or floppy drives. Other platform
specificity are not listed here.
      LBA check box is displayed in advanced mode (enabled by default) to
allow using LBA addressing if available (PC with LILO). bootloader combo to
select a given bootloader to use, available choice are Grub, "LILO with text
menu, LILO with graphical menu. default chosen is LILO
with graphical menu. Delay before booting default image" entry
field is available with default value current setting (upgrade) or 5 else.
Precise RAM size if needed (found xx MB) entry is displayed too,
clean /tmp check box is disabled by default too.
Boot in graphical mode (init 5) is available here in advanced mode too
(previously in X configuration). Video mode combo, Password, Password (again),
Restrict command line options check box is displayed.
Video mode combo list text mode and video mode used for frame buffer, video mode
used for frame buffer are available only if the install managed to boot with
frame buffer activated. Password are restricted according to security level as
other password. Password are mandatory according to security level TO BE DEFINED.

      Configure X: step always displayed. By default on recommended mode,
everything is done automatically if possible up to test of graphic card, and if
the user accept the settings no more question are asked to him. In customized
mode a dialog is displayed to choose resolution, color depth and which version
of XFree (with 3D optionally) is available for the current card where only a
short description is displayed. Ok button allow to jump to test phase (for the
first time only) if available. Cancel return to main XFree configuration
window allowing to change Monitor, Graphic card, Server options or Resolution
with X version to choose. Show all extend resolution list to more resolutions
according to card (with onboard memory) only and no more monitor capabilities.
      The main dialog is a list of command to change some X configuration aspect
according to advanced mode or not :
        Change Monitor: display a tree selection of monitors where default one
is selected. Ok and Cancel buttons are available.
        Change Graphic card: display a tree selection of graphic card where
default one is selected. Ok and Cancel buttons are available. If Unlisted
is chosen, then a tree of server/driver is displayed containing available server
for XF3 or driver for XF4. Cancel return to main window and Ok validates
change.
        Change Server options: available only in advanced mode. display list
of check boxes options for server currently used. Ok and Cancel available.
        Change Resolution: change resolution and depth including with X server
version chosen (relative to Xdrakres too).
        Show Information: display an information dialog showing current
configuration internals of X.
        Test again: restart test with current configuration of X.
        Quit: exit X configuration main window. Other question about autologin
and window manager to use are asked on Add user step.

      Exit install: step displayed only in customized mode but always
executed. Only a text is displayed with a Ok button. If clicked and some step
have not been executed/completed correctly, a question dialog ask the user if he
really want to quit now, default answer is No. Advanced switch let user access
to do the previously Auto install floppy step in DrakX < 8.0. This is just a
question asking the user to generate an auto install floppy automatically.
s="hl opt">; 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; $in ||= interactive->vnew; # Install firmware run_program::rooted($::prefix, "mkdir", "-p", "/usr/share/sane/firmware") or 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") or 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") or 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) or 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 open my $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 my $backend; $backend = $1 if $port =~ /^([^:]+):/; # Does the scanner need a firmware file my $firmwareline = firmwareline($backend); # Store collected data push @res, { port => $port, val => { DESCRIPTION => $description, if_($backend, BACKEND => $backend), if_($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(); open my $DETECT, "LC_ALL=C sane-find-scanner -q |"; while (my $line = <$DETECT>) { my ($vendorid, $productid, $make, $model, $description, $port, $driver); my $real_device; 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}; $real_device = $device } else { #warn "Failed to lookup $vendorid and $productid!\n"; } # We have vendor and product ID, look up the scanner in # the usbtable foreach my $entry (common::catMaybeCompressed("$scannerDBdir/usbtable")) { if ($entry =~ /^\s*$vendorid\s+$productid\s+.*"([^"]+)"\s*$/) { $description = $1; $description =~ s/Seiko\s+Epson/Epson/i; if ($description =~ /^([^\|]+)\|(.*)$/) { $make = $1; $model = $2; } last; } } } } elsif ($line =~ /^\s*found\s+SCSI/i) { # SCSI scanner if ($line =~ /"([^"\s]+)\s+([^"]+?)\s+([^"\s]+)"/) { $make = $1; $model = $2; $description = "$make|$model"; } } else { # Comment line in output of "sane-find-scanner" next; } # The Alcatel Speed Touch internet scanner is not supported by # SANE next if $description =~ /Alcatel.*Speed.*Touch|Camera|ISDN|ADSL/i; # Extract port $port = $1 if $line =~ /\s+(\S+)\s*$/; # Check for duplicate (scanner.o/libusb) if ($port =~ /^libusb/) { my $duplicate = 0; foreach (@res) { if ($_->{val}{vendor} eq $vendorid && $_->{val}{id} eq $productid && $_->{port} =~ /dev.*usb.*scanner/ && !defined($_->{port2})) { # Duplicate entry found, merge the entries $_->{port2} = $port; $_->{val}{MANUFACTURER} ||= $make; $_->{val}{MODEL} ||= $model; $_->{val}{DESCRIPTION} ||= $description; $duplicate = 1; last; } } next if $duplicate; } # Store collected data push @res, { port => $port, val => { CLASS => 'SCANNER', MODEL => $model, MANUFACTURER => $make, DESCRIPTION => $description, id => $productid, vendor => $vendorid, driver => $driver, drakx_device => $real_device, } }; } close $DETECT; if (@configured) { # Remove scanners which are already working foreach my $d (@res) { my $searchport1 = handle_configs::searchstr(resolve_symlinks($d->{port})); my $searchport2 = handle_configs::searchstr(resolve_symlinks($d->{port2})); foreach my $c (@configured) { my $currentport = resolve_symlinks($c->{port}); if ($currentport =~ /$searchport1$/ || $searchport2 && $currentport =~ /$searchport2$/) { $d->{configured} = 1; last; } } } @res = grep { ! $_->{configured} } @res; } # blacklist device that have a driver b/c of buggy sane-find-scanner: return grep { member($_->{val}{driver}, qw(scanner unknown usbcore)) } @res; } sub resolve_symlinks { # Check if a given file (either the pure filename or in a SANE device # string as "<prefix>:<file>") is a symlink, if so expand the link. # If the new file name is a link, expand again, until finding the # physical file. my ($file) = @_; my $prefix = ""; if ($file =~ m!^([^/]*)(/.*)$!) { $prefix = $1; $file = $2; } else { return $file; } while (1) { my $ls = `ls -l $file 2> /dev/null`; if ($ls =~ m!\s($file)\s*\->\s*(\S+)\s*$!) { my $target = $2; if ($target !~ m!^/! && $file =~ m!^(.*)/[^/]+$!) { $target = "$1/$target"; } $file = $target; } else { last; } } return $prefix . $file; } sub get_usb_ids_for_port { my ($port) = @_; if ($port =~ /^\s*libusb:(\d+):(\d+)\s*$/) { # Use "lsusb" to find the USB IDs open my $DETECT, "LC_ALL=C lsusb -s $1:$2 |"; while (my $line = <$DETECT>) { if ($line =~ /ID\s+([0-9a-f]+):(0x[0-9a-f]+)($|\s+)/) { # Scanner connected via scanner.o kernel module return "0x$1", "0x$2"; } } } else { # Run "sane-find-scanner" on the port open my $DETECT, "LC_ALL=C sane-find-scanner -q $port |"; while (my $line = <$DETECT>) { if ($line =~ /^\s*found\s+USB\s+scanner/i) { if ($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 return $1, $3; } } } } } sub readconfiglinetemplates { # Read templates for configuration file lines my %configlines; my $backend; foreach my $line (cat_("$scannerDBdir/scannerconfigs")) { chomp $line; if ($line =~ /^\s*SERVER\s+(\S+)\s*$/) { $backend = $1; } elsif ($backend) { push @{$configlines{$backend}}, $line; } } return \%configlines; } sub firmwareline { # Determine whether the given SANE backend supports a firmware file # and return the line needed in the config file my ($backend) = @_; # Read templates for configuration file lines my %configlines = %{readconfiglinetemplates()}; # Does the backend support a line for the firmware? my @firmwarelines = (grep { s/^FIRMWARELINE // } @{$configlines{$backend}}); return join("\n", @firmwarelines); } sub readScannerDB { my ($file) = @_; my ($card, %cards); my $F = common::openFileMaybeCompressed($file); my ($cmd, $val); my $lineno = 0; my $fs = { LINE => sub { push @{$card->{lines}}, "LINE $val" }, SCSILINE => sub { push @{$card->{lines}}, "SCSILINE $val" }, USBLINE => sub { push @{$card->{lines}}, "USBLINE $val" }, PARPORTLINE => sub { push @{$card->{lines}}, "PARPORTLINE $val" }, FIRMWARELINE => sub { push @{$card->{lines}}, "FIRMWARELINE $val" }, NAME => sub { #$cards{$card->{type}} = $card if ($card and !$card->{flags}{unsupported}); $cards{$card->{type}} = $card if $card; $val =~ s/Seiko\s+Epson/Epson/i; $card = { type => $val }; }, SEE => sub { $val =~ s/Seiko\s+Epson/Epson/i; my $c = $cards{$val} or die "Error in database, invalid reference $val at line $lineno"; push @{$card->{lines}}, @{$c->{lines} || []}; add2hash($card->{flags}, $c->{flags}); add2hash($card, $c); }, ASK => sub { $card->{ask} = $val }, SERVER => sub { $card->{server} = $val }, DRIVER => sub { $card->{driver} = $val }, KERNEL => sub { push(@{$card->{kernel}}, $val) }, SCSIKERNEL => sub { push(@{$card->{scsikernel}}, $val) }, USBKERNEL => sub { push(@{$card->{usbkernel}}, $val) }, PARPORTKERNEL => sub { push(@{$card->{parportkernel}}, $val) }, UNSUPPORTED => sub { $card->{flags}{unsupported} = 1 }, MANUAL => sub { $card->{flags}{manual} = 1 }, MANUALREQUIRED => sub { $card->{flags}{manual} = 2 }, COMMENT => sub {}, }; local $_; while (<$F>) { $lineno++; s/\s+$//; /^#/ and next; /^$/ and next; /^END/ and do { $cards{$card->{type}} = $card if $card; last }; ($cmd, $val) = /(\S+)\s*(.*)/ or next; #log::l("bad line $lineno ($_)"), next; my $f = $fs->{$cmd}; $f ? $f->() : log::l("unknown line $lineno ($_)"); } \%cards; } sub updateScannerDBfromUsbtable() { substInFile { s/^END// } "ScannerDB"; my $to_add = "# generated from usbtable by scannerdrake\n"; foreach (cat_("$ENV{SHARE_PATH}/ldetect-lst/usbtable")) { my ($vendor_id, $product_id, $mod, $name) = chomp_(split /\s/,$_,4); next if $mod ne '"scanner"'; $name =~ s/"(.*)"$/$1/; if ($scanner::scannerDB->{$name}) { print "#[$name] already in ScannerDB!\n"; next; } $to_add .= "NAME $name\nDRIVER USB\nCOMMENT usb $vendor_id $product_id\nUNSUPPORTED\n\n"; } $to_add .= "END\n"; append_to_file("ScannerDB", $to_add); } sub updateScannerDBfromSane { my ($sanesrcdir) = @_; substInFile { s/^END// } "ScannerDB"; my $to_add = "# generated from Sane by scannerdrake\n"; # for compat with our usbtable my $sane2DB = { "Acer" => "Acer Peripherals Inc.", "AGFA" => "AGFA-Gevaert NV", "Agfa" => "AGFA-Gevaert NV", "Epson" => "Epson Corp.", "Fujitsu Computer Products of America" => "Fujitsu", "HP" => sub { $_[0] =~ s/HP\s/Hewlett-Packard|/; $_[0] =~ s/HP4200/Hewlett-Packard|ScanJet 4200C/; $_[0] }, "Hewlett-Packard" => sub { $_[0] =~ s/HP 3200 C/Hewlett-Packard|ScanJet 3200C/ or $_[0] = "Hewlett-Packard|$_[0]"; $_[0] }, "Hewlett Packard" => "Hewlett-Packard", "Kodak" => "Kodak Co.", "Mustek" => "Mustek Systems Inc.", "NEC" => "NEC Systems", "Nikon" => "Nikon Corp.", "Plustek" => "Plustek, Inc.", "Primax" => "Primax Electronics", "Siemens" => "Siemens Information and Communication Products", "Trust" => "Trust Technologies", "UMAX" => "Umax", "Vobis/Highscreen" => "Vobis", }; # Read templates for configuration file lines my %configlines = %{readconfiglinetemplates()}; foreach my $ff (glob_("$sanesrcdir/doc/descriptions/*.desc"), glob_("$sanesrcdir/doc/descriptions-external/*.desc"), "UNSUPPORTED") { my $f = $ff; # unsupported.desc must be treated separately, as the list of # unsupported scanners in SANE is out of date. next if $f =~ /unsupported.desc$/; # Treat unsupported.desc in the end $f = "$sanesrcdir/doc/descriptions/unsupported.desc" if ($f eq "UNSUPPORTED"); my $F = common::openFileMaybeCompressed($f); $to_add .= "\n# from $f"; my ($lineno, $cmd, $val) = 0; my ($name, $intf, $comment, $mfg, $backend); my $fs = { backend => sub { $backend = $val }, mfg => sub { $mfg = $val; $name = undef },#bug when a new mfg comes. should called $fs->{ $name }(); but ?? model => sub { unless ($name) { $name = $val; return } $name = exists $sane2DB->{$mfg} ? ref($sane2DB->{$mfg}) ? $sane2DB->{$mfg}($name) : "$sane2DB->{ $mfg }|$name" : "$mfg|$name"; # When adding the unsupported scanner models, check # whether the model is not already supported. To # compare the names ignore upper/lower case. my $searchname = quotemeta($name); if ($backend =~ /unsupported/i && $to_add =~ /^NAME $searchname$/im) { $to_add .= "# $name already supported!\n"; } else { # SANE bug: "snapscan" calls itself "SnapScan" $backend =~ s/SnapScan/snapscan/g; $to_add .= "\nNAME $name\nSERVER $backend\nDRIVER $intf\n"; # Go through the configuration lines of # this backend and add what is needed for the # interfaces of this scanner foreach my $line (@{$configlines{$backend}}) { my $i; $i = $1 if $line =~ /^\s*(\S*?)LINE/; if (!$i || $i eq "FIRMWARE" ||