(fix_submap_inheritance, get_keyelt, store_in_keymap,
[bpt/emacs.git] / src / filelock.c
index 743b8d0..116f96e 100644 (file)
@@ -37,6 +37,8 @@ Boston, MA 02111-1307, USA.  */
 #include "lisp.h"
 #include "buffer.h"
 
+#include <time.h>
+#include <utmp.h>
 #include <errno.h>
 #ifndef errno
 extern int errno;
@@ -58,14 +60,14 @@ extern int errno;
    that's too unreliable.  Hence the separate file, which could
    theoretically be updated by daemons running separately -- but this
    whole idea is unimplemented; in practice, at least in our
-   environment, it seems such stale locks arise fiarly infrequently, and
+   environment, it seems such stale locks arise fairly infrequently, and
    Emacs' standard methods of dealing with clashes suffice.
 
    We use symlinks instead of normal files because (1) they can be
    stored more efficiently on the filesystem, since the kernel knows
    they will be small, and (2) all the info about the lock can be read
    in a single system call (readlink).  Although we could use regular
-   files to be useful on old systems lacking symlinks, noawdays
+   files to be useful on old systems lacking symlinks, nowadays
    virtually all such systems are probably single-user anyway, so it
    didn't seem worth the complication.
    
@@ -80,6 +82,32 @@ extern int errno;
    --karl@cs.umb.edu/karl@hq.ileaf.com.  */
 
 \f
+/* Return the time of the last system boot.  */
+
+static time_t boot_time;
+
+static time_t
+get_boot_time ()
+{
+#ifdef BOOT_TIME
+  struct utmp ut, *utp;
+
+  if (boot_time)
+    return boot_time;
+
+  utmpname ("/var/log/wtmp");
+  ut.ut_type = BOOT_TIME;
+  utp = getutid (&ut);
+  endutent ();
+
+  if (!utp)
+    return boot_time = 1;
+  return boot_time = utp->ut_time;
+#else
+  return 0;
+#endif;
+}
+\f
 /* Here is the structure that stores information about a lock.  */
 
 typedef struct
@@ -87,6 +115,7 @@ typedef struct
   char *user;
   char *host;
   unsigned long pid;
+  time_t boot_time;
 } lock_info_type;
 
 /* When we read the info back, we might need this much more,
@@ -100,7 +129,7 @@ typedef struct
 /* Write the name of the lock file for FN into LFNAME.  Length will be
    that of FN plus two more for the leading `.#' plus one for the null.  */
 #define MAKE_LOCK_NAME(lock, file) \
-  (lock = (char *) alloca (XSTRING (file)->size + 2 + 1), \
+  (lock = (char *) alloca (XSTRING (file)->size_byte + 2 + 1), \
    fill_in_lock_file_name (lock, (file)))
 
 static void
@@ -133,13 +162,29 @@ lock_file_1 (lfname, force)
      int force;
 {
   register int err;
-  char *user_name = XSTRING (Fuser_login_name (Qnil))->data;
-  char *host_name = XSTRING (Fsystem_name ())->data;
-  char *lock_info_str = alloca (strlen (user_name) + strlen (host_name)
-                                + LOCK_PID_MAX + 5);
+  time_t boot_time;
+  char *user_name;
+  char *host_name;
+  char *lock_info_str;
 
-  sprintf (lock_info_str, "%s@%s.%lu", user_name, host_name,
-           (unsigned long) getpid ());
+  if (STRINGP (Fuser_login_name (Qnil)))
+    user_name = (char *)XSTRING (Fuser_login_name (Qnil))->data;
+  else
+    user_name = "";
+  if (STRINGP (Fsystem_name ()))
+    host_name = (char *)XSTRING (Fsystem_name ())->data;
+  else
+    host_name = "";
+  lock_info_str = (char *)alloca (strlen (user_name) + strlen (host_name)
+                                 + LOCK_PID_MAX + 5);
+
+  boot_time = get_boot_time ();
+  if (boot_time)
+    sprintf (lock_info_str, "%s@%s.%lu:%lu", user_name, host_name,
+            (unsigned long) getpid (), (unsigned long) boot_time);
+  else
+    sprintf (lock_info_str, "%s@%s.%lu", user_name, host_name,
+            (unsigned long) getpid ());    
 
   err = symlink (lock_info_str, lfname);
   if (errno == EEXIST && force)
@@ -168,7 +213,7 @@ current_lock_owner (owner, lfname)
 #endif
   int o, p, len, ret;
   int local_owner = 0;
-  char *at, *dot;
+  char *at, *dot, *colon;
   char *lfinfo = 0;
   int bufsize = 50;
   /* Read arbitrarily-long contents of symlink.  Similar code in
@@ -195,25 +240,34 @@ current_lock_owner (owner, lfname)
      read it to determine return value, so allocate it.  */
   if (!owner)
     {
-      owner = alloca (sizeof (lock_info_type));
+      owner = (lock_info_type *) alloca (sizeof (lock_info_type));
       local_owner = 1;
     }
   
-  /* Parse USER@HOST.PID.  If can't parse, return -1.  */
+  /* Parse USER@HOST.PID:BOOT_TIME.  If can't parse, return -1.  */
   /* The USER is everything before the first @.  */
   at = index (lfinfo, '@');
   dot = rindex (lfinfo, '.');
-  if (!at || !dot) {
-    xfree (lfinfo);
-    return -1;
-  }
+  if (!at || !dot)
+    {
+      xfree (lfinfo);
+      return -1;
+    }
   len = at - lfinfo;
   owner->user = (char *) xmalloc (len + 1);
   strncpy (owner->user, lfinfo, len);
   owner->user[len] = 0;
   
-  /* The PID is everything after the last `.'.  */
+  /* The PID is everything from the last `.' to the `:'.  */
   owner->pid = atoi (dot + 1);
+  colon = dot;
+  while (*colon && *colon != ':')
+    colon++;
+  /* After the `:', if there is one, comes the boot time.  */
+  if (*colon == ':')
+    owner->boot_time = atoi (colon + 1);
+  else
+    owner->boot_time = 0;
 
   /* The host is everything in between.  */
   len = dot - at - 1;
@@ -225,21 +279,22 @@ current_lock_owner (owner, lfname)
   xfree (lfinfo);
   
   /* On current host?  */
-  if (strcmp (owner->host, XSTRING (Fsystem_name ())->data) == 0)
+  if (STRINGP (Fsystem_name ())
+      && strcmp (owner->host, XSTRING (Fsystem_name ())->data) == 0)
     {
       if (owner->pid == getpid ())
         ret = 2; /* We own it.  */
-      
-      if (owner->pid > 0
-               && (kill (owner->pid, 0) >= 0 || errno == EPERM))
+      else if (owner->pid > 0
+               && (kill (owner->pid, 0) >= 0 || errno == EPERM)
+              && (owner->boot_time == 0
+                  || owner->boot_time == get_boot_time ()))
         ret = 1; /* An existing process on this machine owns it.  */
-      
       /* The owner process is dead or has a strange pid (<=0), so try to
          zap the lockfile.  */
-      if (unlink (lfname) < 0)
+      else if (unlink (lfname) < 0)
         ret = -1;
-      
-      ret = 0;
+      else
+       ret = 0;
     }
   else
     { /* If we wanted to support the check for stale locks on remote machines,
@@ -267,7 +322,7 @@ lock_if_free (clasher, lfname)
      lock_info_type *clasher;
      register char *lfname; 
 {
-  while (lock_file_1 (lfname, 0) == 0)
+  if (lock_file_1 (lfname, 0) == 0)
     {
       int locker;
 
@@ -282,11 +337,8 @@ lock_if_free (clasher, lfname)
         }
       else if (locker == 1)
         return 1;  /* Someone else has it.  */
-      else if (locker == -1)
-        return -1; /* Something's wrong.  */
 
-       /* If some other error, or no such lock, try to lock again.  */
-       /* Is there a case where we loop forever?  */
+      return -1; /* Something's wrong.  */
     }
   return 0;
 }
@@ -339,9 +391,9 @@ lock_file (fn)
     return;
 
   /* Else consider breaking the lock */
-  locker = alloca (strlen (lock_info.user) + strlen (lock_info.host)
-                   + LOCK_PID_MAX + 9);
-  sprintf (locker, "%s@%s (pid %d)", lock_info.user, lock_info.host,
+  locker = (char *) alloca (strlen (lock_info.user) + strlen (lock_info.host)
+                           + LOCK_PID_MAX + 9);
+  sprintf (locker, "%s@%s (pid %lu)", lock_info.user, lock_info.host,
            lock_info.pid);
   FREE_LOCK_INFO (lock_info);
   
@@ -379,7 +431,14 @@ unlock_all_files ()
     {
       b = XBUFFER (XCONS (XCONS (tail)->car)->cdr);
       if (STRINGP (b->file_truename) && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b))
-       unlock_file (b->file_truename);
+       {
+         register char *lfname;
+
+         MAKE_LOCK_NAME (lfname, b->file_truename);
+
+         if (current_lock_owner (0, lfname) == 2)
+           unlink (lfname);
+       }
     }
 }
 \f
@@ -415,6 +474,7 @@ if it should normally be locked.")
 
 /* Unlock the file visited in buffer BUFFER.  */
 
+void
 unlock_buffer (buffer)
      struct buffer *buffer;
 {
@@ -451,35 +511,9 @@ t if it is locked by you, else a string of the name of the locker.")
 
   return ret;
 }
-
 \f
 /* Initialization functions.  */
 
-init_filelock ()
-{
-#if 0
-  char *new_name;
-
-  lock_dir = egetenv ("EMACSLOCKDIR");
-  if (! lock_dir)
-    lock_dir = PATH_LOCK;
-
-  /* Copy the name in case egetenv got it from a Lisp string.  */
-  new_name = (char *) xmalloc (strlen (lock_dir) + 2);
-  strcpy (new_name, lock_dir);
-  lock_dir = new_name;
-
-  /* Make sure it ends with a slash.  */
-  if (lock_dir[strlen (lock_dir) - 1] != '/')
-    strcat (lock_dir, "/");
-
-  superlock_file = (char *) xmalloc ((strlen (lock_dir)
-                                     + sizeof (SUPERLOCK_NAME)));
-  strcpy (superlock_file, lock_dir);
-  strcat (superlock_file, SUPERLOCK_NAME);
-#endif
-}
-
 syms_of_filelock ()
 {
   defsubr (&Sunlock_buffer);