Exemplo n.º 1
0
static int
lock_if_free (lock_info_type *clasher, register char *lfname)
{
  while (lock_file_1 (lfname, 0) == 0)
    {
      int locker;

      if (errno != EEXIST)
	return -1;

      locker = current_lock_owner (clasher, lfname);
      if (locker == 2)
        {
          FREE_LOCK_INFO (*clasher);
          return 0;   /* We ourselves locked it.  */
        }
      else if (locker == 1)
        return 1;  /* Someone else has it.  */
      else if (locker == -1)
	return -1;   /* current_lock_owner returned strange error.  */

      /* We deleted a stale lock; try again to lock the file.  */
    }
  return 0;
}
Exemplo n.º 2
0
void
lock_file (Lisp_Object fn)
{
  register Lisp_Object attack, orig_fn, encoded_fn;
  register char *lfname, *locker;
  lock_info_type lock_info;
  struct gcpro gcpro1;

  /* Don't do locking while dumping Emacs.
     Uncompressing wtmp files uses call-process, which does not work
     in an uninitialized Emacs.  */
  if (! NILP (Vpurify_flag))
    return;

  orig_fn = fn;
  GCPRO1 (fn);
  fn = Fexpand_file_name (fn, Qnil);
  encoded_fn = ENCODE_FILE (fn);

  /* Create the name of the lock-file for file fn */
  MAKE_LOCK_NAME (lfname, encoded_fn);

  /* See if this file is visited and has changed on disk since it was
     visited.  */
  {
    register Lisp_Object subject_buf;

    subject_buf = get_truename_buffer (orig_fn);

    if (!NILP (subject_buf)
	&& NILP (Fverify_visited_file_modtime (subject_buf))
	&& !NILP (Ffile_exists_p (fn)))
      call1 (intern ("ask-user-about-supersession-threat"), fn);

  }
  UNGCPRO;

  /* Try to lock the lock. */
  if (lock_if_free (&lock_info, lfname) <= 0)
    /* Return now if we have locked it, or if lock creation failed */
    return;

  /* Else consider breaking the lock */
  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);

  attack = call2 (intern ("ask-user-about-lock"), fn, build_string (locker));
  if (!NILP (attack))
    /* User says take the lock */
    {
      lock_file_1 (lfname, 1);
      return;
    }
  /* User says ignore the lock */
}
Exemplo n.º 3
0
static int
current_lock_owner (lock_info_type *owner, char *lfname)
{
  int ret;
  ptrdiff_t len;
  lock_info_type local_owner;
  intmax_t n;
  char *at, *dot, *colon;
  char readlink_buf[READLINK_BUFSIZE];
  char *lfinfo = emacs_readlink (lfname, readlink_buf);

  /* If nonexistent lock file, all is well; otherwise, got strange error. */
  if (!lfinfo)
    return errno == ENOENT ? 0 : -1;

  /* Even if the caller doesn't want the owner info, we still have to
     read it to determine return value.  */
  if (!owner)
    owner = &local_owner;

  /* Parse [email protected]:BOOT_TIME.  If can't parse, return -1.  */
  /* The USER is everything before the last @.  */
  at = strrchr (lfinfo, '@');
  dot = strrchr (lfinfo, '.');
  if (!at || !dot)
    {
      if (lfinfo != readlink_buf)
	xfree (lfinfo);
      return -1;
    }
  len = at - lfinfo;
  owner->user = xmalloc (len + 1);
  memcpy (owner->user, lfinfo, len);
  owner->user[len] = 0;

  /* The PID is everything from the last `.' to the `:'.  */
  errno = 0;
  n = strtoimax (dot + 1, NULL, 10);
  owner->pid =
    ((0 <= n && n <= TYPE_MAXIMUM (pid_t)
      && (TYPE_MAXIMUM (pid_t) < INTMAX_MAX || errno != ERANGE))
     ? n : 0);

  colon = strchr (dot + 1, ':');
  /* After the `:', if there is one, comes the boot time.  */
  n = 0;
  if (colon)
    {
      errno = 0;
      n = strtoimax (colon + 1, NULL, 10);
    }
  owner->boot_time =
    ((0 <= n && n <= TYPE_MAXIMUM (time_t)
      && (TYPE_MAXIMUM (time_t) < INTMAX_MAX || errno != ERANGE))
     ? n : 0);

  /* The host is everything in between.  */
  len = dot - at - 1;
  owner->host = xmalloc (len + 1);
  memcpy (owner->host, at + 1, len);
  owner->host[len] = 0;

  /* We're done looking at the link info.  */
  if (lfinfo != readlink_buf)
    xfree (lfinfo);

  /* On current host?  */
  if (STRINGP (Fsystem_name ())
      && strcmp (owner->host, SSDATA (Fsystem_name ())) == 0)
    {
      if (owner->pid == getpid ())
        ret = 2; /* We own it.  */
      else if (owner->pid > 0
               && (kill (owner->pid, 0) >= 0 || errno == EPERM)
	       && (owner->boot_time == 0
		   || within_one_second (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.  */
      else if (unlink (lfname) < 0)
        ret = -1;
      else
	ret = 0;
    }
  else
    { /* If we wanted to support the check for stale locks on remote machines,
         here's where we'd do it.  */
      ret = 1;
    }

  /* Avoid garbage.  */
  if (owner == &local_owner || ret <= 0)
    {
      FREE_LOCK_INFO (*owner);
    }
  return ret;
}
Exemplo n.º 4
0
static int
current_lock_owner (lock_info_type *owner, char *lfname)
{
  int len, ret;
  int local_owner = 0;
  char *at, *dot, *colon;
  char *lfinfo = 0;
  int bufsize = 50;
  /* Read arbitrarily-long contents of symlink.  Similar code in
     file-symlink-p in fileio.c.  */
  do
    {
      bufsize *= 2;
      lfinfo = (char *) xrealloc (lfinfo, bufsize);
      errno = 0;
      len = readlink (lfname, lfinfo, bufsize);
#ifdef ERANGE
      /* HP-UX reports ERANGE if the buffer is too small.  */
      if (len == -1 && errno == ERANGE)
	len = bufsize;
#endif
    }
  while (len >= bufsize);

  /* If nonexistent lock file, all is well; otherwise, got strange error. */
  if (len == -1)
    {
      xfree (lfinfo);
      return errno == ENOENT ? 0 : -1;
    }

  /* Link info exists, so `len' is its length.  Null terminate.  */
  lfinfo[len] = 0;

  /* Even if the caller doesn't want the owner info, we still have to
     read it to determine return value, so allocate it.  */
  if (!owner)
    {
      owner = (lock_info_type *) alloca (sizeof (lock_info_type));
      local_owner = 1;
    }

  /* Parse [email protected]:BOOT_TIME.  If can't parse, return -1.  */
  /* The USER is everything before the last @.  */
  at = strrchr (lfinfo, '@');
  dot = strrchr (lfinfo, '.');
  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 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;
  owner->host = (char *) xmalloc (len + 1);
  strncpy (owner->host, at + 1, len);
  owner->host[len] = 0;

  /* We're done looking at the link info.  */
  xfree (lfinfo);

  /* On current host?  */
  if (STRINGP (Fsystem_name ())
      && strcmp (owner->host, SSDATA (Fsystem_name ())) == 0)
    {
      if (owner->pid == getpid ())
        ret = 2; /* We own it.  */
      else if (owner->pid > 0
               && (kill (owner->pid, 0) >= 0 || errno == EPERM)
	       && (owner->boot_time == 0
		   || within_one_second (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.  */
      else if (unlink (lfname) < 0)
        ret = -1;
      else
	ret = 0;
    }
  else
    { /* If we wanted to support the check for stale locks on remote machines,
         here's where we'd do it.  */
      ret = 1;
    }

  /* Avoid garbage.  */
  if (local_owner || ret <= 0)
    {
      FREE_LOCK_INFO (*owner);
    }
  return ret;
}