Ejemplo n.º 1
0
dotlock_t
dotlock_create (const char *file_to_lock, unsigned int flags)
{
  static int initialized;
  dotlock_t h;

  if ( !initialized )
    {
      atexit (dotlock_remove_lockfiles);
      initialized = 1;
    }

  if ( !file_to_lock )
    return NULL;  /* Only initialization was requested.  */

  if (flags)
    {
      jnlib_set_errno (EINVAL);
      return NULL;
    }

  h = jnlib_calloc (1, sizeof *h);
  if (!h)
    return NULL;
  h->extra_fd = -1;

  if (never_lock)
    {
      h->disable = 1;
      LOCK_all_lockfiles ();
      h->next = all_lockfiles;
      all_lockfiles = h;
      UNLOCK_all_lockfiles ();
      return h;
    }

#ifdef HAVE_DOSISH_SYSTEM
  return dotlock_create_w32 (h, file_to_lock);
#else /*!HAVE_DOSISH_SYSTEM */
  return dotlock_create_unix (h, file_to_lock);
#endif /*!HAVE_DOSISH_SYSTEM*/
}
Ejemplo n.º 2
0
time_t
timegm (struct tm *tm)
{
#ifdef HAVE_W32_SYSTEM
  /* This one is thread safe.  */
  SYSTEMTIME st;
  FILETIME ft;
  unsigned long long cnsecs;

  st.wYear   = tm->tm_year + 1900;
  st.wMonth  = tm->tm_mon  + 1;
  st.wDay    = tm->tm_mday;
  st.wHour   = tm->tm_hour;
  st.wMinute = tm->tm_min;
  st.wSecond = tm->tm_sec;
  st.wMilliseconds = 0; /* Not available.  */
  st.wDayOfWeek = 0;    /* Ignored.  */

  /* System time is UTC thus the conversion is pretty easy.  */
  if (!SystemTimeToFileTime (&st, &ft))
    {
      jnlib_set_errno (EINVAL);
      return (time_t)(-1);
    }

  cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
            | ft.dwLowDateTime);
  cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01.  */
  return (time_t)(cnsecs / 10000000ULL);

#else /* (Non thread safe implementation!) */

  time_t answer;
  char *zone;

  zone=getenv("TZ");
  putenv("TZ=UTC");
  tzset();
  answer=mktime(tm);
  if(zone)
    {
      static char *old_zone;

      if (!old_zone)
        {
          old_zone = malloc(3+strlen(zone)+1);
          if (old_zone)
            {
              strcpy(old_zone,"TZ=");
              strcat(old_zone,zone);
            }
	}
      if (old_zone)
        putenv (old_zone);
    }
  else
    gnupg_unsetenv("TZ");

  tzset();
  return answer;
#endif
}
Ejemplo n.º 3
0
/* Unix specific code of make_dotlock.  Returns 0 on success and -1 on
   error.  */
static int
dotlock_take_unix (dotlock_t h, long timeout)
{
  int wtime = 0;
  int sumtime = 0;
  int pid;
  int lastpid = -1;
  int ownerchanged;
  const char *maybe_dead="";
  int same_node;

 again:
  if (h->use_o_excl)
    {
      /* No hardlink support - use open(O_EXCL).  */
      int fd;

      do
        {
          jnlib_set_errno (0);
          fd = open (h->lockname, O_WRONLY|O_CREAT|O_EXCL,
                     S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
        }
      while (fd == -1 && errno == EINTR);

      if (fd == -1 && errno == EEXIST)
        ; /* Lock held by another process.  */
      else if (fd == -1)
        {
          my_error_2 ("lock not made: open(O_EXCL) of `%s' failed: %s\n",
                      h->lockname, strerror (errno));
          return -1;
        }
      else
        {
          char pidstr[16];

          snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid());
          if (write (fd, pidstr, 11 ) == 11
              && write (fd, h->tname + h->nodename_off,h->nodename_len)
              == h->nodename_len
              && write (fd, "\n", 1) == 1
              && !close (fd))
            {
              h->locked = 1;
              return 0;
            }
          /* Write error.  */
          my_error_2 ("lock not made: writing to `%s' failed: %s\n",
                      h->lockname, strerror (errno));
          close (fd);
          unlink (h->lockname);
          return -1;
        }
    }
  else /* Standard method:  Use hardlinks.  */
    {
      struct stat sb;

      link (h->tname, h->lockname);

      if (stat (h->tname, &sb))
        {
          my_error_1 ("lock not made: Oops: stat of tmp file failed: %s\n",
                      strerror (errno));
          /* In theory this might be a severe error: It is possible
             that link succeeded but stat failed due to changed
             permissions.  We can't do anything about it, though.  */
          return -1;
        }

      if (sb.st_nlink == 2)
        {
          h->locked = 1;
          return 0; /* Okay.  */
        }
    }

  /* Check for stale lock files.  */
  if ( (pid = read_lockfile (h, &same_node)) == -1 )
    {
      if ( errno != ENOENT )
        {
          my_info_0 ("cannot read lockfile\n");
          return -1;
        }
      my_info_0 ("lockfile disappeared\n");
      goto again;
    }
  else if ( pid == getpid() && same_node )
    {
      my_info_0 ("Oops: lock already held by us\n");
      h->locked = 1;
      return 0; /* okay */
    }
  else if ( same_node && kill (pid, 0) && errno == ESRCH )
    {
      /* Note: It is unlikley that we get a race here unless a pid is
         reused too fast or a new process with the same pid as the one
         of the stale file tries to lock right at the same time as we.  */
      my_info_1 (_("removing stale lockfile (created by %d)\n"), pid);
      unlink (h->lockname);
      goto again;
    }

  if (lastpid == -1)
    lastpid = pid;
  ownerchanged = (pid != lastpid);

  if (timeout)
    {
      struct timeval tv;

      /* Wait until lock has been released.  We use increasing retry
         intervals of 50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s
         but reset it if the lock owner meanwhile changed.  */
      if (!wtime || ownerchanged)
        wtime = 50;
      else if (wtime < 800)
        wtime *= 2;
      else if (wtime == 800)
        wtime = 2000;
      else if (wtime < 8000)
        wtime *= 2;

      if (timeout > 0)
        {
          if (wtime > timeout)
            wtime = timeout;
          timeout -= wtime;
        }

      sumtime += wtime;
      if (sumtime >= 1500)
        {
          sumtime = 0;
          my_info_3 (_("waiting for lock (held by %d%s) %s...\n"),
                     pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
        }


      tv.tv_sec = wtime / 1000;
      tv.tv_usec = (wtime % 1000) * 1000;
      select (0, NULL, NULL, NULL, &tv);
      goto again;
    }

  jnlib_set_errno (EACCES);
  return -1;
}
Ejemplo n.º 4
0
/* Locking core for Unix.  It used a temporary file and the link
   system call to make locking an atomic operation. */
static dotlock_t
dotlock_create_unix (dotlock_t h, const char *file_to_lock)
{
  int  fd = -1;
  char pidstr[16];
  const char *nodename;
  const char *dirpart;
  int dirpartlen;
  struct utsname utsbuf;
  size_t tnamelen;

  snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid() );

  /* Create a temporary file. */
  if ( uname ( &utsbuf ) )
    nodename = "unknown";
  else
    nodename = utsbuf.nodename;

  if ( !(dirpart = strrchr (file_to_lock, DIRSEP_C)) )
    {
      dirpart = EXTSEP_S;
      dirpartlen = 1;
    }
  else
    {
      dirpartlen = dirpart - file_to_lock;
      dirpart = file_to_lock;
    }

  LOCK_all_lockfiles ();
  h->next = all_lockfiles;
  all_lockfiles = h;

  tnamelen = dirpartlen + 6 + 30 + strlen(nodename) + 10 + 1;
  h->tname = jnlib_malloc (tnamelen + 1);
  if (!h->tname)
    {
      all_lockfiles = h->next;
      UNLOCK_all_lockfiles ();
      jnlib_free (h);
      return NULL;
    }
  h->nodename_len = strlen (nodename);

  snprintf (h->tname, tnamelen, "%.*s/.#lk%p.", dirpartlen, dirpart, h );
  h->nodename_off = strlen (h->tname);
  snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off,
           "%s.%d", nodename, (int)getpid ());

  do
    {
      jnlib_set_errno (0);
      fd = open (h->tname, O_WRONLY|O_CREAT|O_EXCL,
                 S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
    }
  while (fd == -1 && errno == EINTR);

  if ( fd == -1 )
    {
      all_lockfiles = h->next;
      UNLOCK_all_lockfiles ();
      my_error_2 (_("failed to create temporary file `%s': %s\n"),
                  h->tname, strerror(errno));
      jnlib_free (h->tname);
      jnlib_free (h);
      return NULL;
    }
  if ( write (fd, pidstr, 11 ) != 11 )
    goto write_failed;
  if ( write (fd, nodename, strlen (nodename) ) != strlen (nodename) )
    goto write_failed;
  if ( write (fd, "\n", 1 ) != 1 )
    goto write_failed;
  if ( close (fd) )
    goto write_failed;

  /* Check whether we support hard links.  */
  switch (use_hardlinks_p (h->tname))
    {
    case 0: /* Yes.  */
      break;
    case 1: /* No.  */
      unlink (h->tname);
      h->use_o_excl = 1;
      break;
    default:
      my_error_2 ("can't check whether hardlinks are supported for `%s': %s\n",
                  h->tname, strerror(errno));
      goto write_failed;
    }

  h->lockname = jnlib_malloc (strlen (file_to_lock) + 6 );
  if (!h->lockname)
    {
      all_lockfiles = h->next;
      UNLOCK_all_lockfiles ();
      unlink (h->tname);
      jnlib_free (h->tname);
      jnlib_free (h);
      return NULL;
    }
  strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
  UNLOCK_all_lockfiles ();
  if (h->use_o_excl)
    my_debug_1 ("locking for `%s' done via O_EXCL\n", h->lockname);

  return h;

 write_failed:
  all_lockfiles = h->next;
  UNLOCK_all_lockfiles ();
  my_error_2 (_("error writing to `%s': %s\n"), h->tname, strerror (errno));
  close (fd);
  unlink (h->tname);
  jnlib_free (h->tname);
  jnlib_free (h);
  return NULL;
}
Ejemplo n.º 5
0
static int
read_lockfile (dotlock_t h, int *same_node )
{
  char buffer_space[10+1+70+1]; /* 70 is just an estimated value; node
                                   names are usually shorter. */
  int fd;
  int pid = -1;
  char *buffer, *p;
  size_t expected_len;
  int res, nread;

  *same_node = 0;
  expected_len = 10 + 1 + h->nodename_len + 1;
  if ( expected_len >= sizeof buffer_space)
    {
      buffer = jnlib_malloc (expected_len);
      if (!buffer)
        return -1;
    }
  else
    buffer = buffer_space;

  if ( (fd = open (h->lockname, O_RDONLY)) == -1 )
    {
      int e = errno;
      my_info_2 ("error opening lockfile `%s': %s\n",
                 h->lockname, strerror(errno) );
      if (buffer != buffer_space)
        jnlib_free (buffer);
      jnlib_set_errno (e); /* Need to return ERRNO here. */
      return -1;
    }

  p = buffer;
  nread = 0;
  do
    {
      res = read (fd, p, expected_len - nread);
      if (res == -1 && errno == EINTR)
        continue;
      if (res < 0)
        {
          my_info_1 ("error reading lockfile `%s'\n", h->lockname );
          close (fd);
          if (buffer != buffer_space)
            jnlib_free (buffer);
          jnlib_set_errno (0); /* Do not return an inappropriate ERRNO. */
          return -1;
        }
      p += res;
      nread += res;
    }
  while (res && nread != expected_len);
  close(fd);

  if (nread < 11)
    {
      my_info_1 ("invalid size of lockfile `%s'\n", h->lockname);
      if (buffer != buffer_space)
        jnlib_free (buffer);
      jnlib_set_errno (0); /* Better don't return an inappropriate ERRNO. */
      return -1;
    }

  if (buffer[10] != '\n'
      || (buffer[10] = 0, pid = atoi (buffer)) == -1
      || !pid )
    {
      my_error_2 ("invalid pid %d in lockfile `%s'\n", pid, h->lockname);
      if (buffer != buffer_space)
        jnlib_free (buffer);
      jnlib_set_errno (0);
      return -1;
    }

  if (nread == expected_len
      && !memcmp (h->tname+h->nodename_off, buffer+11, h->nodename_len)
      && buffer[11+h->nodename_len] == '\n')
    *same_node = 1;

  if (buffer != buffer_space)
    jnlib_free (buffer);
  return pid;
}