Automate udev file creation

Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

Threaded View

I am trying to put together a script to automate creating a Linux (RHEL5) udev file for the given disks on a system.  Here is what I have:

use strict;
use warnings;

my $logfile     = "disks.log";
my %sizes;

sub write_log

        open(LOG, ">>$logfile") || die "Couldn't open $logfile: $!";
        print LOG @_;
        close LOG;


unlink $logfile,"$.bak";

write_log(`fdisk -l |grep "Disk /dev/s"| awk '{print \$2,\$3}'`);
system (`sed -i.bak s,/dev/,,g $logfile; sed -i.bak s,:,,g $logfile`);

open FH, "$logfile" || die "Couldn't open $logfile: $!";

        while (<FH>) {

                my ($key,$value) = split(/ /);
                $sizes = $value;


foreach my $key (keys %sizes)


        my $wwid = `scsi_id -gus /block/$key`;
        print "Disk $key = $wwid";


The three pieces of information that I need are: Disk, disk size, and wwid.  The above allows me to get what I need (wwid dropped to stout just to test returning it) but ideally I'd like them in a neat, retrievable, variable structure.

I've read about using perlreftut.  Is this what I am looking for?  If so, I'm having trouble understanding what I need to do and how I would output the contents.

Obviously I have to finish the file creating part of the script but I feel I can get that going once I have the values in place.

Any guidance is greatly appreciated,


Re: Automate udev file creation

On 29/9/2015 22:23, wrote:
Quoted text here. Click to load it


Re: Automate udev file creation

 > lsblk -n -l -o NAME,UUID,SIZE,FSTYPE,TYPE

George - Thank your for your reply.  Unfortunately RHEL5 does not include lsblk command.  But I would be more interested in:

lsblk -d | grep disk | awk '{print $1,$4}'

Re: Automate udev file creation

 > On 30/9/2015 03:08, wrote:
Quoted text here. Click to load it

try the following herbert, tested at rhel5 , rhel6 , archlinux

# quick disk info
# George Mpouras
use strict; use warnings;

# /dev/mapper
my %mapper;
my $path = '/dev/mapper';
opendir  DIR, $path or die ":(  $!\n";
foreach my $file ( grep ! /^..?$/, readdir DIR) {
next unless -l "$path/$file";
my $real = readlink("$path/$file") or die ":-/ $!\n";
$real =~s|^..|/dev|;
$mapper         = "$path/$file";
$mapper = $real }
closedir DIR;

# mounts
my %mount;
open FILE,'<','/proc/mounts' or die $!;
close FILE;
foreach (@) {
my ($dev,$mountdir,$fstype)=$_=~/^(\S+)\s+(\S+)\s+(\S+)\s+/ or next;

foreach my $id ('id', 'uuid') {
$path = "/dev/disk/by-$id";
next unless -d $path;
opendir DIR, $path or die "could not read $path $!\n";

    foreach my $alias ( grep ! /^..?$/, readdir DIR) {
    next unless -l "$path/$alias";
    my $device   = readlink("$path/$alias") or die "oh no $!\n";
    $device      =~s|^../..|/dev|;
    my $mountdir = '';
    my $type     = '';
    my $size     = '';
    my $mounted  = 'no';

        if (exists $mount) {
        $mountdir = $mount->[0];
        $type     = $mount->[1];
        elsif (exists $mount) {
        $mountdir = $mount->[0];
        $type     = $mount->[1];

        if ($type ne '') {
        $mounted  = 'yes';
        ($size = qx/df -h $mountdir/ ) =~s/^.*?\s+(\d+\w+)\s+.*/$1/s;

    print "$device,$id=$alias,$type,$size\n"

close DIR

Re: Automate udev file creation

Quoted text here. Click to load it
[snipped unneccessary code]
Quoted text here. Click to load it

perlreftut should get you where you want to be, which bits are you  
having trouble with?

... I seem to have got a bit carried away below. If you want to figure  
it our for yourself please ask about the areas of perlreftut you're  
stuck on, and don't read on!

With regard to your code, there's no need to write the output of your  
commands to a file and then read that file. This should get the data
you require, and doing so in a loop allows you to process date as you  
collect it:

for (`/sbin/fdisk -l`) {
    next unless m{^Disk /dev/s};
    my (undef, $dev_id, $size) = split;
    $dev_id =~ s|/dev/||g; # [see note below]
    my $wwid = `scsi_id -gus /block/$dev_id`;

Note: I'm not sure the /g is needed on the regex substitution, I've not
got SCSI disks or a recent RHEL to see the output of the fdisk command.

There may be perl modules that can interface with the hardware and not
require the backtick capturing, I've not looked.  

Prepend the above with your hash declaration:

my %sizes;
for (`/sbin/fdisk -l`) {
    next unless m{^Disk /dev/s};
    my (undef, $dev_id, $size) = split;
    my $wwid = `scsi_id -gus /block/$dev_id`;
    ... assign here...

You have a hash (%sizes, empty so far), want it to be keyed by the  
device ID, and the values to be hashes keyed by size and wwid with  
those values from the variables you've collected. Those 'second level'
hashes will have to be references to hashes because a hash value must  
be a scalar, it can't be a list or a hash. A reference to an anonymous  
hash is, conveniently, a scalar. So you could:

my %second_level_hash = (
    size => $size,
    wwid => $wwid,

and then:
$sizes{ $dev_id } = \%second_level_hash;  # take ref to 2nd level hash

... but that's not very perlish, the perlish way would be to assign an
anonymous hash directly as the value to your key:

$hash{ $key } = {
    key1 => $value1,
    key2 => $value2,

Putting that all together should result in something like:

my %sizes;
for (`/sbin/fdisk -l`) {
    next unless m{^Disk /dev/s};
    my (undef, $dev_id, $size) = split;
    my $wwid = `scsi_id -gus /block/$dev_id`;
    $sizes{ $dev_id } = {
        wwid => $wwid,
        size => $size,

Now you have everything in that nice tidy data structure you wanted, and  
no files written.  

You can access your data:

for my $key (keys %sizes) {
    print "Size of device $key is $sizes{ $key }->\n";


Justin C, by the sea.

Re: Automate udev file creation

George and Justin - Thank you very much for your guidance.  I was able to get my script working with your help. Thanks again.


Site Timeline