#! /usr/bin/perl -w # Read syslog to find when each USB or MMC drive was attached # If it gets removed and re-attached, only the last one counts. # If it was attached so long ago that the event is # no longer visible in syslog, this approach fails. # If there are more than one such devices, each one # is shown, in order of time of attachment. use strict; use Symbol 'gensym'; use DateTime; my @moname = ("Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec"); my $tz = DateTime::TimeZone::Local->TimeZone(); main: { my %map = (); my $sequence = -1; # keep track of chronological order # Read /dev/disk/by-id # Fairly robust way of finding all usb drives. foo: { my $dh = gensym(); my $dir= '/dev/disk/by-id'; my $simple = $dir; $simple =~ s'/$''; opendir($dh, $dir) || die; # typical thing we are interested in: #> /dev/disk/by-id/usb-SanDisk_Ultra_4C531001640417112401-0:0 -> ../../sdb #> /dev/disk/by-id/mmc-SL64G_0x436a2d8a -> ../../mmcblk0 # # and in contrast, not interested in: #> /dev/disk/by-id/usb-USB_2.0_USB_Flash_Drive_2cf51c40bc0343-0:0-part1 -> ../../sdc1 while(my $entry = readdir $dh) { if ($entry =~ m'^(usb|mmc)' && $entry !~ m'-part[0-9]*$') { my $fn = "$simple/$entry"; my $target = readlink $fn; if (defined $target) { #### print "$fn -> $target\n"; my $rslt = {}; my @status = stat $fn; my $ctime = $status[10]; $target =~ s'[./]*''; $rslt->{drive} = $target; $rslt->{date} = format_date($ctime); $rslt->{seq} = $ctime; $map{$target} = $rslt; } # else not a symlink, should never happen } } closedir $dh; } # sort so that they come out in chronological order: for my $drive (sort {${$map{$a}}{seq} <=> ${$map{$b}}{seq}} keys %map) { my $rslt = $map{$drive}; my $special = "/dev/$rslt->{drive}"; if (-b $special) { my $cmd = "blockdev --getsz $special"; my $pipe = gensym(); open ($pipe, '-|', $cmd) || die "Cannot pipe from '$cmd' : $!\n"; my $size = <$pipe>; if (close $pipe) { $size /= 2; # convert from sectors to kiB $size /= 1024; # convert to MiB } else { $size = '???'; # probably "permission denied" # when trying to do --getsz } my $s1 = "DISK=$special"; my $s2 = "DISKsize__MiB=$size"; my $s3 = "DISKdate='$rslt->{date}'"; printf ("%-20s %-20s %s\n", $s1, $s2, $s3); } } } sub format_date{ my ($epoch) = @_; my $dt = DateTime->from_epoch( epoch => $epoch, time_zone => $tz); my $year = $dt->year; my $month = $dt->mon; # 1-12 - you can also use '$dt->mon' my $day = $dt->day; # 1-31 - also 'day_of_month', 'mday' my $dow = $dt->day_of_week; # 1-7 (Monday is 1) - also 'dow', 'wday' my $hour = $dt->hour; # 0-23 my $minute = $dt->minute; # 0-59 - also 'min' my $second = $dt->second; # 0-61 (leap seconds!) - also 'sec' my $doy = $dt->day_of_year; # 1-366 (leap years) - also 'doy' my $doq = $dt->day_of_quarter; # 1.. - also 'doq' my $qtr = $dt->quarter; # 1-4 my $ymd = $dt->ymd; # 1974-11-30 $ymd = $dt->ymd('/'); # 1974/11/30 - also 'date' my $hms = $dt->hms; # 13:30:00 # $hms = $dt->hms('|'); # 13|30|00 - also 'time' return "$moname[$month-1] $day $hms"; }