Logo Search packages:      
Sourcecode: leafnode version File versions

int try_lock ( unsigned long  timeout  ) 

Try to set a lockfile, blocking or non-blocking. Checks if the lockfile exists and is active.

requires: atomic link(2) syscall.

features:

  • NFS safe (but leafnode does not work distributed)
  • stale detection by PID in lock file (may be fooled)

Bug:
Cannot remove stale lock on other machine.
Bug:
Stale detection may be fooled if another process has been assigned the PID that the last caller had.
Returns:
  • 0: if locking succeeded
  • 1: if locking failed because the lock is held by someone else and isn't stale
  • -1: for other errors
Parameters:
timeout  Timeout, if nonzero, wait at most this many seconds.

Definition at line 200 of file lockfile.c.

References fd_st_nlink(), lock_is_stale(), and safe_mkstemp().

{
    const int block = 1;
    char *l2, *pid;
    int fd;
    int have_lock = 0;
    int quiet = 0;
    const char *const append = ".XXXXXXXXXX";
    const int have_timeout = (timeout != 0);

    if (debugmode)
      syslog(LOG_DEBUG,
             "try_lock(timeout=%lu), fqdn=\"%s\"",
             timeout, fqdn);
    if (verbose)
      printf("try_lock(timeout=%lu), fqdn=\"%s\"\n",
            timeout, fqdn);

    /* kill bogus fqdn */
    if (!is_validfqdn(fqdn)) {
      ln_log(LNLOG_SCRIT, LNLOG_CTOP,
             "Internal error: "
             "must not try to lock with local host name \"%s\"", fqdn);
      return -1;
    }

    l2 = (char *)critmalloc(strlen(lockfile) + strlen(append) + 1,
                      "try_lock");
    pid = (char *)critmalloc(strlen(fqdn) + sizeof(unsigned long) * 4 + 4,
                       "try_lock");

    strcpy(l2, lockfile); /* RATS: ignore */
    strcat(l2, append); /* RATS: ignore */

    /* make a temporary file */
    fd = safe_mkstemp(l2);
    if (fd < 0) {
      ln_log(LNLOG_SERR, LNLOG_CTOP, "mkstemp(%s) failed: %m", l2);
      free(l2);
      free(pid);
      return -1;
    }

    /* write our PID and host into it (stale detection) */
    sprintf(pid, "%lu\n%s\n", (unsigned long)getpid(), fqdn);
    /* safe, see malloc above */
    if (writes(fd, pid) < 0 || fsync(fd) < 0) {
      ln_log(LNLOG_SERR, LNLOG_CTOP, "cannot write to %s: %m", l2);
      if (unlink(l2))
          ln_log(LNLOG_SERR, LNLOG_CTOP,
               "Cannot remove lock helper file %s: %m", l2);
      free(l2);
      free(pid);
      return -1;
    }

    /* and try to finally lock */
    while (!have_lock) {
      if (0 == link(l2, lockfile)) {
          /* link succeeded. good. */
          have_lock = 1;
          break;
      } else {
          if (2 == fd_st_nlink(fd)) {
            /* link failed, but st_nlink has increased to 2, good. */
            have_lock = 1;
          } else {
            int stale;
            struct timeval tv = { 1, 0 };

            /* Could not create link. Check if the lock file is stale. */
            stale = lock_is_stale(lockfile, quiet);

            /* if we have a stale file, it's just been removed.
               retry, don't care for what block says */
            if (stale == 1)
                continue;

            quiet = 1;

            /* if we have a problem with stale detection, or
               if we are in non-blocking mode, abort */
            if (stale == -1 || !block)
                break;

            if (have_timeout) {
                if (timeout == 0)
                  break;

                --timeout;
            }

            /* retry after a second, select does not interfere w/ alarm */
            if (select(0, NULL, NULL, NULL, &tv) < 0) {
                /* must not happen */
                ln_log(LNLOG_SERR, LNLOG_CTOP,
                     "try_lock: select failed: %m");
                break;
            }
          }
      }
    }

    if (close(fd) < 0) {
      ln_log(LNLOG_SERR, LNLOG_CTOP, "cannot write to %s: %m", l2);
      have_lock = 0;
    }

    /* unlink l2, but just log if unable to unlink, ignore otherwise */
    if (unlink(l2))
      ln_log(LNLOG_SERR, LNLOG_CTOP,
             "Cannot remove lock helper file %s: %m", l2);

    /* clean up */
    free(l2);
    free(pid);

    /* mind the return logic */
    return have_lock ? 0 : 1;
}


Generated by  Doxygen 1.6.0   Back to index