home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / perl / scripts-convex / lockem < prev    next >
Encoding:
Text File  |  1991-06-07  |  4.7 KB  |  203 lines

  1. #!/usr/local/bin/perl
  2.  
  3. $editor = $ENV{'EDITOR'} || 'vi';
  4.  
  5. $atomic = 1; # unless reset by -w
  6.  
  7. while ($ARGV[0] =~ /^-(.+)/ && (($_ = $1), shift, 1)) {
  8.     next if $_ eq ''; # options exhausted
  9.  
  10.     if (/^-$/) {
  11.     push(@options, shift) while $ARGV[0] =~ /^-/;
  12.     last;
  13.     } 
  14.  
  15.     s/b// && (++$nonblock,  redo);
  16.     s/c// && (++$create, redo);
  17.     s/s// && (++$ronly,  redo);
  18.     s/w// && (($atomic = 0), redo);
  19.     s/f// && (++$use_flock, redo);
  20.     s/l// && (++$use_lockf, redo);
  21.     s/e// && (($editor = $_ || shift),  next);
  22.  
  23.     print STDERR "unknown option: -$_\n";
  24.     &usage;
  25.  
  26.  
  27. &usage unless @ARGV;
  28.  
  29. $use_lockf++ unless $use_flock || $use_lockf;
  30.  
  31. &flock_init if $use_flock;
  32. &lockf_init if $use_lockf;
  33.  
  34. $fh = 'FH000';
  35.  
  36. for (@ARGV) {
  37.     local($locker);
  38.     die "$0: $_ is a directory\n" if -d;
  39.     $files{$_} = ++$fh;
  40.     if (!open($fh, ($use_lockf ? "+<" : "<") . $_)) {
  41.     if ($! =~ /no such file/i && $create) {
  42.         warn "$0: creating $_\n";
  43.         die "$0: cannot create $_: $!\n" unless open($fh, ">>$_");
  44.     } else {
  45.         warn "$0: cannot open $_: $!\n";
  46.         &atomic;
  47.         delete $files{$_};
  48.         sleep 1;
  49.         next;
  50.     }
  51.     } 
  52.     if (&slock($fh)) {
  53.     if (! &lock($fh)) {
  54.         warn "$_ disappeared" unless -e;
  55.         &whosgot;
  56.         &atomic;
  57.     } 
  58.     } 
  59.     elsif (!$nonblock && ($! =~ /would block/i || 
  60.     ($! =~ /permission/i && $use_lockf)))
  61.     {
  62.     &whosgot;
  63.     print STDERR "waiting for ", ($ronly ? "shared" : "exclusive"),
  64.          " lock on $_...";
  65.     unless (&lock($fh)) {
  66.         warn "$_ disappeared" unless -e;
  67.         &whosgot;
  68.         &atomic;
  69.     } 
  70.     print STDERR "lock on $_ granted.\n";
  71.     sleep 1;
  72.     } else {
  73.     &whosgot;
  74.     &atomic;
  75.     delete $files{$_};
  76.     } 
  77.  
  78. system $editor, @options, @ARGV;
  79.  
  80. for (keys %files) {
  81.     unless (&unlock($files{$_})) {
  82.     warn "$0: cannot unlock $_ ($files{$_}): $!\n";
  83.     next;
  84.     } 
  85.  
  86. exit 0;
  87.  
  88. sub atomic {  # like quarks
  89.   die "$0: use -w to continue without acquiring all locks\n" if $atomic;
  90. }
  91.  
  92. sub usage { 
  93.     die <<EOM;
  94. usage: $0 [-wbcsfl] [-e editor] [-- -editor_options] files
  95.        -w: give warnings only if all locks can't be acquired
  96.        -b: do NOT block until all locks acquired
  97.        -c: create non-existent files
  98.        -s: shared locks only (good for read-only files)
  99.        -f: use flock
  100.        -l: use lockf (default)
  101.        -e editor: invoke program other than \$EDITOR
  102.        --: end options to $0, rest will go to \$EDITOR
  103. EOM
  104. }
  105.  
  106. sub lockf_init {
  107.     # require 'fcntl.ph';
  108.  
  109.     ($F_GETLK, $F_SETLK, $F_SETLKW) = (7..9);
  110.     ($F_RDLCK, $F_WRLCK, $F_UNLCK) = (1..3);
  111.  
  112.     # struct flock definition
  113.     $flock_t = 'ssLLss';    
  114.  
  115.     # and its field names
  116.     ( $L_TYPE,        # $F_RDLCK, $F_WRLCK, or $F_UNLCK
  117.       $L_WHENCE,    # flag to choose starting offset 
  118.       $L_START,        # relative offset, in bytes 
  119.       $L_LEN,        # length, in bytes; 0 means lock to EOF 
  120.       $L_PID,        # returned with $F_GETLK 
  121.       $L_XXX )        # reserved for future use 
  122.       = (0..5);
  123. }
  124.  
  125. sub flock_init {
  126.     ($LOCK_SH, $LOCK_EX, $LOCK_NB, $LOCK_UN) = (1,2,4,8);
  127.  
  128. sub unlock {
  129.     local($fh) = @_;
  130.     local($return) = 1;
  131.     if ($use_flock) {
  132.     $return = flock($fh, $LOCK_UN);
  133.     } 
  134.     if ($use_lockf && !$return) {
  135.     local(@flock,$flock);
  136.     $flock[$L_TYPE] = $F_UNLCK;
  137.     $flock = pack($flock_t, @flock);
  138.     &getlocker unless $return = fcntl($fh, $F_SETLK, $flock);
  139.     } 
  140.     $return;
  141.  
  142. sub slock {  # safely lock a file if i can w/o blocking
  143.     local($fh) = @_;
  144.     local($return) = 1;
  145.  
  146.     if ($use_flock) {
  147.     $return = flock($fh, $LOCK_NB | ($ronly ? $LOCK_SH : $LOCK_EX));
  148.     } 
  149.     if ($use_lockf && $return) {
  150.     local(@flock,$flock);
  151.     $flock[$L_TYPE] = $ronly ? $F_RDLCK : $F_WRLCK;
  152.     $flock = pack($flock_t, @flock);
  153.     &getlocker unless $return = fcntl($fh, $F_SETLK, $flock);
  154.     } 
  155.     $return;
  156.  
  157. sub lock {  # lock with blocking
  158.     local($fh) = @_;
  159.     local($return) = 1;
  160.     if ($use_flock) {
  161.     $return = flock($fh, $ronly ? $LOCK_SH : $LOCK_EX);
  162.     }
  163.     if ($use_lockf && $return) {
  164.     local(@flock,$flock);
  165.     $flock[$L_TYPE] = $ronly ? $F_RDLCK : $F_WRLCK;
  166.     $flock = pack($flock_t, @flock);
  167.     $return = fcntl($fh, $F_SETLKW, $flock);
  168.     if (!$return && $! =~  /interrupt/i) { # broken kernel (^Z/fg)
  169.         warn "$0: interrupted, trying again\n";
  170.         $return = &lock($fh); 
  171.     } 
  172.     }
  173.     $return;
  174. }
  175.  
  176. sub getlocker {
  177.     local(@flock,$flock);
  178.     local($!); # save old errno
  179.     $flock[$L_TYPE] = $ronly ? $F_RDLCK : $F_WRLCK;
  180.     $flock = pack($flock_t, @flock);
  181.     if (fcntl($fh, $F_GETLK, $flock)) {
  182.     @flock = unpack($flock_t, $flock);
  183.     $locker = ($flock[$L_TYPE] == $F_UNLCK ? 0 : $flock[$L_PID])
  184.             || "some remote host";
  185.     } else {
  186.     warn "can't getlk: $!"; 
  187.     }
  188.  
  189. sub whosgot { 
  190.     if ($use_lockf && $locker) {
  191.     warn "$0: lock on $_ held by pid $locker\n";
  192.     } else {
  193.     warn "$0: cannot lock $_: $!\n";
  194.     }
  195. }
  196.