Blame lib/rpmlock.c

2ff057
2ff057
#include "system.h"
2ff057
2ff057
#include <errno.h>
2ff057
2ff057
#include <rpm/rpmlog.h>
2ff057
#include <rpm/rpmfileutil.h>
2ff057
2ff057
#include "lib/rpmlock.h"
2ff057
2ff057
#include "debug.h"
2ff057
2ff057
/* Internal interface */
2ff057
2ff057
struct rpmlock_s {
2ff057
    int fd;
2ff057
    int openmode;
2ff057
    char *path;
2ff057
    char *descr;
2ff057
    int fdrefs;
2ff057
};
2ff057
2ff057
static rpmlock rpmlock_new(const char *lock_path, const char *descr)
2ff057
{
2ff057
    rpmlock lock = (rpmlock) malloc(sizeof(*lock));
2ff057
2ff057
    if (lock != NULL) {
2ff057
	mode_t oldmask = umask(022);
2ff057
	lock->fd = open(lock_path, O_RDWR|O_CREAT, 0644);
2ff057
	(void) umask(oldmask);
2ff057
2ff057
	if (lock->fd == -1) {
2ff057
	    if (errno == EACCES)
2ff057
		lock->fd = open(lock_path, O_RDONLY);
2ff057
	    if (lock->fd == -1) {
2ff057
		free(lock);
2ff057
		lock = NULL;
2ff057
	    } else {
2ff057
		lock->openmode = RPMLOCK_READ;
2ff057
	    }
2ff057
	} else {
2ff057
	    lock->openmode = RPMLOCK_WRITE | RPMLOCK_READ;
2ff057
	}
2ff057
	if (lock) {
2ff057
	    lock->path = xstrdup(lock_path);
2ff057
	    lock->descr = xstrdup(descr);
2ff057
	    lock->fdrefs = 1;
2ff057
	}
2ff057
    }
2ff057
    return lock;
2ff057
}
2ff057
2ff057
static void rpmlock_free(rpmlock lock)
2ff057
{
2ff057
    if (--lock->fdrefs == 0) {
2ff057
	free(lock->path);
2ff057
	free(lock->descr);
2ff057
	(void) close(lock->fd);
2ff057
	free(lock);
2ff057
    }
2ff057
}
2ff057
2ff057
static int rpmlock_acquire(rpmlock lock, int mode)
2ff057
{
2ff057
    int res = 0;
2ff057
2ff057
    if (!(mode & lock->openmode))
2ff057
	return res;
2ff057
2ff057
    if (lock->fdrefs > 1) {
2ff057
	res = 1;
2ff057
    } else {
2ff057
	struct flock info;
2ff057
	int cmd;
2ff057
	if (mode & RPMLOCK_WAIT)
2ff057
	    cmd = F_SETLKW;
2ff057
	else
2ff057
	    cmd = F_SETLK;
2ff057
	if (mode & RPMLOCK_READ)
2ff057
	    info.l_type = F_RDLCK;
2ff057
	else
2ff057
	    info.l_type = F_WRLCK;
2ff057
	info.l_whence = SEEK_SET;
2ff057
	info.l_start = 0;
2ff057
	info.l_len = 0;
2ff057
	info.l_pid = 0;
2ff057
	if (fcntl(lock->fd, cmd, &info) != -1)
2ff057
	    res = 1;
2ff057
    }
2ff057
2ff057
    lock->fdrefs += res;
2ff057
2ff057
    return res;
2ff057
}
2ff057
2ff057
static void rpmlock_release(rpmlock lock)
2ff057
{
2ff057
    /* if not locked then we must not release */
2ff057
    if (lock->fdrefs <= 1)
2ff057
	return;
2ff057
2ff057
    if (--lock->fdrefs == 1) {
2ff057
	struct flock info;
2ff057
	info.l_type = F_UNLCK;
2ff057
	info.l_whence = SEEK_SET;
2ff057
	info.l_start = 0;
2ff057
	info.l_len = 0;
2ff057
	info.l_pid = 0;
2ff057
	(void) fcntl(lock->fd, F_SETLK, &info;;
2ff057
     }
2ff057
}
2ff057
2ff057
2ff057
/* External interface */
2ff057
rpmlock rpmlockNew(const char *lock_path, const char *descr)
2ff057
{
2ff057
    rpmlock lock = rpmlock_new(lock_path, descr);
2ff057
    if (!lock) {
2ff057
	rpmlog(RPMLOG_ERR, _("can't create %s lock on %s (%s)\n"), 
2ff057
		descr, lock_path, strerror(errno));
2ff057
    }
2ff057
    return lock;
2ff057
}
2ff057
2ff057
int rpmlockAcquire(rpmlock lock)
2ff057
{
2ff057
    int locked = 0; /* assume failure */
2ff057
    int myerrno = errno;
2ff057
    int maywait = isatty(STDIN_FILENO); /* dont wait within scriptlets */
2ff057
    errno = myerrno;
2ff057
2ff057
    if (lock) {
2ff057
	locked = rpmlock_acquire(lock, RPMLOCK_WRITE);
2ff057
	if (!locked && (lock->openmode & RPMLOCK_WRITE) && maywait) {
2ff057
	    rpmlog(RPMLOG_WARNING, _("waiting for %s lock on %s\n"),
2ff057
		    lock->descr, lock->path);
2ff057
	    locked = rpmlock_acquire(lock, (RPMLOCK_WRITE|RPMLOCK_WAIT));
2ff057
	}
2ff057
	if (!locked) {
2ff057
	    rpmlog(RPMLOG_ERR, _("can't create %s lock on %s (%s)\n"), 
2ff057
		   lock->descr, lock->path, strerror(errno));
2ff057
	}
2ff057
    }
2ff057
    return locked;
2ff057
}
2ff057
2ff057
void rpmlockRelease(rpmlock lock)
2ff057
{
2ff057
    if (lock)
2ff057
	rpmlock_release(lock);
2ff057
}
2ff057
2ff057
rpmlock rpmlockNewAcquire(const char *lock_path, const char *descr)
2ff057
{
2ff057
    rpmlock lock = rpmlockNew(lock_path, descr);
2ff057
    if (!rpmlockAcquire(lock))
2ff057
	lock = rpmlockFree(lock);
2ff057
    return lock;
2ff057
}
2ff057
2ff057
rpmlock rpmlockFree(rpmlock lock)
2ff057
{
2ff057
    if (lock) {
2ff057
	rpmlock_release(lock);
2ff057
	rpmlock_free(lock);
2ff057
    }
2ff057
    return NULL;
2ff057
}
2ff057
2ff057