Re: Détection carte CF

Top Page

Reply to this message
Author: Edgar Bonet
Date:  
To: guilde
Subject: Re: Détection carte CF
Le lundi 8 octobre, Frédéric Mantegazza a écrit :
> De toute façon, si je branche une clé, puis mon APN, les ports sont
> décalés, non ? Donc l'automatisation requière quand même de réfléchir,
> et de faire les choses dans le bon ordre.


Si tu nommes le point de montage comme le label du filesystem, alors tu
n'as plus à faire attention à l'ordre de branchement. Par exemple, chez
moi j'ai :

  - /mnt/CLEF_EDGAR : ma clef USB
  - /mnt/NIKON_D70  : la carte CF de mon APN vue via un lecteur
  - /mnt/backup     : disque externe de sauvegarde
  - /mnt/shuttle    : disque « navette » labo / maison


et ce, quel que soit l'ordre de branchement. C'est bien pratique.

Enfin, ça marchait très bien comme ça sous Mandriva 2006.0. Depuis
2007.0 ça n'a plus l'air de marcher que sous KDE ou Gnome. Et j'aime pas
KDE ni Gnome. Du coup je me suis fait un petit script (que je joins ici)
qui fait en gros la même chose. À installer suid root. Malheureuseemnt
je n'ai pas compris comment faire appeler ça automatiquement par udev.
:-(

> Pour essayer de comprendre : qui, ici, utilise un lecteur de cartes en
> USB ? Est-ce que tous ceux qui en ont un pourrait faire le test (sous
> udev, bien sûr), pour voir si la carte est bien détectée lorsqu'on
> l'insère alors que le lecteur est déjà branché ?


Je fais toujours comme ça et ça marche.

Edgar.
#!/usr/bin/perl -w -T

# update_fstab: Arrange for removable mass-storage devices (like USB
# keys) to be mountable by user:
# - create mountpoints named like the volume labels
# - add the relevant lines to /etc/fstab
# - undo when the device is no longer connected
#
# Athor: Edgar Bonet
#
# Version: 1.5, 2007-07-18
#
# TODO:
# - find a way to call this from udev

$help = "Usage: update_fstab [-v|--verbose] [-n|--dry-run] [-h|--help]\n";

# drakupdate_fstab used
# "umask=0,users,iocharset=iso8859-1,sync,codepage=850,noauto,exec"
# minimalist: "noauto,user,sync"
$fsoptions = "noauto,user,exec,sync";

# Security
foreach $var ('PATH', 'IFS', 'ENV') { delete($ENV{$var}); }

# Options
$verbose = 0;
$dry_run = 0;
foreach $opt (@ARGV) {
    if ($opt eq '-v' or $opt eq '--verbose') { $verbose = 1; next; }
    if ($opt eq '-n' or $opt eq '--dry-run') { $dry_run = 1; next; }
    if ($opt eq '-h' or $opt eq '--help') { print $help; exit; }
    print STDERR $help; exit;
}


$rewrite_fstab = 0;

# List devices like /dev/sd[a-z]*
@devs = glob('/dev/sd[a-z]*');
%devexists = ();
foreach $dev (@devs) {
    $dev =~ m|^(/dev/sd[a-z][0-9]{0,2})$| or die "Weird device: $dev\n";
    $dev = $1;  # untaint
    $devexists{$dev} = 1;
}
if ($verbose) {
    print "*** sd devices found:\n";
    foreach $dev (@devs) {
        print "\t$dev\n";
    }
}


# Find directories in /mnt
%mountpoint = ();
foreach $mtpt (glob('/mnt/*')) { $mountpoint{$mtpt} = 1; }
if ($verbose) {
    print "*** Directories in /mnt:\n";
    foreach $mtpt (keys %mountpoint) {
        print "\t$mtpt\n";
    }
}


# Parse /etc/fstab
$fstab_text = "";
%fstab = ();
%invfstab = ();
open(FSTAB, '/etc/fstab') or die "Could not read /etc/fstab: $!\n";
while (<FSTAB>) {
    $fstab_text .= $_;
    @field = split / +/;
    $fstab{$field[0]} = $field[1];
    $invfstab{$field[1]} = $field[0];
}
close(FSTAB);
if ($verbose) {
    print "*** /etc/fstab:\n";
    foreach $dev (keys %fstab) {
        $mtpt = $fstab{$dev};
        print "\t[$dev] -> [$mtpt]\n";
    }
}


# Add fstab lines
if ($verbose) { print "*** Lines added to /etc/fstab:\n"; }
foreach $dev (@devs) {
    next if $fstab{$dev};


    $extraoptions = "";


    # Look for fs label
    $file = `/usr/bin/file -s $dev`;


    # Known filesystem?
    if ($file =~ / FAT \(\d+ bit\)/) {
        $extraoptions = ",dmask=022,fmask=133";
        if ($file =~ /label: "([^"]+?)\s*", FAT/) {
            $name = $1;
        } else {
            $name = 'removable';
        }
    }
    elsif ($file =~ /\bext[23] filesystem\b/) {
        $dump = `/sbin/dumpe2fs -h $dev`;
        if ($dump =~ /\bvolume name: +(\S+)\n/) {
            $name = $1;
        } else {
            $name = 'removable';
        }
    }
    else {
        if ($verbose) { print "\t($dev not a filesystem)\n"; }
        next;   # not a known filesystem
    }


    $name =~ s/[^a-zA-Z0-9_+-]/_/g;     # sanitize name
    $mtpt = "/mnt/$name";


    # Add a digit if mountpoint already used
    $count = 1;
    while ($invfstab{$mtpt}) {
        $mtpt = "/mnt/$name$count";
        $count++;
    }


    # Modify /etc/fstab
    $extra_line = "$dev $mtpt auto $fsoptions$extraoptions 0 0\n";
    $fstab_text .= $extra_line;
    $fstab{$dev} = $mtpt;
    $invfstab{$mtpt} = $dev;
    $rewrite_fstab = 1;
    if ($verbose) { print "\t$extra_line"; }


    # Create directory if needed
    unless ($mountpoint{$mtpt}) {
        if ($verbose) { print "+++ created $mtpt\n"; }
        unless ($dry_run) {
            mkdir($mtpt) or warn "Could not create $mtpt\n";
        }
        $mountpoint{$mtpt} = 1;
    }
}


# Remove fstab lines
if ($verbose) { print "*** Removed from /etc/fstab:\n"; }
foreach $dev (keys %fstab) {
    next unless $dev =~ /\/dev\/sd??/;
    next if $devexists{$dev};
    if ($verbose) { print "\t$dev\n"; }


    $fstab_text =~ s/^$dev .*\n//m;
    delete($invfstab{$fstab{$dev}});
    delete($fstab{$dev});


    $rewrite_fstab = 1;
}


# Write back /etc/fstab
if ($rewrite_fstab) {
    if ($verbose) {
        print "*** /etc/fstab rewritten as follows:\n";
        print "====================================\n";
        print $fstab_text;
        print "====================================\n";
    }
    unless ($dry_run) {
        open(FSTAB, '>/etc/fstab')
            or die "Could not open /etc/fstab for writing: $!\n";
        print FSTAB $fstab_text
            or die "Could not write to /etc/fstab: $!\n";
        close(FSTAB)
            or die "Problem closing /etc/fstab: $!\n";
    }
}


# Remove useless directories
if ($verbose) { print "*** Deleted directories:\n"; }
foreach $mtpt (keys %mountpoint) {
    next if $invfstab{$mtpt};
    if ($verbose) { print "\t$mtpt\n"; }
    unless ($dry_run) {
        rmdir($mtpt) or warn "Could not remove $mtpt: $!\n";
    }
}