#!/usr/bin/perl -W #------------------------------------------------------------------------------- # ls.pl (C) 2003 T.Birnthaler OSTC GmbH # Emulation des UNIX-Kommandos "ls" (mit den Optionen "-d" "-F" "-i" "-l"). #------------------------------------------------------------------------------- # TODO: # * Name von Verzeichnis mit "/" davor und ":" dahinter vor Dateien ausgeben. # * "insgesamt"/"total"-Zeile ausgeben (überhaupt sinnvoll???) # DONE: # * Bei Executables Farbe grün statt rot # * Option "-F" hinzufügen # * Farben analog "ls" # * Link-Ziel mit "->" davor ausgeben. # * Verzeichnis durch seinen Inhalt ersetzen. #------------------------------------------------------------------------------- use strict; use POSIX qw(strftime); # Datum+Zeit formatiert use Fcntl ':mode'; # Datei-Typ+Rechte-Konstanten use Term::ANSIColor qw/ :constants /; # Farb-Konstanten use Getopt::Std; # Optionen erkennen # Globale Variablen my %passwd; # Abbildung UID -> Username my %group; # Abbildung GID -> Gruppenname my $opt; # Aktuelle Option während Optionserkennung my $dir_opt; # Option "-d" angegeben? my $flag_opt; # Option "-F" angegeben? my $inode_opt; # Option "-i" angegeben? my $long_opt; # Option "-l" angegeben? my @FILES; # Liste der auszugebenden Dateinamen # Datei "passwd" einlesen und Abbildung UID -> Username erzeugen open PASSWD, "< /etc/passwd" or die "cannot open '/etc/passwd'\n"; foreach () { my ($name, $uid) = (split(":"))[0,2]; $passwd{$uid} = $name; } close PASSWD; # Datei "group" einlesen und Abbildung GID -> Gruppenname erzeugen open GROUP, "< /etc/group" or die "cannot open '/etc/group'\n"; while () { my ($name, $gid) = (split(":"))[0,2]; $group{$gid} = $name; } close GROUP; # Optionen erkennen my %opts; getopts('dFil', \%opts); $dir_opt = 1 if ($opts{"d"}); $flag_opt = 1 if ($opts{"F"}); $inode_opt = 1 if ($opts{"i"}); $long_opt = 1 if ($opts{"l"}); # Keine Argumente? -> aktuelles Verzeichnis auflisten @ARGV = (".") if (@ARGV == 0); # Verzeichnisse in ihren Inhalt umwandeln (nicht -d)? if (not $dir_opt) { foreach (@ARGV) { if (-d) { push @FILES, glob "$_/*" } else { push @FILES, $_; } } @ARGV = sort @FILES; } # Alle Argumente abarbeiten foreach (@ARGV) { my $type; my $rights; # Inode zu Datei einlesen (nicht "stat", sonst wird symbolischer Link aufgelöst) my ($dev, $inode, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) = lstat $_; s#.*/##; $type = &FileType($mode); $rights = &FileRights($mode); # Inode-Nummer (-i)? printf("%7d ", $inode) if ($inode_opt); # Langes Format (-l)? # -> Dateityp, Rechte, Anzahl Links, Besitzer, Besitzergruppe, # Dateigröße/Device Numbers, Datum ausgeben if ($long_opt) { printf("%1s%9s %4d %-8s %-8s ", $type, $rights, $nlink, $passwd{$uid}, $group{$gid}); if ($type eq "b" or $type eq "c") { printf("%3d,%4d ", $rdev / 256, $rdev % 256); } else { printf("%8d ", $size); } print strftime("%Y-%m-%d %H:%M ", localtime($mtime)); } # Dateinamen in richtiger Farbe ausgeben print &FileColor($type, $rights), $_, RESET; # Link erkennen und Pfeil sowie Linkziel mit der richtigen Farbe ausgeben if ($long_opt and $type eq "l") { print " -> ", &LinkColor($_), readlink $_, RESET; } # Dateiname mit Flag am Ende kennzeichnen (-F)? print &FileFlag($_) if ($flag_opt); print "\n"; } #------------------------------------------------------------------------------- # Dateityp ermitteln #------------------------------------------------------------------------------- sub FileType { my $mode = shift; return "l" if S_ISLNK($mode); # Zuerst! return "-" if S_ISREG($mode); return "d" if S_ISDIR($mode); return "b" if S_ISBLK($mode); return "c" if S_ISCHR($mode); return "p" if S_ISFIFO($mode); return "s" if S_ISSOCK($mode); return "?"; } #------------------------------------------------------------------------------- # Dateirechte ermitteln #------------------------------------------------------------------------------- sub FileRights { my $mode = shift; my $rights; # Links = Benutzer-Rechte + SetUserID-Recht $rights = ($mode & S_IRUSR) ? "r" : "-"; $rights .= ($mode & S_IWUSR) ? "w" : "-"; $rights .= ($mode & S_IXUSR) ? ($mode & S_ISUID) ? "s" : "x" : ($mode & S_ISUID) ? "S" : "-"; # Mitte = BenutzerGruppen-Rechte + SetGroupID-Recht $rights .= ($mode & S_IRGRP) ? "r" : "-"; $rights .= ($mode & S_IWGRP) ? "w" : "-"; $rights .= ($mode & S_IXGRP) ? ($mode & S_ISGID) ? "s" : "x" : ($mode & S_ISGID) ? "S" : "-"; # Rechts = "Others"-Rechte + Sticky-Recht $rights .= ($mode & S_IROTH) ? "r" : "-"; $rights .= ($mode & S_IWOTH) ? "w" : "-"; $rights .= ($mode & S_IXOTH) ? ($mode & S_ISVTX) ? "t" : "x" : ($mode & S_ISVTX) ? "T" : "-"; return $rights; } #------------------------------------------------------------------------------- # Farbe abhängig vom Datei-Typ ermitteln. #------------------------------------------------------------------------------- sub FileColor { my ($type, $rights) = @_; if ($type eq "-") { if ($rights =~ "x") { return GREEN; } else { return BLACK; } } elsif ($type eq "d") { return BLUE; } elsif ($type eq "l") { if (not -e readlink $_) { return RED, ON_BLACK; } else { return CYAN; } } elsif ($type eq "b") { return YELLOW, ON_BLACK; } elsif ($type eq "c") { return YELLOW, ON_BLACK; } elsif ($type eq "p") { return YELLOW, ON_BLACK; } elsif ($type eq "s") { return GREEN; } return ""; } #------------------------------------------------------------------------------- # Linkfarbe abhängig vom Datei-Typ ermitteln. #------------------------------------------------------------------------------- sub LinkColor { my $file = shift; if (-f readlink $file) { if (-x readlink $file) { return GREEN; } else { return BLACK; } } elsif (-d readlink $file) { return BLUE; } elsif (-l readlink $file) { return BLACK; } elsif (-b readlink $file) { return YELLOW, ON_BLACK; } elsif (-c readlink $file) { return YELLOW, ON_BLACK; } elsif (-p readlink $file) { return YELLOW, ON_BLACK; } elsif (-s readlink $file) { return GREEN; } return BLACK; } #------------------------------------------------------------------------------- # Flag-Postfix abhängig vom Datei-Typ ermitteln. # (directory = "/", executable file = "*", named pipe = "|", socket = "=") #------------------------------------------------------------------------------- sub FileFlag { my ($file) = shift; if (-d $_ or -l $_ and -d readlink $_) { return "/"; } elsif (-f $_ and -x $_ or -l $_ and -f readlink $_ and -x readlink $_) { return "*"; } elsif (-p $_ or -l $_ and -p readlink $_) { return "|"; } elsif (-S $_ or -l $_ and -S readlink $_) { return "="; } return ""; }