#define __EXTENSIONS__
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <locale.h>
#include <libgen.h>
#include <sys/param.h>
#include <errno.h>
#include <assert.h>
#include <time.h>
#include <fnmatch.h>
#include <zone.h>
#include <libinst.h>
#include <pkglib.h>
#include "pkgadm.h"
#include "pkgadm_msgs.h"
#define SECONDS(x) ((unsigned int)(x))
#define MINUTES(x) ((unsigned int)(seconds(x)*60))
#define WAITER_INITIAL SECONDS(1)
#define WAITER_MAX SECONDS(60)
#define WAITER_NEXT(x) ((x)*2)
typedef unsigned int WAITER_T;
#define LOCK_OBJECT_MAXLEN 512-1
#define LOCK_KEY_MAXLEN 37
#define LOCK_DIRECTORY "/tmp"
#define LOCK_FILENAME \
"/tmp/.ai.pkg.zone.lock-afdb66cf-1dd1-11b2-a049-000d560ddc3e"
#define LOCK_FILEMODE \
(S_ISGID|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
#define LOCK_SLEEP_INTERVAL SECONDS(2)
typedef unsigned long RECORDNUM_T;
#define RECORDNUM_NONE 0xFFFFFFFF
struct _adminLock
{
RECORDNUM_T lockRecordNum;
unsigned long lockCount;
unsigned long lockExclusive;
pid_t lockPid;
zoneid_t lockZoneId;
char lockKey[LOCK_KEY_MAXLEN+1];
char lockObject[LOCK_OBJECT_MAXLEN+1];
};
typedef struct _adminLock ADMINLOCK_T;
#define LOCK_SIZE sizeof (ADMINLOCK_T)
union _lockRecord
{
char _lrLockData[LOCK_SIZE];
ADMINLOCK_T _lrLock;
};
typedef union _lockRecord LOCK_T;
typedef unsigned long FINDLOCK_T;
#define FINDLOCK_FOUND ((FINDLOCK_T)0)
#define FINDLOCK_ERROR ((FINDLOCK_T)-1)
#define FINDLOCK_NOTFOUND ((FINDLOCK_T)-2)
#define FINDLOCK_KEYMISMATCH ((FINDLOCK_T)-3)
#define FINDLOCK_LOCKED ((FINDLOCK_T)-4)
#define FINDLOCK_NOTLOCKED ((FINDLOCK_T)-5)
#define FINDLOCK_LOCKACQUIRED ((FINDLOCK_T)-6)
static FINDLOCK_T lock_acquire(LOCK_T *a_lock, int *a_fd, char *a_root,
char *a_key, char *a_object, int a_quiet,
int a_wait, long a_timeout, int a_exclusive,
char *a_altRoot, pid_t a_pid, zoneid_t a_zid);
static int lock_release(int a_fd, char *a_key, char *a_object,
int a_quiet);
static int lock_status(int a_fd, char *a_key, char *a_object,
int a_quiet);
static int _lockMatch(char *a_s1Lock, char *a_s2Lock);
static FINDLOCK_T _findLock(LOCK_T *a_theLock, RECORDNUM_T *r_recordNum,
int a_fd, char *a_object, char *a_key);
static int _decrementLockCount(int a_fd, LOCK_T *a_theLock);
static int _addLock(char *r_key, int a_fd, char *a_object,
int a_exclusive, pid_t a_pid, zoneid_t a_zid);
static int _incrementLockCount(int a_fd, LOCK_T *a_theLock);
static FINDLOCK_T _lock_acquire(LOCK_T *a_lock, int a_fd, char *a_key,
char *a_object, int a_quiet, int a_exclusive,
pid_t a_pid, zoneid_t a_zid);
static char *_getUniqueId(void);
static int _openLockFile(char *a_root);
static void sighup_handler(int a_signo);
static void sigint_handler(int a_signo);
static boolean_t _validateLock(int a_fd, LOCK_T *a_theLock, int a_quiet);
static int signal_received = 0;
int
admin_lock(int argc, char **argv)
{
FINDLOCK_T tResult;
LOCK_T theLock;
char *RFlag = "/";
char *endptr;
char *kFlag = "";
char *oFlag = "";
char *p;
int c;
int aFlag = 0;
int eFlag = 0;
int exclusive = 1;
int fd;
int qFlag = 0;
int rFlag = 0;
int result;
int sFlag = 0;
int tFlag = 0;
int wFlag = 0;
long WFlag = 0;
pid_t pFlag = 0;
struct sigaction nact;
struct sigaction oact;
zoneid_t zFlag = -1;
while ((c = getopt(argc, argv, ":aek:o:p:qrR:stwW:z:")) != EOF) {
switch (c) {
case 'a':
aFlag++;
break;
case 'e':
eFlag++;
break;
case 'k':
kFlag = optarg;
if (strlen(optarg) > LOCK_KEY_MAXLEN) {
log_msg(LOG_MSG_ERR,
MSG_LOCK_kARG_TOOLONG,
strlen(optarg), LOCK_KEY_MAXLEN);
return (1);
}
break;
case 'o':
oFlag = optarg;
if (strlen(optarg) > LOCK_OBJECT_MAXLEN) {
log_msg(LOG_MSG_ERR,
MSG_LOCK_oARG_TOOLONG,
strlen(optarg), LOCK_OBJECT_MAXLEN);
return (1);
}
break;
case 'p':
errno = 0;
endptr = 0;
pFlag = strtol(optarg, &endptr, 10);
if ((endptr != (char *)NULL) && (*endptr != '\0')) {
log_msg(LOG_MSG_ERR, MSG_LOCK_pFLAG_BADINT,
optarg, *endptr);
return (1);
}
if ((pFlag == 0) && (errno != 0)) {
log_msg(LOG_MSG_ERR,
MSG_LOCK_pFLAG_ERROR,
optarg, strerror(errno));
return (1);
}
break;
case 'q':
qFlag++;
break;
case 'r':
rFlag++;
break;
case 'R':
if (*optarg != '/') {
log_msg(LOG_MSG_ERR,
MSG_LOCK_RARG_NOT_ABSOLUTE, optarg);
return (1);
}
if (access(optarg, F_OK) != 0) {
if (mkdirp(optarg, 0755) != 0) {
log_msg(LOG_MSG_ERR,
MSG_LOCK_ALTROOT_CANTCREATE,
optarg, strerror(errno));
return (1);
}
}
p = pkgstrPrintf("%s/tmp", optarg);
if (access(p, F_OK) != 0) {
if (mkdirp(p, 0777) != 0) {
log_msg(LOG_MSG_ERR,
MSG_LOCK_ALTROOT_CANTCREATE,
p, strerror(errno));
return (1);
}
}
if (access(p, F_OK) != 0) {
log_msg(LOG_MSG_ERR, MSG_LOCK_ALTROOT_NONEXIST,
optarg, strerror(errno));
return (1);
}
(void) free(p);
RFlag = optarg;
break;
case 's':
sFlag++;
break;
case 't':
tFlag++;
break;
case 'w':
wFlag++;
break;
case 'W':
errno = 0;
endptr = 0;
WFlag = strtol(optarg, &endptr, 10);
if ((endptr != (char *)NULL) && (*endptr != '\0')) {
log_msg(LOG_MSG_ERR, MSG_LOCK_WFLAG_BADINT,
optarg, *endptr);
return (1);
}
if ((WFlag == 0) && (errno != 0)) {
log_msg(LOG_MSG_ERR,
MSG_LOCK_WFLAG_ERROR,
optarg, strerror(errno));
return (1);
}
wFlag++;
break;
case 'z':
errno = 0;
endptr = 0;
zFlag = strtol(optarg, &endptr, 10);
if ((endptr != (char *)NULL) && (*endptr != '\0')) {
log_msg(LOG_MSG_ERR, MSG_LOCK_zFLAG_BADINT,
optarg, *endptr);
return (1);
}
if ((zFlag == 0) && (errno != 0)) {
log_msg(LOG_MSG_ERR,
MSG_LOCK_zFLAG_ERROR,
optarg, strerror(errno));
return (1);
}
break;
case ':':
log_msg(LOG_MSG_ERR, MSG_MISSING_OPERAND, optopt);
case '?':
default:
log_msg(LOG_MSG_ERR, MSG_USAGE);
return (1);
}
}
if (tFlag) {
int rs = 0;
int rx;
int a;
a = argc-optind;
if ((a < 2) || (a > 3)) {
(void) fprintf(stderr, MSG_T_OPTION_ARGS, argc-optind);
return (1);
}
if (a == 3) {
rs = atoi(argv[optind+2]);
}
rx = _lockMatch(argv[optind+0], argv[optind+1]);
if (a == 2) {
rs = rx;
}
if (a == 2) {
(void) fprintf(stderr, MSG_T_RESULT_TWO,
rx, argv[optind+0], argv[optind+1]);
return (rx);
}
if (rx != rs) {
(void) fprintf(stderr, MSG_T_RESULT_THREE,
rs, rx, argv[optind+0], argv[optind+1]);
}
return (rx == rs ? 0 : 1);
}
if ((argc-optind) > 0) {
log_msg(LOG_MSG_ERR, MSG_USAGE);
return (1);
}
if (aFlag && rFlag) {
log_msg(LOG_MSG_ERR, MSG_LOCK_ar_TOGETHER);
return (1);
}
if (eFlag && sFlag) {
log_msg(LOG_MSG_ERR, MSG_LOCK_es_TOGETHER);
return (1);
}
if (!aFlag && eFlag) {
log_msg(LOG_MSG_ERR, MSG_LOCK_e_without_a);
return (1);
}
if (!aFlag && sFlag) {
log_msg(LOG_MSG_ERR, MSG_LOCK_s_without_a);
return (1);
}
(void) sighold(SIGHUP);
(void) sighold(SIGINT);
nact.sa_handler = sigint_handler;
nact.sa_flags = SA_RESTART;
(void) sigemptyset(&nact.sa_mask);
(void) sigaction(SIGINT, &nact, &oact);
nact.sa_handler = sighup_handler;
nact.sa_flags = SA_RESTART;
(void) sigemptyset(&nact.sa_mask);
(void) sigaction(SIGHUP, &nact, &oact);
(void) sigrelse(SIGHUP);
(void) sigrelse(SIGINT);
fd = _openLockFile(RFlag);
if (fd < 0) {
return (1);
}
if (aFlag) {
if (sFlag) {
exclusive = 0;
} else if (eFlag) {
exclusive = 1;
}
tResult = lock_acquire(&theLock, &fd, RFlag, kFlag, oFlag,
qFlag, wFlag, WFlag, exclusive, RFlag, pFlag, zFlag);
switch (tResult) {
case FINDLOCK_LOCKACQUIRED:
(void) fprintf(stdout, "%s\n",
theLock._lrLock.lockKey);
result = 0;
break;
case FINDLOCK_LOCKED:
(void) fprintf(stdout, "%s\n",
theLock._lrLock.lockObject);
result = 1;
break;
default:
result = 1;
break;
}
} else if (rFlag) {
result = lock_release(fd, kFlag, oFlag, qFlag);
} else {
result = lock_status(fd, kFlag, oFlag, qFlag);
}
(void) close(fd);
return (result);
}
static FINDLOCK_T
lock_acquire(LOCK_T *a_theLock, int *a_fd, char *a_root, char *a_key,
char *a_object, int a_quiet, int a_wait, long a_timeout,
int a_exclusive, char *a_altRoot, pid_t a_pid, zoneid_t a_zid)
{
int notified = 0;
FINDLOCK_T result;
time_t timeout;
int closeOnExit = 0;
bzero(a_theLock, sizeof (LOCK_T));
if ((*a_fd) < 0) {
(*a_fd) = _openLockFile(a_altRoot);
if ((*a_fd) < 0) {
return (FINDLOCK_ERROR);
}
closeOnExit++;
}
timeout = time((time_t *)NULL) + a_timeout;
for (;;) {
time_t curtime;
result = _lock_acquire(a_theLock, *a_fd, a_key, a_object,
a_quiet, a_exclusive, a_pid, a_zid);
switch (result) {
case FINDLOCK_LOCKACQUIRED:
if (closeOnExit) {
(void) close(*a_fd);
*a_fd = -1;
}
return (FINDLOCK_LOCKACQUIRED);
case FINDLOCK_FOUND:
case FINDLOCK_NOTFOUND:
case FINDLOCK_KEYMISMATCH:
case FINDLOCK_NOTLOCKED:
case FINDLOCK_ERROR:
default:
if (closeOnExit) {
(void) close(*a_fd);
*a_fd = -1;
}
return (result);
case FINDLOCK_LOCKED:
;
}
if ((a_wait == 0) || (signal_received != 0)) {
log_msg(a_quiet ? LOG_MSG_DEBUG : LOG_MSG_ERR,
MSG_LOCK_ACQUIRE_BUSY_FIRST,
a_exclusive ? MSG_LOCK_EXC : MSG_LOCK_SHR,
a_object, a_key,
a_theLock->_lrLock.lockObject,
a_theLock->_lrLock.lockExclusive ?
MSG_LOCK_EXC : MSG_LOCK_SHR,
a_theLock->_lrLock.lockExclusive !=
a_exclusive ? "" :
MSG_LOCK_ACQUIRE_BUSY_ADDITIONAL);
if (closeOnExit) {
(void) close(*a_fd);
*a_fd = -1;
}
return (FINDLOCK_LOCKED);
}
if (a_timeout > 0) {
curtime = time((time_t *)NULL);
if (curtime > timeout) {
log_msg(a_quiet ? LOG_MSG_DEBUG : LOG_MSG_ERR,
MSG_LOCK_ACQUIRE_TIMEDOUT,
a_exclusive ?
MSG_LOCK_EXC : MSG_LOCK_SHR,
a_object, a_key);
if (closeOnExit) {
(void) close(*a_fd);
*a_fd = -1;
}
return (FINDLOCK_ERROR);
}
}
if (notified++ == 0) {
log_msg(a_quiet ? LOG_MSG_DEBUG : LOG_MSG_WRN,
MSG_LOCK_ACQUIRE_WAITING,
a_object);
}
(void) close(*a_fd);
(void) sleep(LOCK_SLEEP_INTERVAL);
*a_fd = _openLockFile(a_root);
if (*a_fd < 0) {
log_msg(LOG_MSG_ERR, MSG_LOCK_ACQUIRE_REOPEN_FAILED,
a_object);
if (closeOnExit) {
(void) close(*a_fd);
*a_fd = -1;
}
return (FINDLOCK_ERROR);
}
}
}
static int
lock_release(int a_fd, char *a_key, char *a_object, int a_quiet)
{
RECORDNUM_T recordNum;
LOCK_T theLock;
FINDLOCK_T result;
log_msg(LOG_MSG_DEBUG, MSG_LOCK_RELEASE_ENTRY,
a_key, a_object, a_quiet);
result = _findLock(&theLock, &recordNum, a_fd, a_object, a_key);
log_msg(LOG_MSG_DEBUG, MSG_LOCK_RELEASE_FINDRESULT,
result, recordNum);
switch (result) {
case FINDLOCK_NOTLOCKED:
log_msg(a_quiet ? LOG_MSG_DEBUG : LOG_MSG_ERR,
MSG_LOCK_RELEASE_NOTLOCKED,
a_object, a_key);
return (result);
case FINDLOCK_LOCKED:
log_msg(a_quiet ? LOG_MSG_DEBUG : LOG_MSG_ERR,
MSG_LOCK_RELEASE_LOCKED,
a_object, a_key);
return (result);
case FINDLOCK_NOTFOUND:
log_msg(a_quiet ? LOG_MSG_DEBUG : LOG_MSG_ERR,
MSG_LOCK_RELEASE_NOTFOUND,
a_object, a_key);
return (result);
case FINDLOCK_KEYMISMATCH:
log_msg(a_quiet ? LOG_MSG_DEBUG : LOG_MSG_ERR,
MSG_LOCK_RELEASE_KEYMISMATCH,
a_object);
return (result);
case FINDLOCK_ERROR:
log_msg(a_quiet ? LOG_MSG_DEBUG : LOG_MSG_ERR,
MSG_LOCK_RELEASE_ERROR,
a_object, a_key);
perror(LOCK_FILENAME);
return (result);
case FINDLOCK_FOUND:
log_msg(LOG_MSG_DEBUG, MSG_LOCK_RELEASE_FOUND,
a_object, a_key);
(void) _decrementLockCount(a_fd, &theLock);
break;
default:
result = FINDLOCK_ERROR;
break;
}
return (result);
}
static int
lock_status(int a_fd, char *a_key, char *a_object, int a_quiet)
{
ADMINLOCK_T *pll;
LOCK_T theLock;
RECORDNUM_T recordNum = 0;
char *pld;
int found = 0;
long pls;
log_msg(LOG_MSG_DEBUG, MSG_LOCK_STATUS_ENTRY,
a_key, a_object);
pld = &theLock._lrLockData[0];
pll = &theLock._lrLock;
pls = sizeof (theLock._lrLockData);
bzero(pld, pls);
for (; pread(a_fd, pld, pls, pls*recordNum) == pls; recordNum++) {
log_msg(LOG_MSG_DEBUG, MSG_LOCK_STATUS_READRECORD,
recordNum, pll->lockCount,
pll->lockObject, pll->lockKey, pll->lockPid,
pll->lockZoneId);
if ((*a_key != '\0') &&
(strcmp(pll->lockKey, a_key) != 0)) {
continue;
}
if ((*a_object != '\0') &&
(strcmp(pll->lockObject, a_object) != 0)) {
continue;
}
found++;
if (a_quiet != 0) {
continue;
}
if (found == 1) {
(void) fprintf(stdout,
"%2s %2s %3s %8s %3s %9s %37s %s\n",
"i#", "l#", "cnt", "pid", "zid", "lock-type",
"---------------lock-key-------------",
"lock-object");
}
(void) fprintf(stdout,
"%2ld %2ld %3ld %8ld %3d %9s %37s %s\n",
recordNum, pll->lockRecordNum, pll->lockCount,
pll->lockPid, pll->lockZoneId,
pll->lockExclusive ? MSG_LOCK_EXC : MSG_LOCK_SHR,
pll->lockKey,
*pll->lockObject == '\0' ? "*" : pll->lockObject);
}
return (found == 0 ? 1 : 0);
}
static FINDLOCK_T
_lock_acquire(LOCK_T *a_theLock, int a_fd, char *a_key,
char *a_object, int a_quiet, int a_exclusive, pid_t a_pid,
zoneid_t a_zid)
{
RECORDNUM_T recordNum;
FINDLOCK_T result;
char key[LOCK_KEY_MAXLEN+1] = {'\0'};
log_msg(LOG_MSG_DEBUG, MSG_LOCK_ACQUIRE_ENTRY,
a_key, a_object, a_quiet, a_exclusive);
for (;;) {
result = _findLock(a_theLock, &recordNum, a_fd, a_object,
a_key);
if (result != FINDLOCK_LOCKED) {
break;
}
if (_validateLock(a_fd, a_theLock, a_quiet) == B_TRUE) {
break;
}
}
log_msg(LOG_MSG_DEBUG, MSG_LOCK_ACQUIRE_FINDRESULT,
a_exclusive ? MSG_LOCK_EXC : MSG_LOCK_SHR,
result, recordNum);
switch (result) {
case FINDLOCK_NOTLOCKED:
log_msg(a_quiet ? LOG_MSG_DEBUG : LOG_MSG_ERR,
MSG_LOCK_ACQUIRE_NOTLOCKED,
a_exclusive ? MSG_LOCK_EXC : MSG_LOCK_SHR,
a_object, a_key);
break;
case FINDLOCK_LOCKED:
if (a_theLock->_lrLock.lockExclusive) {
break;
}
if (a_exclusive) {
break;
}
log_msg(LOG_MSG_DEBUG,
MSG_LOCK_ACQUIRE_LOCKED_SHARED,
a_object, a_key);
if (_incrementLockCount(a_fd, a_theLock) == 0) {
result = FINDLOCK_LOCKACQUIRED;
} else {
result = FINDLOCK_ERROR;
}
break;
case FINDLOCK_NOTFOUND:
log_msg(LOG_MSG_DEBUG,
MSG_LOCK_ACQUIRE_NOTFOUND,
a_exclusive ? MSG_LOCK_EXC : MSG_LOCK_SHR,
a_object);
if (_addLock(key, a_fd, a_object, a_exclusive,
a_pid, a_zid) == 0) {
(void) strncpy(a_theLock->_lrLock.lockKey, key,
sizeof (a_theLock->_lrLock.lockKey));
result = FINDLOCK_LOCKACQUIRED;
} else {
result = FINDLOCK_ERROR;
}
break;
case FINDLOCK_KEYMISMATCH:
log_msg(a_quiet ? LOG_MSG_DEBUG : LOG_MSG_ERR,
MSG_LOCK_ACQUIRE_KEYMISMATCH,
a_exclusive ? MSG_LOCK_EXC : MSG_LOCK_SHR,
a_object);
break;
case FINDLOCK_ERROR:
log_msg(LOG_MSG_ERR, MSG_LOCK_ACQUIRE_ERROR,
a_object, a_key, strerror(errno));
break;
case FINDLOCK_FOUND:
if (a_exclusive != a_theLock->_lrLock.lockExclusive) {
result = FINDLOCK_LOCKED;
break;
}
log_msg(LOG_MSG_DEBUG, MSG_LOCK_ACQUIRE_FOUND_INC,
a_object, a_key,
a_exclusive ? MSG_LOCK_EXC : MSG_LOCK_SHR);
if (_incrementLockCount(a_fd, a_theLock) == 0) {
result = FINDLOCK_LOCKACQUIRED;
} else {
result = FINDLOCK_ERROR;
}
break;
default:
result = FINDLOCK_ERROR;
break;
}
return (result);
}
static int
_openLockFile(char *a_root)
{
WAITER_T waiter;
char lockpath[MAXPATHLEN];
int fd;
int result;
log_msg(LOG_MSG_DEBUG, MSG_LOCK_OPENFILE_ENTRY,
a_root, LOCK_FILENAME);
(void) snprintf(lockpath, sizeof (lockpath), "%s/%s",
a_root, LOCK_DIRECTORY);
if (access(lockpath, F_OK) != 0) {
log_msg(LOG_MSG_ERR, MSG_LOCK_ROOTDIR_INVALID,
lockpath, strerror(errno));
return (-1);
}
(void) snprintf(lockpath, sizeof (lockpath),
"%s/%s", a_root, LOCK_FILENAME);
for (waiter = WAITER_INITIAL;
waiter < WAITER_MAX;
waiter = WAITER_NEXT(waiter)) {
fd = open(lockpath, O_CREAT|O_RDWR, LOCK_FILEMODE);
if (fd >= 0) {
break;
}
if (errno == EACCES) {
break;
}
if (waiter == WAITER_INITIAL) {
log_msg(LOG_MSG_DEBUG,
MSG_LOCK_OPENFILE_SLEEPING,
strerror(errno), waiter);
}
(void) sleep(waiter);
}
if (fd < 0) {
log_msg(LOG_MSG_DEBUG, MSG_LOCK_OPENFILE_FAILURE,
strerror(errno));
perror(lockpath);
return (-1);
}
for (waiter = WAITER_INITIAL;
waiter < WAITER_MAX;
waiter = WAITER_NEXT(waiter)) {
result = lockf(fd, F_LOCK, 0xFFFFF);
if (result == 0) {
break;
}
if (waiter == WAITER_INITIAL) {
log_msg(LOG_MSG_DEBUG, MSG_LOCK_OPENFILE_SLEEP2,
strerror(errno), waiter);
}
(void) sleep(waiter);
}
if (result < 0) {
log_msg(LOG_MSG_DEBUG, MSG_LOCK_OPENFILE_FAIL2,
strerror(errno));
perror(lockpath);
(void) close(fd);
return (-1);
}
log_msg(LOG_MSG_DEBUG, MSG_LOCK_OPENFILE_SUCCESS, fd);
return (fd);
}
static int
_lockMatch(char *a_s1Lock, char *a_s2Lock)
{
boolean_t s1Sfx = B_FALSE;
boolean_t s2Sfx = B_FALSE;
char *final1Lock = (char *)NULL;
char *final2Lock = (char *)NULL;
char s1Buf[MAXPATHLEN] = {'\0'};
char s1Prefix[MAXPATHLEN] = {'\0'};
char s2Buf[MAXPATHLEN] = {'\0'};
char s2Prefix[MAXPATHLEN] = {'\0'};
int result = 0;
int s1Cnt;
int s2Cnt = 0;
assert(a_s1Lock != (char *)NULL);
assert(a_s2Lock != (char *)NULL);
log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_ENTRY, a_s1Lock, a_s2Lock);
for (s1Cnt = 0; ; s1Cnt++) {
pkgstrGetToken_r((char *)NULL, a_s1Lock, s1Cnt, "/",
s1Buf, sizeof (s1Buf));
log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_FSTNODE, s1Cnt, s1Buf);
if (s1Buf[0] == '\0') {
break;
}
pkgstrGetToken_r((char *)NULL, s1Buf, 0, ".", s1Prefix,
sizeof (s1Prefix));
s1Sfx = (strlen(s1Prefix) == strlen(s1Buf) ? B_FALSE : B_TRUE);
for (s2Cnt = 0; ; s2Cnt++) {
pkgstrGetToken_r((char *)NULL, a_s2Lock, s2Cnt, "/",
s2Buf, sizeof (s2Buf));
log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_SCNDNODE, s2Cnt,
s2Buf);
if (s2Buf[0] == '\0') {
break;
}
pkgstrGetToken_r((char *)NULL, s2Buf, 0, ".", s2Prefix,
sizeof (s2Prefix));
s2Sfx = (strlen(s2Prefix) ==
strlen(s2Buf) ? B_FALSE : B_TRUE);
log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_NODES, s1Buf,
s1Prefix, s1Sfx, s2Buf, s2Prefix, s2Sfx);
if ((s1Sfx == B_FALSE) || (s2Sfx == B_FALSE)) {
if (strcmp(s1Buf, s2Buf) == 0) {
log_msg(LOG_MSG_DEBUG,
MSG_LCKMCH_DIRMCH,
s1Buf, s2Buf);
break;
}
log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_DIRNOMCH,
s1Buf, s2Buf);
continue;
}
if (strcmp(s1Prefix, s2Prefix) == 0) {
log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_PFXMCH,
s1Prefix, s2Prefix);
break;
}
log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_PFXNOMCH, s1Prefix,
s2Prefix);
}
if (s2Buf[0] != '\0') {
break;
}
}
log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_FSTLCK, s1Cnt, s1Buf,
s1Prefix, s1Sfx);
log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_SCNDLCK, s2Cnt, s2Buf,
s2Prefix, s2Sfx);
if ((s1Buf[0] == '\0') && (s2Buf[0] == '\0')) {
if (((s1Cnt == 1) || (s2Cnt == 1)) &&
((s1Sfx == B_FALSE) || (s2Sfx == B_FALSE))) {
log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_ABSNOMCH, a_s1Lock,
a_s2Lock);
return (1);
}
log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_OBJMCH, a_s1Lock, a_s2Lock);
return (0);
}
if ((s2Buf[0] != '\0') && (s1Buf[0] != '\0') &&
(s1Cnt > 0) && (s2Cnt > 0)) {
log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_OVLPNOMCH, a_s1Lock, a_s2Lock,
s1Cnt+1, s1Buf);
return (1);
}
final1Lock = a_s1Lock;
final2Lock = a_s2Lock;
if ((s1Cnt == 0) && (s2Cnt == 0)) {
log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_SAME, a_s1Lock, a_s2Lock,
s1Buf);
} else if ((s1Cnt != 0) && (s2Cnt == 0) && (s2Buf[0] != '\0')) {
log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_SCNDSUB, a_s2Lock, a_s1Lock,
s1Cnt+1, s1Buf);
if (strchr(a_s1Lock, '/') != (char *)NULL) {
for (; s1Cnt > 0 && (*final1Lock != '\0');
final1Lock++) {
if (*final1Lock == '/') {
s1Cnt--;
}
}
}
} else if ((s2Cnt != 0) && (s1Cnt == 0) && (s1Buf[0] != '\0')) {
log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_FRSTSUB, a_s1Lock, a_s2Lock,
s2Cnt+1, s2Buf);
if (strchr(a_s2Lock, '/') != (char *)NULL) {
for (; s2Cnt > 0 && (*final2Lock != '\0');
final2Lock++) {
if (*final2Lock == '/') {
s2Cnt--;
}
}
}
} else {
log_msg(LOG_MSG_ERR, MSG_LCKMCH_DONTKNOW, a_s1Lock, a_s2Lock);
}
log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_READY, final1Lock, final2Lock);
for (s1Cnt = 0; ; s1Cnt++) {
pkgstrGetToken_r((char *)NULL, final1Lock, s1Cnt, "/", s1Buf,
sizeof (s1Buf));
if (s1Buf[0] == '\0') {
break;
}
pkgstrGetToken_r((char *)NULL, final2Lock, s1Cnt, "/", s2Buf,
sizeof (s2Buf));
if (s2Buf[0] == '\0') {
break;
}
result = fnmatch(s1Buf, s2Buf, 0);
if (result != 0) {
result = fnmatch(s2Buf, s1Buf, 0);
}
if (result != 0) {
log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_NODEFAIL,
s1Cnt, s1Buf, s2Buf);
return (1);
}
log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_NODEOK, s1Cnt, s1Buf, s2Buf);
}
log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_MATCHOK, final1Lock, final2Lock);
return (0);
}
static FINDLOCK_T
_findLock(LOCK_T *a_theLock, RECORDNUM_T *r_recordNum,
int a_fd, char *a_object, char *a_key)
{
ADMINLOCK_T *pll;
char *pld;
int recordNum = 0;
long pls;
off_t pos;
*r_recordNum = RECORDNUM_NONE;
pld = &a_theLock->_lrLockData[0];
pll = &a_theLock->_lrLock;
pls = sizeof (a_theLock->_lrLockData);
bzero(pld, pls);
log_msg(LOG_MSG_DEBUG, MSG_LOCK_FINDLOCK_ENTRY,
a_object, a_key);
pos = lseek(a_fd, 0L, SEEK_SET);
if (pos == (off_t)-1) {
log_msg(LOG_MSG_ERR, MSG_LOCK_FINDLOCK_LSEEK_FAILURE,
a_object, a_key, strerror(errno));
return (FINDLOCK_ERROR);
}
for (; pread(a_fd, pld, pls, pls*recordNum) == pls; recordNum++) {
log_msg(LOG_MSG_DEBUG, MSG_LOCK_FINDLOCK_READRECORD,
recordNum, pll->lockCount,
pll->lockObject, pll->lockKey, pll->lockPid,
pll->lockZoneId);
if (_lockMatch(a_object, pll->lockObject) != 0) {
continue;
}
if (*a_key == '\0') {
*r_recordNum = recordNum;
return (FINDLOCK_LOCKED);
}
if (strcmp(pll->lockKey, a_key) != 0) {
*r_recordNum = recordNum;
return (FINDLOCK_KEYMISMATCH);
}
log_msg(LOG_MSG_DEBUG, MSG_LOCK_FINDLOCK_FOUND);
*r_recordNum = recordNum;
return (FINDLOCK_FOUND);
}
if (*a_key != '\0') {
return (FINDLOCK_NOTLOCKED);
}
log_msg(LOG_MSG_DEBUG, MSG_LOCK_FINDLOCK_NOTFOUND);
return (FINDLOCK_NOTFOUND);
}
static int
_addLock(char *r_key, int a_fd, char *a_object, int a_exclusive, pid_t a_pid,
zoneid_t a_zid)
{
LOCK_T theLock;
char *key;
off_t pos;
ssize_t result;
key = _getUniqueId();
pos = lseek(a_fd, 0L, SEEK_END);
if (pos == (off_t)-1) {
log_msg(LOG_MSG_ERR, MSG_LOCK_ADDLOCK_LSEEK_FAILURE,
a_exclusive ? MSG_LOCK_EXC : MSG_LOCK_SHR,
a_object, strerror(errno));
return (1);
}
bzero(&theLock, sizeof (theLock));
(void) strlcpy(theLock._lrLock.lockObject, a_object,
LOCK_OBJECT_MAXLEN);
(void) strlcpy(theLock._lrLock.lockKey, key, LOCK_KEY_MAXLEN);
theLock._lrLock.lockCount = 1;
theLock._lrLock.lockPid = (a_pid > 0 ? a_pid : 0);
theLock._lrLock.lockRecordNum = (pos == 0 ? 0 : (pos/sizeof (LOCK_T)));
theLock._lrLock.lockExclusive = a_exclusive;
theLock._lrLock.lockZoneId = (a_zid >= 0 ? a_zid : -1);
log_msg(LOG_MSG_DEBUG, MSG_LOCK_ADDLOCK_ADDING,
a_exclusive ? MSG_LOCK_EXC : MSG_LOCK_SHR,
pos, theLock._lrLock.lockObject, theLock._lrLock.lockKey,
theLock._lrLock.lockPid, theLock._lrLock.lockZoneId);
result = pwrite(a_fd, &theLock, LOCK_SIZE, pos);
if (result != LOCK_SIZE) {
log_msg(LOG_MSG_ERR, MSG_LOCK_ADDLOCK_PWRITE_FAILURE,
a_exclusive ? MSG_LOCK_EXC : MSG_LOCK_SHR,
a_object, strerror(errno));
return (1);
}
(void) strncpy(r_key, key, LOCK_KEY_MAXLEN);
return (0);
}
static int
_incrementLockCount(int a_fd, LOCK_T *a_theLock)
{
ADMINLOCK_T *pll;
char *pld;
long pls;
ssize_t result;
pld = &a_theLock->_lrLockData[0];
pll = &a_theLock->_lrLock;
pls = sizeof (a_theLock->_lrLockData);
log_msg(LOG_MSG_DEBUG, MSG_LOCK_INCLOCK_ENTRY,
a_theLock->_lrLock.lockExclusive ?
MSG_LOCK_EXC : MSG_LOCK_SHR,
pll->lockRecordNum, pll->lockCount);
pll->lockCount++;
result = pwrite(a_fd, pld, pls, pll->lockRecordNum*pls);
if (result != pls) {
log_msg(LOG_MSG_ERR, MSG_LOCK_INCLOCK_PWRITE_FAILURE,
a_theLock->_lrLock.lockExclusive ?
MSG_LOCK_EXC : MSG_LOCK_SHR,
a_theLock->_lrLock.lockObject,
strerror(errno));
return (1);
}
log_msg(LOG_MSG_DEBUG, MSG_LOCK_INCLOCK_DONE,
pll->lockRecordNum, pll->lockCount,
pll->lockObject, pll->lockKey);
return (0);
}
static boolean_t
_validateLock(int a_fd, LOCK_T *a_theLock, int a_quiet)
{
ADMINLOCK_T *pll;
char path[MAXPATHLEN];
pll = &a_theLock->_lrLock;
if (pll->lockPid <= 0) {
log_msg(LOG_MSG_DEBUG, MSG_VALID_NOPID, pll->lockObject);
return (B_TRUE);
}
if (pll->lockZoneId != getzoneid()) {
log_msg(LOG_MSG_DEBUG, MSG_VALID_BADZID, pll->lockObject,
pll->lockZoneId, getzoneid());
return (B_TRUE);
} else {
log_msg(LOG_MSG_DEBUG, MSG_VALID_ZIDOK, pll->lockObject,
pll->lockZoneId, getzoneid());
}
pkgstrPrintf_r(path, sizeof (path), "/proc/%d", pll->lockPid);
if (access(path, F_OK) == 0) {
log_msg(LOG_MSG_DEBUG, MSG_VALID_OK, pll->lockObject,
pll->lockPid, path);
return (B_TRUE);
}
log_msg(LOG_MSG_DEBUG, MSG_VALID_NOTOK, pll->lockObject, pll->lockPid,
path);
log_msg(a_quiet ? LOG_MSG_DEBUG : LOG_MSG_WRN,
MSG_VALID_STALE, pll->lockObject, pll->lockPid,
pll->lockZoneId);
_decrementLockCount(a_fd, a_theLock);
return (B_FALSE);
}
static int
_decrementLockCount(int a_fd, LOCK_T *a_theLock)
{
ADMINLOCK_T *pll;
LOCK_T tmpLock;
RECORDNUM_T lastRecord;
char *pld;
long pls;
off_t lastPos;
ssize_t result;
int res;
pld = &a_theLock->_lrLockData[0];
pll = &a_theLock->_lrLock;
pls = sizeof (a_theLock->_lrLockData);
pll->lockCount--;
if (pll->lockCount > 0) {
log_msg(LOG_MSG_DEBUG, MSG_LOCK_DECLOCK_DECING,
a_theLock->_lrLock.lockExclusive ?
MSG_LOCK_EXC : MSG_LOCK_SHR,
pll->lockRecordNum, pll->lockCount);
result = pwrite(a_fd, pld, pls, pll->lockRecordNum*pls);
if (result != pls) {
log_msg(LOG_MSG_ERR, MSG_LOCK_DECLOCK_PWRITE_FAILURE,
a_theLock->_lrLock.lockExclusive ?
MSG_LOCK_EXC : MSG_LOCK_SHR,
a_theLock->_lrLock.lockObject,
strerror(errno));
return (1);
}
log_msg(LOG_MSG_DEBUG, MSG_LOCK_DECLOCK_DONE,
pll->lockRecordNum, pll->lockCount,
pll->lockObject, pll->lockKey);
return (0);
}
lastPos = lseek(a_fd, 0L, SEEK_END);
if (lastPos == (off_t)-1) {
log_msg(LOG_MSG_ERR, MSG_LOCK_DECLOCK_LSEEK_FAILURE,
a_theLock->_lrLock.lockExclusive ?
MSG_LOCK_EXC : MSG_LOCK_SHR,
a_theLock->_lrLock.lockObject,
strerror(errno));
return (1);
}
lastRecord = (lastPos/pls)-1;
log_msg(LOG_MSG_DEBUG, MSG_LOCK_DECLOCK_REMOVE,
lastPos, lastRecord, pll->lockRecordNum);
if (lastRecord == pll->lockRecordNum) {
log_msg(LOG_MSG_DEBUG, MSG_LOCK_DECLOCK_LASTONE,
a_theLock->_lrLock.lockExclusive ?
MSG_LOCK_EXC : MSG_LOCK_SHR,
lastRecord, lastPos-pls);
res = ftruncate(a_fd, lastPos-pls);
if (res == -1) {
log_msg(LOG_MSG_ERR, MSG_LOCK_DECLOCK_FTRUNCATE_FAILURE,
a_theLock->_lrLock.lockExclusive ?
MSG_LOCK_EXC : MSG_LOCK_SHR,
a_theLock->_lrLock.lockObject,
strerror(errno));
return (1);
}
return (0);
}
log_msg(LOG_MSG_DEBUG, MSG_LOCK_DECLOCK_REMOVING,
pll->lockRecordNum, lastRecord, lastPos-pls);
result = pread(a_fd, tmpLock._lrLockData, pls, lastRecord*pls);
if (result != pls) {
log_msg(LOG_MSG_ERR, MSG_LOCK_DECLOCK_PREAD_FAILURE,
a_theLock->_lrLock.lockExclusive ?
MSG_LOCK_EXC : MSG_LOCK_SHR,
a_theLock->_lrLock.lockObject,
strerror(errno));
return (1);
}
res = ftruncate(a_fd, lastPos-pls);
if (res == -1) {
log_msg(LOG_MSG_ERR, MSG_LOCK_DECLOCK_FTRUNCATE_FAILURE,
a_theLock->_lrLock.lockExclusive ?
MSG_LOCK_EXC : MSG_LOCK_SHR,
a_theLock->_lrLock.lockObject,
strerror(errno));
return (1);
}
tmpLock._lrLock.lockRecordNum = pll->lockRecordNum;
result = pwrite(a_fd, tmpLock._lrLockData, pls, pll->lockRecordNum*pls);
if (result != pls) {
log_msg(LOG_MSG_ERR, MSG_LOCK_DECLOCK_PWRITE_FAILURE,
a_theLock->_lrLock.lockExclusive ?
MSG_LOCK_EXC : MSG_LOCK_SHR,
a_theLock->_lrLock.lockObject,
strerror(errno));
return (1);
}
return (0);
}
static char *
_getUniqueId(void)
{
char newkey[LOCK_KEY_MAXLEN];
hrtime_t hretime;
struct tm tstruct;
time_t thetime;
hretime = gethrtime();
thetime = time((time_t *)NULL);
(void) localtime_r(&thetime, &tstruct);
(void) snprintf(newkey, sizeof (newkey),
"%02d%02d%02d%03d-%02d%02d%02d%d-%016llx", tstruct.tm_mday,
tstruct.tm_mon, tstruct.tm_year, tstruct.tm_yday,
tstruct.tm_hour, tstruct.tm_min, tstruct.tm_sec,
tstruct.tm_wday, hretime);
log_msg(LOG_MSG_DEBUG, MSG_LOCK_GENUID_INTERNAL, newkey);
return (strdup(newkey));
}
static void
sigint_handler(int a_signo)
{
signal_received++;
}
static void
sighup_handler(int a_signo)
{
signal_received++;
}