#include "SCPreferencesInternal.h"
#include "SCHelper_client.h"
#include <unistd.h>
#include <pthread.h>
static Boolean
__SCPreferencesUnlock_helper(SCPreferencesRef prefs)
{
Boolean ok;
SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
uint32_t status = kSCStatusOK;
if (prefsPrivate->helper_port == MACH_PORT_NULL) {
goto fail;
}
ok = _SCHelperExec(prefsPrivate->helper_port,
SCHELPER_MSG_PREFS_UNLOCK,
NULL,
&status,
NULL);
if (!ok) {
goto fail;
}
if (status != kSCStatusOK) {
goto error;
}
prefsPrivate->locked = FALSE;
return TRUE;
fail :
if (prefsPrivate->helper_port != MACH_PORT_NULL) {
_SCHelperClose(&prefsPrivate->helper_port);
}
status = kSCStatusAccessError;
error :
_SCErrorSet(status);
return FALSE;
}
static void
reportDelay(SCPreferencesRef prefs, struct timeval *delay)
{
SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
SC_log(LOG_ERR,
"SCPreferences(%@:%@) lock held for %d.%3.3d seconds",
prefsPrivate->name,
prefsPrivate->prefsID,
(int)delay->tv_sec,
delay->tv_usec / 1000);
return;
}
Boolean
SCPreferencesUnlock(SCPreferencesRef prefs)
{
struct timeval lockElapsed;
struct timeval lockEnd;
SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
if (prefs == NULL) {
_SCErrorSet(kSCStatusNoPrefsSession);
return FALSE;
}
if (!prefsPrivate->locked) {
_SCErrorSet(kSCStatusNeedLock);
return FALSE;
}
if (prefsPrivate->authorizationData != NULL) {
return __SCPreferencesUnlock_helper(prefs);
}
pthread_mutex_lock(&prefsPrivate->lock);
if (prefsPrivate->sessionNoO_EXLOCK != NULL) {
CFRelease(prefsPrivate->sessionNoO_EXLOCK);
prefsPrivate->sessionNoO_EXLOCK = NULL;
}
if (prefsPrivate->lockFD != -1) {
if (prefsPrivate->lockPath != NULL) {
unlink(prefsPrivate->lockPath);
}
close(prefsPrivate->lockFD);
prefsPrivate->lockFD = -1;
}
(void)gettimeofday(&lockEnd, NULL);
timersub(&lockEnd, &prefsPrivate->lockTime, &lockElapsed);
if (lockElapsed.tv_sec > 0) {
reportDelay(prefs, &lockElapsed);
}
SC_log(LOG_DEBUG, "SCPreferences() unlock: %s",
prefsPrivate->newPath ? prefsPrivate->newPath : prefsPrivate->path);
prefsPrivate->locked = FALSE;
pthread_mutex_unlock(&prefsPrivate->lock);
return TRUE;
}