summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamanta Navarro <ferivoz@riseup.net>2023-05-10 11:57:20 +0000
committerSerge Hallyn <serge@hallyn.com>2023-05-11 10:59:21 -0500
commit72290ede0e0d0cf960127bf42f11a7e227d4dac5 (patch)
tree1edf02807e8235faf5343568b077328395dcb1ef
parent4abcbb056e8894e92c71508c9ae7c63051cf4d37 (diff)
commonio: Use do_lock_file again
This avoids regressions introduced with do_fcntl_lock. Signed-off-by: Samanta Navarro <ferivoz@riseup.net>
-rw-r--r--lib/commonio.c203
1 files changed, 175 insertions, 28 deletions
diff --git a/lib/commonio.c b/lib/commonio.c
index 6857f531..1f9291e5 100644
--- a/lib/commonio.c
+++ b/lib/commonio.c
@@ -34,6 +34,8 @@
/* local function prototypes */
static int lrename (const char *, const char *);
+static int check_link_count (const char *file, bool log);
+static int do_lock_file (const char *file, const char *lock, bool log);
static /*@null@*/ /*@dependent@*/FILE *fopen_set_perms (
const char *name,
const char *mode,
@@ -91,6 +93,150 @@ int lrename (const char *old, const char *new)
return res;
}
+static int check_link_count (const char *file, bool log)
+{
+ struct stat sb;
+
+ if (stat (file, &sb) != 0) {
+ if (log) {
+ (void) fprintf (shadow_logfd,
+ "%s: %s file stat error: %s\n",
+ shadow_progname, file, strerror (errno));
+ }
+ return 0;
+ }
+
+ if (sb.st_nlink != 2) {
+ if (log) {
+ (void) fprintf (shadow_logfd,
+ "%s: %s: lock file already used (nlink: %u)\n",
+ shadow_progname, file, sb.st_nlink);
+ }
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int do_lock_file (const char *file, const char *lock, bool log)
+{
+ int fd;
+ pid_t pid;
+ ssize_t len;
+ int retval;
+ char buf[32];
+
+ fd = open (file, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+ if (-1 == fd) {
+ if (log) {
+ (void) fprintf (shadow_logfd,
+ "%s: %s: %s\n",
+ shadow_progname, file, strerror (errno));
+ }
+ return 0;
+ }
+
+ pid = getpid ();
+ snprintf (buf, sizeof buf, "%lu", (unsigned long) pid);
+ len = (ssize_t) strlen (buf) + 1;
+ if (write (fd, buf, (size_t) len) != len) {
+ if (log) {
+ (void) fprintf (shadow_logfd,
+ "%s: %s file write error: %s\n",
+ shadow_progname, file, strerror (errno));
+ }
+ (void) close (fd);
+ unlink (file);
+ return 0;
+ }
+ if (fdatasync (fd) == -1) {
+ if (log) {
+ (void) fprintf (shadow_logfd,
+ "%s: %s file sync error: %s\n",
+ shadow_progname, file, strerror (errno));
+ }
+ (void) close (fd);
+ unlink (file);
+ return 0;
+ }
+ close (fd);
+
+ if (link (file, lock) == 0) {
+ retval = check_link_count (file, log);
+ unlink (file);
+ return retval;
+ }
+
+ fd = open (lock, O_RDWR);
+ if (-1 == fd) {
+ if (log) {
+ (void) fprintf (shadow_logfd,
+ "%s: %s: %s\n",
+ shadow_progname, lock, strerror (errno));
+ }
+ unlink (file);
+ errno = EINVAL;
+ return 0;
+ }
+ len = read (fd, buf, sizeof (buf) - 1);
+ close (fd);
+ if (len <= 0) {
+ if (log) {
+ (void) fprintf (shadow_logfd,
+ "%s: existing lock file %s without a PID\n",
+ shadow_progname, lock);
+ }
+ unlink (file);
+ errno = EINVAL;
+ return 0;
+ }
+ buf[len] = '\0';
+ if (get_pid (buf, &pid) == 0) {
+ if (log) {
+ (void) fprintf (shadow_logfd,
+ "%s: existing lock file %s with an invalid PID '%s'\n",
+ shadow_progname, lock, buf);
+ }
+ unlink (file);
+ errno = EINVAL;
+ return 0;
+ }
+ if (kill (pid, 0) == 0) {
+ if (log) {
+ (void) fprintf (shadow_logfd,
+ "%s: lock %s already used by PID %lu\n",
+ shadow_progname, lock, (unsigned long) pid);
+ }
+ unlink (file);
+ errno = EEXIST;
+ return 0;
+ }
+ if (unlink (lock) != 0) {
+ if (log) {
+ (void) fprintf (shadow_logfd,
+ "%s: cannot get lock %s: %s\n",
+ shadow_progname, lock, strerror (errno));
+ }
+ unlink (file);
+ return 0;
+ }
+
+ retval = 0;
+ if (link (file, lock) == 0) {
+ retval = check_link_count (file, log);
+ } else {
+ if (log) {
+ (void) fprintf (shadow_logfd,
+ "%s: cannot get lock %s: %s\n",
+ shadow_progname, lock, strerror (errno));
+ }
+ }
+
+ unlink (file);
+ return retval;
+}
+
static /*@null@*/ /*@dependent@*/FILE *fopen_set_perms (
const char *name,
@@ -205,43 +351,38 @@ bool commonio_present (const struct commonio_db *db)
}
-int do_fcntl_lock (const char *file, bool log, short type)
-{
- int fd;
- struct flock lck = {
- .l_type = type,
- .l_whence = SEEK_SET,
- .l_start = 0,
- .l_len = 0,
- };
-
- fd = open (file, O_WRONLY | O_CREAT, 0600);
- if (-1 == fd) {
- if (log) {
- (void) fprintf (shadow_logfd, "%s: %s: %s\n",
- shadow_progname, file, strerror (errno));
- }
- return 0;
- }
-
- fcntl (fd, F_SETLKW, &lck);
- return(1);
-}
-
int commonio_lock_nowait (struct commonio_db *db, bool log)
{
+ char* file = NULL;
+ char* lock = NULL;
+ size_t lock_file_len;
+ size_t file_len;
int err = 0;
if (db->locked) {
return 1;
}
-
- if (do_fcntl_lock (db->filename, log, F_WRLCK | F_RDLCK) != 0) {
+ file_len = strlen(db->filename) + 11;/* %lu max size */
+ lock_file_len = strlen(db->filename) + 6; /* sizeof ".lock" */
+ file = MALLOCARRAY(file_len, char);
+ if (file == NULL) {
+ goto cleanup_ENOMEM;
+ }
+ lock = MALLOCARRAY(lock_file_len, char);
+ if (lock == NULL) {
+ goto cleanup_ENOMEM;
+ }
+ snprintf (file, file_len, "%s.%lu",
+ db->filename, (unsigned long) getpid ());
+ snprintf (lock, lock_file_len, "%s.lock", db->filename);
+ if (do_lock_file (file, lock, log) != 0) {
db->locked = true;
lock_count++;
err = 1;
}
-
+cleanup_ENOMEM:
+ free(file);
+ free(lock);
return err;
}
@@ -332,6 +473,8 @@ static void dec_lock_count (void)
int commonio_unlock (struct commonio_db *db)
{
+ char lock[1024];
+
if (db->isopen) {
db->readonly = true;
if (commonio_close (db) == 0) {
@@ -342,9 +485,13 @@ int commonio_unlock (struct commonio_db *db)
}
}
if (db->locked) {
+ /*
+ * Unlock in reverse order: remove the lock file,
+ * then call ulckpwdf() (if used) on last unlock.
+ */
db->locked = false;
-
- do_fcntl_lock (db->filename, false, F_UNLCK);
+ snprintf (lock, sizeof lock, "%s.lock", db->filename);
+ unlink (lock);
dec_lock_count ();
return 1;
}