http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.16.tar.gz
[xscreensaver] / driver / xscreensaver-getimage-file
index 6370db1c24b4d47ca4a1647e55a6d697b1fb3e40..ef0c5d557715ff3265b846c96fcc310030357460 100755 (executable)
@@ -1,5 +1,5 @@
 #!/usr/bin/perl -w
-# Copyright © 2001 Jamie Zawinski <jwz@jwz.org>, all rights reserved.
+# Copyright © 2001, 2002, 2003, 2004 Jamie Zawinski <jwz@jwz.org>.
 #
 # Permission to use, copy, modify, distribute, and sell this software and its
 # documentation for any purpose is hereby granted without fee, provided that
@@ -30,12 +30,23 @@ use strict;
 use POSIX;
 use Fcntl;
 
+use POSIX ':fcntl_h';                          # S_ISLNK was here in Perl 5.6
+import Fcntl ':mode' unless defined &S_ISLNK;  # but it is here in Perl 5.8
+
 
 my $progname = $0; $progname =~ s@.*/@@g;
-my $version = q{ $Revision: 1.6 $ }; $version =~ s/^[^0-9]+([0-9.]+).*$/$1/;
+my $version = q{ $Revision: 1.15 $ }; $version =~ s/^[^0-9]+([0-9.]+).*$/$1/;
 
 my $verbose = 0;
 
+# This matches files that we are allowed to use as images (case-insensitive.)
+# Anything not matching this is ignored.  This is so you can point your
+# imageDirectory at directory trees that have things other than images in
+# them, but it assumes that you gave your images sensible file extensions.
+#
+my $good_file_re = '\.(gif|p?jpe?g|png|tiff?|xbm|xpm)$';
+
+
 # These are programs that can be used to put an image file on the root
 # window (including virtual root windows.)  The first one of these programs
 # that exists on $PATH will be used (with the file name as the last arg.)
@@ -44,7 +55,7 @@ my $verbose = 0;
 #
 my @programs = (
   "chbg       -once -xscreensaver -max_grow 4 -max_size 100",
-  "xv         -root -quit -viewonly -maxpect -noresetroot -quick24 -rmode 5" .
+  "xv         -root -quit -viewonly -maxpect +noresetroot -quick24 -rmode 5" .
   "           -rfg black -rbg black",
   "xli        -quiet -fullscreen -onroot -center -border black",
   "xloadimage -quiet -fullscreen -onroot -center -border black",
@@ -53,6 +64,7 @@ my @programs = (
 # "xsri       -scale -keep-aspect -center-horizontal -center-vertical",
 );
 
+
 sub pick_displayer {
   my @names = ();
 
@@ -76,6 +88,8 @@ sub pick_displayer {
 
 my @all_files = ();
 my %seen_inodes;
+my $skip_count = 0;
+my $dir_count = 1;
 
 sub find_all_files {
   my ($dir) = @_;
@@ -84,7 +98,7 @@ sub find_all_files {
 
   local *DIR;
   if (! opendir (DIR, $dir)) {
-    print STDERR "$progname: couldn't open $dir: $!\n";
+    print STDERR "$progname: couldn't open $dir: $!\n" if ($verbose);
     return;
   }
   my @files = readdir (DIR);
@@ -93,24 +107,42 @@ sub find_all_files {
   my @dirs = ();
 
   foreach my $file (@files) {
-    next if ($file =~ m/^\./);      # ignore dot files
-    next if ($file =~ m/[~%\#]$/);  # ignore backup files
-    next if ($file =~ m/\.(BAK|bak|tmp|orig|rej|rpmsave)$/);
-    next if ($file eq "core");
+    next if ($file =~ m/^\./);      # ignore dot files/dirs
 
     $file = "$dir/$file";
+    my @st = stat($file);
     my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
-        $atime,$mtime,$ctime,$blksize,$blocks) = stat($file);
+        $atime,$mtime,$ctime,$blksize,$blocks) = @st;
+
+    if ($#st == -1) {
+      if ($verbose) {
+        my $ll = readlink $file;
+        if (defined ($ll)) {
+          print STDERR "$progname: dangling symlink: $file -> $ll\n";
+        } else {
+          print STDERR "$progname: unreadable: $file\n";
+        }
+      }
+      next;
+    }
 
-    next if ($seen_inodes{$ino}); # break symlink loops
-    $seen_inodes{$ino} = 1;
+    next if ($seen_inodes{"$dev:$ino"}); # break symlink loops
+    $seen_inodes{"$dev:$ino"} = 1;
 
     if (S_ISDIR($mode)) {
       push @dirs, $file;
+      $dir_count++;
       print STDERR "$progname:   found dir  $file\n" if ($verbose > 2);
     } elsif (S_ISREG($mode) || S_ISLNK($mode)) {
-      push @all_files, $file;
-      print STDERR "$progname:   found file $file\n" if ($verbose > 2);
+
+      if ($file =~ m/[~%\#]$/ ||               # backup file, or
+          ! ($file =~ m/$good_file_re/io)) {   # no image extension
+        $skip_count++;
+        print STDERR "$progname:   skip file $file\n" if ($verbose > 2);
+      } else {
+        push @all_files, $file;
+        print STDERR "$progname:   found file $file\n" if ($verbose > 2);
+      }
     } elsif ($verbose > 2) {
       print STDERR "$progname:   nonreg $file\n";
     }
@@ -129,10 +161,20 @@ sub find_random_file {
 
   print STDERR "$progname: recursively reading $dir...\n" if ($verbose > 1);
   find_all_files ($dir);
-  print STDERR "$progname: found $#all_files files\n" if ($verbose > 1);
+  print STDERR "$progname: found " . ($#all_files+1) .
+               " file" . ($#all_files == 0 ? "" : "s") .
+               " in $dir_count dir" . ($dir_count == 1 ? "" : "s") .
+               "; skipped $skip_count file" . ($skip_count == 1 ? "" : "s") .
+               ".\n"
+    if ($verbose > 1);
 
   @all_files = sort(@all_files);
 
+  if ($#all_files < 0) {
+    print STDERR "$progname: no files in $dir\n";
+    exit 1;
+  }
+
   my $n = int (rand ($#all_files + 1));
   my $file = $all_files[$n];
 
@@ -165,9 +207,10 @@ sub find_and_display {
 
 
 sub usage {
-  print STDERR "usage: $progname [--verbose] [--name] directory\n";
-  print STDERR "Puts a randomly selected image on the root window.\n";
-  print STDERR "With --name, merely prints the filename to stdout.\n";
+  print STDERR "usage: $progname [--verbose] [--name] file-or-directory\n\n" .
+  "       Puts the given image file (or a randomly selected image from the\n" .
+  "       given directory) on the root window.  If --name is specified,\n" .
+  "       just prints the selected filename to stdout instead.\n\n";
   exit 1;
 }
 
@@ -195,6 +238,7 @@ sub main {
   } elsif (-f $dir) {
     display_file ($dir, $displayer);
   } else {
+    print STDERR "$progname: $dir does not exist\n";
     usage();
   }
 }