#include <unistd.h>
#include <syslog.h>
#include <sys/mman.h>
#include <thread.h>
#include <synch.h>
#include <strings.h>
#include <ndbm.h>
#include "../ypsym.h"
#include "../ypdefs.h"
#include "shim.h"
#define LOCKFILE "/var/run/yp_maplock"
struct lockarray {
mutex_t locknode[MAXHASH];
};
typedef struct lockarray lockarray;
static struct lockarray *shmlockarray;
static int lockfile;
int
get_map_id(char *map_name, int index)
{
map_id_elt_t *cur_elt;
map_id_elt_t **map_list_p;
int max_map;
get_list_max(&map_list_p, &max_map);
cur_elt = map_list_p[index];
while (cur_elt != NULL) {
if (strcmp(map_name, cur_elt->map_name) == 0) {
return (cur_elt->map_id);
}
cur_elt = cur_elt->next;
}
syslog(LOG_WARNING, "get_map_id: no hash id found for %s"
", giving max_map value (%d)",
map_name, max_map);
return (max_map);
}
int
hash(char *s)
{
unsigned int n = 0;
int i;
char *map_name = s;
for (i = 1; *s; i += 10, s++) {
n += i * (*s);
}
n %= MAXHASH;
if (yptol_mode & yptol_newlock) {
return (get_map_id(map_name, n));
} else {
return (n);
}
}
bool
init_locks_mem()
{
int iiter, rc;
int ebusy_cnt = 0;
for (iiter = 0; iiter < MAXHASH; iiter++) {
if (rc = mutex_init(&(shmlockarray->locknode[iiter]),
USYNC_PROCESS | LOCK_ROBUST, 0)) {
if (rc == EBUSY) {
ebusy_cnt++;
} else {
syslog(LOG_ERR,
"init_locks_mem():mutex_init():error=%d",
rc);
return (FALSE);
}
}
}
if ((ebusy_cnt > 0) && (ebusy_cnt != MAXHASH)) {
syslog(LOG_ERR,
"%s inconsistent. Remove and restart NIS (YP).", LOCKFILE);
return (FALSE);
}
return (TRUE);
}
bool
init_lock_map()
{
char buff[ sizeof (lockarray) ];
int write_cnt, lf_size;
struct stat fdata;
lockfile = open(LOCKFILE, O_RDWR|O_CREAT, 0600);
if (lockfile != -1) {
if (lockf(lockfile, F_LOCK, 0) == 0) {
if (fstat(lockfile, &fdata) == 0) {
lf_size = fdata.st_size;
if (lf_size < sizeof (lockarray)) {
bzero(buff, sizeof (buff));
if ((write_cnt = write(lockfile, buff,
sizeof (buff)) != sizeof (buff))) {
if (write_cnt < 0) {
syslog(LOG_ERR,
"write(%s) => errno=%d",
LOCKFILE, errno);
} else {
syslog(LOG_ERR,
"write(%s) => %d!=%d: wrong number of bytes written.",
LOCKFILE,
write_cnt,
sizeof (buff));
}
lockf(lockfile, F_ULOCK, 0);
close(lockfile);
return (FALSE);
}
}
} else {
syslog(LOG_ERR,
"fstat(%s) => errno=%d", LOCKFILE, errno);
lockf(lockfile, F_ULOCK, 0);
close(lockfile);
return (FALSE);
}
} else {
syslog(LOG_ERR,
"lockf(%s,F_LOCK) => errno=%d", LOCKFILE, errno);
close(lockfile);
return (FALSE);
}
} else {
syslog(LOG_ERR,
"open(%s) => errno=%d", LOCKFILE, errno);
return (FALSE);
}
shmlockarray = (lockarray *)mmap((caddr_t)0, sizeof (lockarray),
PROT_READ | PROT_WRITE, MAP_SHARED, lockfile, 0);
if (shmlockarray == MAP_FAILED) {
syslog(LOG_ERR, "mmap(%s) => errno=%d", LOCKFILE, errno);
lockf(lockfile, F_ULOCK, 0);
close(lockfile);
return (FALSE);
}
if (lf_size < sizeof (lockarray)) {
if (init_locks_mem() == FALSE) {
lockf(lockfile, F_ULOCK, 0);
close(lockfile);
if (remove(LOCKFILE) != 0) {
syslog(LOG_ERR,
"remove(%s) => errno=%d: Please delete file.",
LOCKFILE, errno);
}
return (FALSE);
}
}
if (lockf(lockfile, F_ULOCK, 0) != 0) {
syslog(LOG_ERR,
"lockf(%s,F_ULOCK) => errno=%d",
LOCKFILE, errno);
close(lockfile);
return (FALSE);
}
if (close(lockfile) == 0) {
return (TRUE);
} else {
syslog(LOG_ERR,
"close(%s) => errno=%d", LOCKFILE, errno);
return (FALSE);
}
}
int
lock_map(char *mapname)
{
int hashval;
hashval = hash(mapname);
return (lock_core(hashval));
}
int
lock_core(int hashval)
{
int rc;
rc = mutex_lock(&(shmlockarray->locknode[hashval]));
while (rc != 0) {
switch (rc) {
case EOWNERDEAD:
rc = mutex_consistent(
&(shmlockarray->locknode[hashval]));
if (rc != 0) {
syslog(LOG_ERR,
"mutex_consistent(): error=%d", rc);
return (0);
}
rc = mutex_unlock(&(shmlockarray->locknode[hashval]));
if (rc != 0) {
syslog(LOG_ERR,
"mutex_unlock(): error=%d", rc);
return (0);
}
break;
default:
syslog(LOG_ERR,
"mutex_lock(): error=%d", rc);
syslog(LOG_ERR,
"Please restart NIS (ypstop/ypstart).");
if (remove(LOCKFILE) != 0) {
syslog(LOG_ERR,
"remove(%s) => errno=%d: Please delete file.",
LOCKFILE, errno);
}
return (0);
}
rc = mutex_lock(&(shmlockarray->locknode[hashval]));
}
return (1);
}
int
unlock_map(char *mapname)
{
int hashval;
hashval = hash(mapname);
return (unlock_core(hashval));
}
int
unlock_core(int hashval)
{
int rc;
rc = mutex_unlock(&(shmlockarray->locknode[hashval]));
if (rc != 0) {
syslog(LOG_ERR,
"mutex_unlock(): error=%d", rc);
syslog(LOG_ERR,
"Please restart NIS (ypstop/ypstart).");
if (remove(LOCKFILE) != 0) {
syslog(LOG_ERR,
"remove(%s) => errno=%d: Please delete file.",
LOCKFILE, errno);
}
return (0);
}
return (1);
}