mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
common: Enhance dotlock, so that we can have a CLI util.
* common/dotlock.h (DOTLOCK_LOCK_BY_PARENT, DOTLOCK_LOCKED): New. * common/dotlock.c [HAVE_POSIX_SYSTEM]: Include <dirent.h>. (dotlock_get_process_id, dotlock_detect_tname): New. (dotlock_create_unix): Handle the case when no_write option is specified. Not creating the lock file, but detect the the file of tname. (dotlock_create) [HAVE_POSIX_SYSTEM]: Add support of DOTLOCK_LOCK_BY_PARENT and DOTLOCK_LOCKED for dotlock CLI util. (dotlock_take_unix): Support the case of DOTLOCK_LOCK_BY_PARENT. -- Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
parent
1c5584c395
commit
6b4fd3a5da
144
common/dotlock.c
144
common/dotlock.c
@ -291,6 +291,7 @@
|
|||||||
# include <sys/types.h>
|
# include <sys/types.h>
|
||||||
# include <sys/stat.h>
|
# include <sys/stat.h>
|
||||||
# include <sys/utsname.h>
|
# include <sys/utsname.h>
|
||||||
|
# include <dirent.h>
|
||||||
#endif
|
#endif
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
@ -393,6 +394,8 @@ struct dotlock_handle
|
|||||||
unsigned int locked:1; /* Lock status. */
|
unsigned int locked:1; /* Lock status. */
|
||||||
unsigned int disable:1; /* If true, locking is disabled. */
|
unsigned int disable:1; /* If true, locking is disabled. */
|
||||||
unsigned int use_o_excl:1; /* Use open (O_EXCL) for locking. */
|
unsigned int use_o_excl:1; /* Use open (O_EXCL) for locking. */
|
||||||
|
unsigned int by_parent:1; /* Parent does the locking. */
|
||||||
|
unsigned int no_write:1; /* No write to the lockfile. */
|
||||||
|
|
||||||
int extra_fd; /* A place for the caller to store an FD. */
|
int extra_fd; /* A place for the caller to store an FD. */
|
||||||
|
|
||||||
@ -679,6 +682,80 @@ use_hardlinks_p (const char *tname)
|
|||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_POSIX_SYSTEM
|
#ifdef HAVE_POSIX_SYSTEM
|
||||||
|
static int
|
||||||
|
dotlock_get_process_id (dotlock_t h)
|
||||||
|
{
|
||||||
|
return h->by_parent? (int)getppid(): (int)getpid();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dotlock_detect_tname (dotlock_t h)
|
||||||
|
{
|
||||||
|
struct stat sb;
|
||||||
|
DIR *dir;
|
||||||
|
char *dirname;
|
||||||
|
char *basename;
|
||||||
|
struct dirent *d;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (stat (h->lockname, &sb))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
basename = make_basename (h->lockname, NULL);
|
||||||
|
dirname = make_dirname (h->lockname);
|
||||||
|
|
||||||
|
dir = opendir (dirname);
|
||||||
|
if (dir == NULL)
|
||||||
|
{
|
||||||
|
xfree (basename);
|
||||||
|
xfree (dirname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((d = readdir (dir)))
|
||||||
|
if (sb.st_ino == d->d_ino && strcmp (d->d_name, basename))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (d)
|
||||||
|
{
|
||||||
|
int len = strlen (h->tname);
|
||||||
|
int dlen = strlen (d->d_name);
|
||||||
|
const char *tname_path;
|
||||||
|
|
||||||
|
if (dlen > len)
|
||||||
|
{
|
||||||
|
xfree (basename);
|
||||||
|
xfree (dirname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy (stpcpy (stpcpy (h->tname, dirname), DIRSEP_S), d->d_name);
|
||||||
|
h->use_o_excl = 0;
|
||||||
|
tname_path = strchr (h->tname + strlen (dirname) + 2, '.');
|
||||||
|
if (!tname_path)
|
||||||
|
{
|
||||||
|
xfree (basename);
|
||||||
|
xfree (dirname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
h->nodename_off = tname_path - h->tname + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
h->use_o_excl = 1;
|
||||||
|
|
||||||
|
r = closedir (dir);
|
||||||
|
if (r)
|
||||||
|
{
|
||||||
|
xfree (basename);
|
||||||
|
xfree (dirname);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
xfree (basename);
|
||||||
|
xfree (dirname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Locking core for Unix. It used a temporary file and the link
|
/* Locking core for Unix. It used a temporary file and the link
|
||||||
system call to make locking an atomic operation. */
|
system call to make locking an atomic operation. */
|
||||||
static dotlock_t
|
static dotlock_t
|
||||||
@ -691,8 +768,10 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
|
|||||||
int dirpartlen;
|
int dirpartlen;
|
||||||
struct utsname utsbuf;
|
struct utsname utsbuf;
|
||||||
size_t tnamelen;
|
size_t tnamelen;
|
||||||
|
int pid;
|
||||||
|
|
||||||
snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid() );
|
pid = dotlock_get_process_id (h);
|
||||||
|
snprintf (pidstr, sizeof pidstr, "%10d\n", pid);
|
||||||
|
|
||||||
/* Create a temporary file. */
|
/* Create a temporary file. */
|
||||||
if ( uname ( &utsbuf ) )
|
if ( uname ( &utsbuf ) )
|
||||||
@ -726,10 +805,17 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
|
|||||||
}
|
}
|
||||||
h->nodename_len = strlen (nodename);
|
h->nodename_len = strlen (nodename);
|
||||||
|
|
||||||
|
if (h->no_write)
|
||||||
|
{
|
||||||
|
memset (h->tname, '_', tnamelen);
|
||||||
|
h->tname[tnamelen] = 0;
|
||||||
|
goto skip_write;
|
||||||
|
}
|
||||||
|
|
||||||
snprintf (h->tname, tnamelen, "%.*s/.#lk%p.", dirpartlen, dirpart, h );
|
snprintf (h->tname, tnamelen, "%.*s/.#lk%p.", dirpartlen, dirpart, h );
|
||||||
h->nodename_off = strlen (h->tname);
|
h->nodename_off = strlen (h->tname);
|
||||||
snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off,
|
snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off,
|
||||||
"%s.%d", nodename, (int)getpid ());
|
"%s.%d", nodename, pid);
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -792,6 +878,7 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
|
|||||||
goto write_failed;
|
goto write_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
skip_write:
|
||||||
h->lockname = xtrymalloc (strlen (file_to_lock) + 6 );
|
h->lockname = xtrymalloc (strlen (file_to_lock) + 6 );
|
||||||
if (!h->lockname)
|
if (!h->lockname)
|
||||||
{
|
{
|
||||||
@ -807,6 +894,20 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
|
|||||||
strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
|
strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
|
||||||
UNLOCK_all_lockfiles ();
|
UNLOCK_all_lockfiles ();
|
||||||
|
|
||||||
|
if (h->no_write)
|
||||||
|
{
|
||||||
|
if (dotlock_detect_tname (h) < 0)
|
||||||
|
{
|
||||||
|
xfree (h->lockname);
|
||||||
|
xfree (h->tname);
|
||||||
|
xfree (h);
|
||||||
|
my_set_errno (EACCES);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
h->locked = 1;
|
||||||
|
}
|
||||||
|
|
||||||
return h;
|
return h;
|
||||||
|
|
||||||
write_failed:
|
write_failed:
|
||||||
@ -914,10 +1015,15 @@ dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
|
|||||||
POSIX systems a temporary file ".#lk.<hostname>.pid[.threadid] is
|
POSIX systems a temporary file ".#lk.<hostname>.pid[.threadid] is
|
||||||
used.
|
used.
|
||||||
|
|
||||||
The only defined FLAG bit is DOTLOCK_PREPARE_CREATE, which only
|
FLAGS may include DOTLOCK_PREPARE_CREATE bit, which only allocates
|
||||||
allocates the handle and requires a further call to
|
the handle and requires a further call to dotlock_finish_create.
|
||||||
dotlock_finish_create. This can be used to set a callback between
|
This can be used to set a callback between these calls.
|
||||||
these calls.
|
|
||||||
|
FLAGS may include DOTLOCK_LOCK_BY_PARENT bit, when it's the parent
|
||||||
|
process controlling the lock. This is used by dotlock util.
|
||||||
|
|
||||||
|
FLAGS may include DOTLOCK_LOCKED bit, when it should not create the
|
||||||
|
lockfile, but to unlock. This is used by dotlock util.
|
||||||
|
|
||||||
The function returns an new handle which needs to be released using
|
The function returns an new handle which needs to be released using
|
||||||
destroy_dotlock but gets also released at the termination of the
|
destroy_dotlock but gets also released at the termination of the
|
||||||
@ -929,8 +1035,13 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
|
|||||||
{
|
{
|
||||||
static int initialized;
|
static int initialized;
|
||||||
dotlock_t h;
|
dotlock_t h;
|
||||||
|
#ifndef HAVE_DOSISH_SYSTEM
|
||||||
|
int by_parent = 0;
|
||||||
|
int no_write = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
if ( !initialized )
|
if ( !(flags & DOTLOCK_LOCK_BY_PARENT)
|
||||||
|
&& !initialized )
|
||||||
{
|
{
|
||||||
atexit (dotlock_remove_lockfiles);
|
atexit (dotlock_remove_lockfiles);
|
||||||
initialized = 1;
|
initialized = 1;
|
||||||
@ -939,6 +1050,14 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
|
|||||||
if ( !file_to_lock )
|
if ( !file_to_lock )
|
||||||
return NULL; /* Only initialization was requested. */
|
return NULL; /* Only initialization was requested. */
|
||||||
|
|
||||||
|
#ifndef HAVE_DOSISH_SYSTEM
|
||||||
|
if ((flags & DOTLOCK_LOCK_BY_PARENT) || (flags & DOTLOCK_LOCKED))
|
||||||
|
{
|
||||||
|
by_parent = !!(flags & DOTLOCK_LOCK_BY_PARENT);
|
||||||
|
no_write = !!(flags & DOTLOCK_LOCKED);
|
||||||
|
flags &= ~(DOTLOCK_LOCK_BY_PARENT | DOTLOCK_LOCKED);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if ((flags & ~DOTLOCK_PREPARE_CREATE))
|
if ((flags & ~DOTLOCK_PREPARE_CREATE))
|
||||||
{
|
{
|
||||||
my_set_errno (EINVAL);
|
my_set_errno (EINVAL);
|
||||||
@ -949,6 +1068,10 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
|
|||||||
if (!h)
|
if (!h)
|
||||||
return NULL;
|
return NULL;
|
||||||
h->extra_fd = -1;
|
h->extra_fd = -1;
|
||||||
|
#ifndef HAVE_DOSISH_SYSTEM
|
||||||
|
h->by_parent = by_parent;
|
||||||
|
h->no_write = no_write;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (never_lock)
|
if (never_lock)
|
||||||
{
|
{
|
||||||
@ -1181,7 +1304,8 @@ dotlock_take_unix (dotlock_t h, long timeout)
|
|||||||
{
|
{
|
||||||
char pidstr[16];
|
char pidstr[16];
|
||||||
|
|
||||||
snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid());
|
snprintf (pidstr, sizeof pidstr, "%10d\n",
|
||||||
|
dotlock_get_process_id (h));
|
||||||
if (write (fd, pidstr, 11 ) == 11
|
if (write (fd, pidstr, 11 ) == 11
|
||||||
&& write (fd, h->tname + h->nodename_off,h->nodename_len)
|
&& write (fd, h->tname + h->nodename_off,h->nodename_len)
|
||||||
== h->nodename_len
|
== h->nodename_len
|
||||||
@ -1251,7 +1375,7 @@ dotlock_take_unix (dotlock_t h, long timeout)
|
|||||||
my_info_0 ("lockfile disappeared\n");
|
my_info_0 ("lockfile disappeared\n");
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
else if ( (pid == getpid() && same_node)
|
else if ( (pid == dotlock_get_process_id (h) && same_node && !h->by_parent)
|
||||||
|| (same_node && kill (pid, 0) && errno == ESRCH) )
|
|| (same_node && kill (pid, 0) && errno == ESRCH) )
|
||||||
{
|
{
|
||||||
/* Stale lockfile is detected. */
|
/* Stale lockfile is detected. */
|
||||||
@ -1460,7 +1584,7 @@ dotlock_release_unix (dotlock_t h)
|
|||||||
my_set_errno (saveerrno);
|
my_set_errno (saveerrno);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ( pid != getpid() || !same_node )
|
if ( pid != dotlock_get_process_id (h) || !same_node )
|
||||||
{
|
{
|
||||||
my_error_1 ("release_dotlock: not our lock (pid=%d)\n", pid);
|
my_error_1 ("release_dotlock: not our lock (pid=%d)\n", pid);
|
||||||
if (h->info_cb)
|
if (h->info_cb)
|
||||||
|
@ -108,7 +108,10 @@ enum dotlock_reasons
|
|||||||
DOTLOCK_WAITING /* Waiting for the lock - may be terminated. */
|
DOTLOCK_WAITING /* Waiting for the lock - may be terminated. */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DOTLOCK_PREPARE_CREATE (1<<5) /* Require dotlock_finish_create. */
|
/* Flags for dotlock_create. */
|
||||||
|
#define DOTLOCK_PREPARE_CREATE (1U << 5) /* Require dotlock_finish_create. */
|
||||||
|
#define DOTLOCK_LOCK_BY_PARENT (1U << 6) /* Used by dotlock util. */
|
||||||
|
#define DOTLOCK_LOCKED (1U << 7) /* Used by dotlock util. */
|
||||||
|
|
||||||
void dotlock_disable (void);
|
void dotlock_disable (void);
|
||||||
dotlock_t dotlock_create (const char *file_to_lock, unsigned int flags);
|
dotlock_t dotlock_create (const char *file_to_lock, unsigned int flags);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user