home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / e20313sr.zip / emacs / 20.3.1 / src / filelock.c < prev    next >
C/C++ Source or Header  |  1999-07-31  |  15KB  |  556 lines

  1. /* Copyright (C) 1985, 86, 87, 93, 94, 96 Free Software Foundation, Inc.
  2.  
  3. This file is part of GNU Emacs.
  4.  
  5. GNU Emacs is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9.  
  10. GNU Emacs is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with GNU Emacs; see the file COPYING.  If not, write to
  17. the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  18. Boston, MA 02111-1307, USA.  */
  19.  
  20.  
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <signal.h>
  24. #include <config.h>
  25.  
  26. #ifdef VMS
  27. #include "vms-pwd.h"
  28. #else
  29. #include <pwd.h>
  30. #endif /* not VMS */
  31.  
  32. #include <sys/file.h>
  33. #ifdef USG
  34. #include <fcntl.h>
  35. #include <string.h>
  36. #endif /* USG */
  37.  
  38. #ifdef HAVE_UNISTD_H
  39. #include <unistd.h>
  40. #endif
  41.  
  42. #include "lisp.h"
  43. #include "buffer.h"
  44. #include "charset.h"
  45. #include "coding.h"
  46.  
  47. #include <time.h>
  48. #include <errno.h>
  49. #ifndef errno
  50. extern int errno;
  51. #endif
  52.  
  53. #ifdef CLASH_DETECTION
  54.  
  55. #include <utmp.h>
  56.   
  57. /* The strategy: to lock a file FN, create a symlink .#FN in FN's
  58.    directory, with link data `user@host.pid'.  This avoids a single
  59.    mount (== failure) point for lock files.
  60.  
  61.    When the host in the lock data is the current host, we can check if
  62.    the pid is valid with kill.
  63.    
  64.    Otherwise, we could look at a separate file that maps hostnames to
  65.    reboot times to see if the remote pid can possibly be valid, since we
  66.    don't want Emacs to have to communicate via pipes or sockets or
  67.    whatever to other processes, either locally or remotely; rms says
  68.    that's too unreliable.  Hence the separate file, which could
  69.    theoretically be updated by daemons running separately -- but this
  70.    whole idea is unimplemented; in practice, at least in our
  71.    environment, it seems such stale locks arise fairly infrequently, and
  72.    Emacs' standard methods of dealing with clashes suffice.
  73.  
  74.    We use symlinks instead of normal files because (1) they can be
  75.    stored more efficiently on the filesystem, since the kernel knows
  76.    they will be small, and (2) all the info about the lock can be read
  77.    in a single system call (readlink).  Although we could use regular
  78.    files to be useful on old systems lacking symlinks, nowadays
  79.    virtually all such systems are probably single-user anyway, so it
  80.    didn't seem worth the complication.
  81.    
  82.    Similarly, we don't worry about a possible 14-character limit on
  83.    file names, because those are all the same systems that don't have
  84.    symlinks.
  85.    
  86.    This is compatible with the locking scheme used by Interleaf (which
  87.    has contributed this implementation for Emacs), and was designed by
  88.    Ethan Jacobson, Kimbo Mundy, and others.
  89.    
  90.    --karl@cs.umb.edu/karl@hq.ileaf.com.  */
  91.  
  92.  
  93. /* Return the time of the last system boot.  */
  94.  
  95. static time_t boot_time;
  96.  
  97. static time_t
  98. get_boot_time ()
  99. {
  100. #ifdef BOOT_TIME
  101.   struct utmp ut, *utp;
  102.  
  103.   if (boot_time)
  104.     return boot_time;
  105.  
  106.   utmpname ("/var/log/wtmp");
  107.   setutent ();
  108.   boot_time = 1;
  109.   while (1)
  110.     {
  111.       /* Find the next reboot record.  */
  112.       ut.ut_type = BOOT_TIME;
  113.       utp = getutid (&ut);
  114.       if (! utp)
  115.     break;
  116.       /* Compare reboot times and use the newest one.  */
  117.       if (utp->ut_time > boot_time)
  118.     boot_time = utp->ut_time;
  119.       /* Advance on element in the file
  120.      so that getutid won't repeat the same one.  */
  121.       utp = getutent ();
  122.       if (! utp)
  123.     break;
  124.     }
  125.   endutent ();
  126.  
  127.   return boot_time;
  128. #else
  129.   return 0;
  130. #endif
  131. }
  132.  
  133. /* Here is the structure that stores information about a lock.  */
  134.  
  135. typedef struct
  136. {
  137.   char *user;
  138.   char *host;
  139.   unsigned long pid;
  140.   time_t boot_time;
  141. } lock_info_type;
  142.  
  143. /* When we read the info back, we might need this much more,
  144.    enough for decimal representation plus null.  */
  145. #define LOCK_PID_MAX (4 * sizeof (unsigned long))
  146.  
  147. /* Free the two dynamically-allocated pieces in PTR.  */
  148. #define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0)
  149.  
  150.  
  151. /* Write the name of the lock file for FN into LFNAME.  Length will be
  152.    that of FN plus two more for the leading `.#' plus one for the null.  */
  153. #define MAKE_LOCK_NAME(lock, file) \
  154.   (lock = (char *) alloca (STRING_BYTES (XSTRING (file)) + 2 + 1), \
  155.    fill_in_lock_file_name (lock, (file)))
  156.  
  157. static void
  158. fill_in_lock_file_name (lockfile, fn)
  159.      register char *lockfile;
  160.      register Lisp_Object fn;
  161. {
  162.   register char *p;
  163.  
  164.   strcpy (lockfile, XSTRING (fn)->data);
  165.  
  166.   /* Shift the nondirectory part of the file name (including the null)
  167.      right two characters.  Here is one of the places where we'd have to
  168.      do something to support 14-character-max file names.  */
  169.   for (p = lockfile + strlen (lockfile); p != lockfile && *p != '/'; p--)
  170.     p[2] = *p;
  171.   
  172.   /* Insert the `.#'.  */
  173.   p[1] = '.';
  174.   p[2] = '#';
  175. }
  176.  
  177. /* Lock the lock file named LFNAME.
  178.    If FORCE is nonzero, we do so even if it is already locked.
  179.    Return 1 if successful, 0 if not.  */
  180.  
  181. static int
  182. lock_file_1 (lfname, force)
  183.      char *lfname; 
  184.      int force;
  185. {
  186.   register int err;
  187.   time_t boot_time;
  188.   char *user_name;
  189.   char *host_name;
  190.   char *lock_info_str;
  191.  
  192.   if (STRINGP (Fuser_login_name (Qnil)))
  193.     user_name = (char *)XSTRING (Fuser_login_name (Qnil))->data;
  194.   else
  195.     user_name = "";
  196.   if (STRINGP (Fsystem_name ()))
  197.     host_name = (char *)XSTRING (Fsystem_name ())->data;
  198.   else
  199.     host_name = "";
  200.   lock_info_str = (char *)alloca (strlen (user_name) + strlen (host_name)
  201.                   + LOCK_PID_MAX + 5);
  202.  
  203.   boot_time = get_boot_time ();
  204.   if (boot_time)
  205.     sprintf (lock_info_str, "%s@%s.%lu:%lu", user_name, host_name,
  206.          (unsigned long) getpid (), (unsigned long) boot_time);
  207.   else
  208.     sprintf (lock_info_str, "%s@%s.%lu", user_name, host_name,
  209.          (unsigned long) getpid ());    
  210.  
  211.   err = symlink (lock_info_str, lfname);
  212.   if (errno == EEXIST && force)
  213.     {
  214.       unlink (lfname);
  215.       err = symlink (lock_info_str, lfname);
  216.     }
  217.  
  218.   return err == 0;
  219. }
  220.  
  221.  
  222.  
  223. /* Return 0 if nobody owns the lock file LFNAME or the lock is obsolete,
  224.    1 if another process owns it (and set OWNER (if non-null) to info),
  225.    2 if the current process owns it,
  226.    or -1 if something is wrong with the locking mechanism.  */
  227.  
  228. static int
  229. current_lock_owner (owner, lfname)
  230.      lock_info_type *owner;
  231.      char *lfname;
  232. {
  233. #ifndef index
  234.   extern char *rindex (), *index ();
  235. #endif
  236.   int o, p, len, ret;
  237.   int local_owner = 0;
  238.   char *at, *dot, *colon;
  239.   char *lfinfo = 0;
  240.   int bufsize = 50;
  241.   /* Read arbitrarily-long contents of symlink.  Similar code in
  242.      file-symlink-p in fileio.c.  */
  243.   do
  244.     {
  245.       bufsize *= 2;
  246.       lfinfo = (char *) xrealloc (lfinfo, bufsize);
  247.       len = readlink (lfname, lfinfo, bufsize);
  248.     }
  249.   while (len >= bufsize);
  250.   
  251.   /* If nonexistent lock file, all is well; otherwise, got strange error. */
  252.   if (len == -1)
  253.     {
  254.       xfree (lfinfo);
  255.       return errno == ENOENT ? 0 : -1;
  256.     }
  257.  
  258.   /* Link info exists, so `len' is its length.  Null terminate.  */
  259.   lfinfo[len] = 0;
  260.   
  261.   /* Even if the caller doesn't want the owner info, we still have to
  262.      read it to determine return value, so allocate it.  */
  263.   if (!owner)
  264.     {
  265.       owner = (lock_info_type *) alloca (sizeof (lock_info_type));
  266.       local_owner = 1;
  267.     }
  268.   
  269.   /* Parse USER@HOST.PID:BOOT_TIME.  If can't parse, return -1.  */
  270.   /* The USER is everything before the first @.  */
  271.   at = index (lfinfo, '@');
  272.   dot = rindex (lfinfo, '.');
  273.   if (!at || !dot)
  274.     {
  275.       xfree (lfinfo);
  276.       return -1;
  277.     }
  278.   len = at - lfinfo;
  279.   owner->user = (char *) xmalloc (len + 1);
  280.   strncpy (owner->user, lfinfo, len);
  281.   owner->user[len] = 0;
  282.   
  283.   /* The PID is everything from the last `.' to the `:'.  */
  284.   owner->pid = atoi (dot + 1);
  285.   colon = dot;
  286.   while (*colon && *colon != ':')
  287.     colon++;
  288.   /* After the `:', if there is one, comes the boot time.  */
  289.   if (*colon == ':')
  290.     owner->boot_time = atoi (colon + 1);
  291.   else
  292.     owner->boot_time = 0;
  293.  
  294.   /* The host is everything in between.  */
  295.   len = dot - at - 1;
  296.   owner->host = (char *) xmalloc (len + 1);
  297.   strncpy (owner->host, at + 1, len);
  298.   owner->host[len] = 0;
  299.  
  300.   /* We're done looking at the link info.  */
  301.   xfree (lfinfo);
  302.   
  303.   /* On current host?  */
  304.   if (STRINGP (Fsystem_name ())
  305.       && strcmp (owner->host, XSTRING (Fsystem_name ())->data) == 0)
  306.     {
  307.       if (owner->pid == getpid ())
  308.         ret = 2; /* We own it.  */
  309.       else if (owner->pid > 0
  310.                && (kill (owner->pid, 0) >= 0 || errno == EPERM)
  311.            && (owner->boot_time == 0
  312.            || owner->boot_time == get_boot_time ()))
  313.         ret = 1; /* An existing process on this machine owns it.  */
  314.       /* The owner process is dead or has a strange pid (<=0), so try to
  315.          zap the lockfile.  */
  316.       else if (unlink (lfname) < 0)
  317.         ret = -1;
  318.       else
  319.     ret = 0;
  320.     }
  321.   else
  322.     { /* If we wanted to support the check for stale locks on remote machines,
  323.          here's where we'd do it.  */
  324.       ret = 1;
  325.     }
  326.   
  327.   /* Avoid garbage.  */
  328.   if (local_owner || ret <= 0)
  329.     {
  330.       FREE_LOCK_INFO (*owner);
  331.     }
  332.   return ret;
  333. }
  334.  
  335.  
  336. /* Lock the lock named LFNAME if possible.
  337.    Return 0 in that case.
  338.    Return positive if some other process owns the lock, and info about
  339.      that process in CLASHER.
  340.    Return -1 if cannot lock for any other reason.  */
  341.  
  342. static int
  343. lock_if_free (clasher, lfname)
  344.      lock_info_type *clasher;
  345.      register char *lfname; 
  346. {
  347.   if (lock_file_1 (lfname, 0) == 0)
  348.     {
  349.       int locker;
  350.  
  351.       if (errno != EEXIST)
  352.     return -1;
  353.       
  354.       locker = current_lock_owner (clasher, lfname);
  355.       if (locker == 2)
  356.         {
  357.           FREE_LOCK_INFO (*clasher);
  358.           return 0;   /* We ourselves locked it.  */
  359.         }
  360.       else if (locker == 1)
  361.         return 1;  /* Someone else has it.  */
  362.  
  363.       return -1; /* Something's wrong.  */
  364.     }
  365.   return 0;
  366. }
  367.  
  368. /* lock_file locks file FN,
  369.    meaning it serves notice on the world that you intend to edit that file.
  370.    This should be done only when about to modify a file-visiting
  371.    buffer previously unmodified.
  372.    Do not (normally) call this for a buffer already modified,
  373.    as either the file is already locked, or the user has already
  374.    decided to go ahead without locking.
  375.  
  376.    When this returns, either the lock is locked for us,
  377.    or the user has said to go ahead without locking.
  378.  
  379.    If the file is locked by someone else, this calls
  380.    ask-user-about-lock (a Lisp function) with two arguments,
  381.    the file name and info about the user who did the locking.
  382.    This function can signal an error, or return t meaning
  383.    take away the lock, or return nil meaning ignore the lock.  */
  384.  
  385. void
  386. lock_file (fn)
  387.      Lisp_Object fn;
  388. {
  389.   register Lisp_Object attack, orig_fn, encoded_fn;
  390.   register char *lfname, *locker;
  391.   lock_info_type lock_info;
  392.  
  393.   orig_fn = fn;
  394.   fn = Fexpand_file_name (fn, Qnil);
  395.   encoded_fn = ENCODE_FILE (fn);
  396.  
  397.   /* Create the name of the lock-file for file fn */
  398.   MAKE_LOCK_NAME (lfname, encoded_fn);
  399.  
  400.   /* See if this file is visited and has changed on disk since it was
  401.      visited.  */
  402.   {
  403.     register Lisp_Object subject_buf;
  404.     struct gcpro gcpro1;
  405.  
  406.     subject_buf = get_truename_buffer (orig_fn);
  407.     GCPRO1 (fn);
  408.  
  409.     if (!NILP (subject_buf)
  410.     && NILP (Fverify_visited_file_modtime (subject_buf))
  411.     && !NILP (Ffile_exists_p (fn)))
  412.       call1 (intern ("ask-user-about-supersession-threat"), fn);
  413.  
  414.     UNGCPRO;
  415.   }
  416.  
  417.   /* Try to lock the lock. */
  418.   if (lock_if_free (&lock_info, lfname) <= 0)
  419.     /* Return now if we have locked it, or if lock creation failed */
  420.     return;
  421.  
  422.   /* Else consider breaking the lock */
  423.   locker = (char *) alloca (strlen (lock_info.user) + strlen (lock_info.host)
  424.                 + LOCK_PID_MAX + 9);
  425.   sprintf (locker, "%s@%s (pid %lu)", lock_info.user, lock_info.host,
  426.            lock_info.pid);
  427.   FREE_LOCK_INFO (lock_info);
  428.   
  429.   attack = call2 (intern ("ask-user-about-lock"), fn, build_string (locker));
  430.   if (!NILP (attack))
  431.     /* User says take the lock */
  432.     {
  433.       lock_file_1 (lfname, 1);
  434.       return;
  435.     }
  436.   /* User says ignore the lock */
  437. }
  438.  
  439. void
  440. unlock_file (fn)
  441.      register Lisp_Object fn;
  442. {
  443.   register char *lfname;
  444.  
  445.   fn = Fexpand_file_name (fn, Qnil);
  446.   fn = ENCODE_FILE (fn);
  447.  
  448.   MAKE_LOCK_NAME (lfname, fn);
  449.  
  450.   if (current_lock_owner (0, lfname) == 2)
  451.     unlink (lfname);
  452. }
  453.  
  454. void
  455. unlock_all_files ()
  456. {
  457.   register Lisp_Object tail;
  458.   register struct buffer *b;
  459.  
  460.   for (tail = Vbuffer_alist; GC_CONSP (tail); tail = XCONS (tail)->cdr)
  461.     {
  462.       b = XBUFFER (XCONS (XCONS (tail)->car)->cdr);
  463.       if (STRINGP (b->file_truename) && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b))
  464.     {
  465.       register char *lfname;
  466.  
  467.       MAKE_LOCK_NAME (lfname, b->file_truename);
  468.  
  469.       if (current_lock_owner (0, lfname) == 2)
  470.         unlink (lfname);
  471.     }
  472.     }
  473. }
  474.  
  475. DEFUN ("lock-buffer", Flock_buffer, Slock_buffer,
  476.   0, 1, 0,
  477.   "Lock FILE, if current buffer is modified.\n\
  478. FILE defaults to current buffer's visited file,\n\
  479. or else nothing is done if current buffer isn't visiting a file.")
  480.   (file)
  481.      Lisp_Object file;
  482. {
  483.   if (NILP (file))
  484.     file = current_buffer->file_truename;
  485.   else
  486.     CHECK_STRING (file, 0);
  487.   if (SAVE_MODIFF < MODIFF
  488.       && !NILP (file))
  489.     lock_file (file);
  490.   return Qnil;    
  491. }
  492.  
  493. DEFUN ("unlock-buffer", Funlock_buffer, Sunlock_buffer,
  494.   0, 0, 0,
  495.  "Unlock the file visited in the current buffer,\n\
  496. if it should normally be locked.")
  497.   ()
  498. {
  499.   if (SAVE_MODIFF < MODIFF
  500.       && STRINGP (current_buffer->file_truename))
  501.     unlock_file (current_buffer->file_truename);
  502.   return Qnil;
  503. }
  504.  
  505. /* Unlock the file visited in buffer BUFFER.  */
  506.  
  507. void
  508. unlock_buffer (buffer)
  509.      struct buffer *buffer;
  510. {
  511.   if (BUF_SAVE_MODIFF (buffer) < BUF_MODIFF (buffer)
  512.       && STRINGP (buffer->file_truename))
  513.     unlock_file (buffer->file_truename);
  514. }
  515.  
  516. DEFUN ("file-locked-p", Ffile_locked_p, Sfile_locked_p, 0, 1, 0,
  517.   "Return nil if the FILENAME is not locked,\n\
  518. t if it is locked by you, else a string of the name of the locker.")
  519.   (filename)
  520.   Lisp_Object filename;
  521. {
  522.   Lisp_Object ret;
  523.   register char *lfname;
  524.   int owner;
  525.   lock_info_type locker;
  526.  
  527.   filename = Fexpand_file_name (filename, Qnil);
  528.  
  529.   MAKE_LOCK_NAME (lfname, filename);
  530.  
  531.   owner = current_lock_owner (&locker, lfname);
  532.   if (owner <= 0)
  533.     ret = Qnil;
  534.   else if (owner == 2)
  535.     ret = Qt;
  536.   else
  537.     ret = build_string (locker.user);
  538.  
  539.   if (owner > 0)
  540.     FREE_LOCK_INFO (locker);
  541.  
  542.   return ret;
  543. }
  544.  
  545. /* Initialization functions.  */
  546.  
  547. void
  548. syms_of_filelock ()
  549. {
  550.   defsubr (&Sunlock_buffer);
  551.   defsubr (&Slock_buffer);
  552.   defsubr (&Sfile_locked_p);
  553. }
  554.  
  555. #endif /* CLASH_DETECTION */
  556.