LCOV - code coverage report
Current view: top level - lib/fs - lockfile.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 21 29 72.4 %
Date: 2021-11-24 03:28:48 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /* Copyright (c) 2003-2004, Roger Dingledine
       2             :  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
       3             :  * Copyright (c) 2007-2021, The Tor Project, Inc. */
       4             : /* See LICENSE for licensing information */
       5             : 
       6             : /**
       7             :  * \file lockfile.c
       8             :  *
       9             :  * \brief Implements lock files to prevent two Tor processes from using the
      10             :  * same data directory at the same time.
      11             :  **/
      12             : 
      13             : #include "orconfig.h"
      14             : #include "lib/fs/files.h"
      15             : #include "lib/fs/lockfile.h"
      16             : #include "lib/log/log.h"
      17             : #include "lib/log/util_bug.h"
      18             : #include "lib/malloc/malloc.h"
      19             : 
      20             : #ifdef HAVE_SYS_FILE_H
      21             : #include <sys/file.h>
      22             : #endif
      23             : #ifdef HAVE_FCNTL_H
      24             : #include <fcntl.h>
      25             : #endif
      26             : #ifdef HAVE_UNISTD_H
      27             : #include <unistd.h>
      28             : #endif
      29             : #ifdef _WIN32
      30             : #include <windows.h>
      31             : #include <sys/locking.h>
      32             : #endif
      33             : 
      34             : #include <errno.h>
      35             : #include <string.h>
      36             : 
      37             : /** Represents a lockfile on which we hold the lock. */
      38             : struct tor_lockfile_t {
      39             :   /** Name of the file */
      40             :   char *filename;
      41             :   /** File descriptor used to hold the file open */
      42             :   int fd;
      43             : };
      44             : 
      45             : /** Try to get a lock on the lockfile <b>filename</b>, creating it as
      46             :  * necessary.  If someone else has the lock and <b>blocking</b> is true,
      47             :  * wait until the lock is available.  Otherwise return immediately whether
      48             :  * we succeeded or not.
      49             :  *
      50             :  * Set *<b>locked_out</b> to true if somebody else had the lock, and to false
      51             :  * otherwise.
      52             :  *
      53             :  * Return a <b>tor_lockfile_t</b> on success, NULL on failure.
      54             :  *
      55             :  * (Implementation note: because we need to fall back to fcntl on some
      56             :  *  platforms, these locks are per-process, not per-thread.  If you want
      57             :  *  to do in-process locking, use tor_mutex_t like a normal person.
      58             :  *  On Windows, when <b>blocking</b> is true, the maximum time that
      59             :  *  is actually waited is 10 seconds, after which NULL is returned
      60             :  *  and <b>locked_out</b> is set to 1.)
      61             :  */
      62             : tor_lockfile_t *
      63          21 : tor_lockfile_lock(const char *filename, int blocking, int *locked_out)
      64             : {
      65          21 :   tor_lockfile_t *result;
      66          21 :   int fd;
      67          21 :   *locked_out = 0;
      68             : 
      69          21 :   log_info(LD_FS, "Locking \"%s\"", filename);
      70          21 :   fd = tor_open_cloexec(filename, O_RDWR|O_CREAT|O_TRUNC, 0600);
      71          21 :   if (fd < 0) {
      72           0 :     log_warn(LD_FS,"Couldn't open \"%s\" for locking: %s", filename,
      73             :              strerror(errno));
      74           0 :     return NULL;
      75             :   }
      76             : 
      77             : #ifdef _WIN32
      78             :   _lseek(fd, 0, SEEK_SET);
      79             :   if (_locking(fd, blocking ? _LK_LOCK : _LK_NBLCK, 1) < 0) {
      80             :     if (errno != EACCES && errno != EDEADLOCK)
      81             :       log_warn(LD_FS,"Couldn't lock \"%s\": %s", filename, strerror(errno));
      82             :     else
      83             :       *locked_out = 1;
      84             :     close(fd);
      85             :     return NULL;
      86             :   }
      87             : #elif defined(HAVE_FLOCK)
      88          42 :   if (flock(fd, LOCK_EX|(blocking ? 0 : LOCK_NB)) < 0) {
      89           0 :     if (errno != EWOULDBLOCK)
      90           0 :       log_warn(LD_FS,"Couldn't lock \"%s\": %s", filename, strerror(errno));
      91             :     else
      92           0 :       *locked_out = 1;
      93           0 :     close(fd);
      94           0 :     return NULL;
      95             :   }
      96             : #else
      97             :   {
      98             :     struct flock lock;
      99             :     memset(&lock, 0, sizeof(lock));
     100             :     lock.l_type = F_WRLCK;
     101             :     lock.l_whence = SEEK_SET;
     102             :     if (fcntl(fd, blocking ? F_SETLKW : F_SETLK, &lock) < 0) {
     103             :       if (errno != EACCES && errno != EAGAIN)
     104             :         log_warn(LD_FS, "Couldn't lock \"%s\": %s", filename, strerror(errno));
     105             :       else
     106             :         *locked_out = 1;
     107             :       close(fd);
     108             :       return NULL;
     109             :     }
     110             :   }
     111             : #endif /* defined(_WIN32) || ... */
     112             : 
     113          21 :   result = tor_malloc(sizeof(tor_lockfile_t));
     114          21 :   result->filename = tor_strdup(filename);
     115          21 :   result->fd = fd;
     116          21 :   return result;
     117             : }
     118             : 
     119             : /** Release the lock held as <b>lockfile</b>. */
     120             : void
     121          21 : tor_lockfile_unlock(tor_lockfile_t *lockfile)
     122             : {
     123          21 :   tor_assert(lockfile);
     124             : 
     125          21 :   log_info(LD_FS, "Unlocking \"%s\"", lockfile->filename);
     126             : #ifdef _WIN32
     127             :   _lseek(lockfile->fd, 0, SEEK_SET);
     128             :   if (_locking(lockfile->fd, _LK_UNLCK, 1) < 0) {
     129             :     log_warn(LD_FS,"Error unlocking \"%s\": %s", lockfile->filename,
     130             :              strerror(errno));
     131             :   }
     132             : #elif defined(HAVE_FLOCK)
     133          21 :   if (flock(lockfile->fd, LOCK_UN) < 0) {
     134           0 :     log_warn(LD_FS, "Error unlocking \"%s\": %s", lockfile->filename,
     135             :              strerror(errno));
     136             :   }
     137             : #else
     138             :   /* Closing the lockfile is sufficient. */
     139             : #endif /* defined(_WIN32) || ... */
     140             : 
     141          21 :   close(lockfile->fd);
     142          21 :   lockfile->fd = -1;
     143          21 :   tor_free(lockfile->filename);
     144          21 :   tor_free(lockfile);
     145          21 : }

Generated by: LCOV version 1.14