#include <fcntl.h>
#include <paths.h>
#include <unistd.h>
#include "configd.h"
#include "configd_server.h"
#include "session.h"
#define SNAPSHOT_PATH_STORE _PATH_VARTMP "configd-store.xml"
#define SNAPSHOT_PATH_PATTERN _PATH_VARTMP "configd-pattern.xml"
#define SNAPSHOT_PATH_SESSION _PATH_VARTMP "configd-session.xml"
#define N_QUICK 100
static CFDictionaryRef
_expandStore(CFDictionaryRef storeData)
{
const void * keys_q[N_QUICK];
const void ** keys = keys_q;
CFIndex nElements;
CFDictionaryRef newStoreData = NULL;
const void * nValues_q[N_QUICK];
const void ** nValues = nValues_q;
const void * oValues_q[N_QUICK];
const void ** oValues = oValues_q;
nElements = CFDictionaryGetCount(storeData);
if (nElements > 0) {
CFIndex i;
if (nElements > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
keys = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
oValues = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
nValues = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
}
bzero(nValues, nElements * sizeof(CFTypeRef));
CFDictionaryGetKeysAndValues(storeData, keys, oValues);
for (i = 0; i < nElements; i++) {
CFDataRef data;
data = CFDictionaryGetValue(oValues[i], kSCDData);
if (data) {
CFPropertyListRef plist;
if (!_SCUnserialize(&plist, data, NULL, NULL)) {
goto done;
}
nValues[i] = CFDictionaryCreateMutableCopy(NULL, 0, oValues[i]);
CFDictionarySetValue((CFMutableDictionaryRef)nValues[i],
kSCDData,
plist);
CFRelease(plist);
} else {
nValues[i] = CFRetain(oValues[i]);
}
}
}
newStoreData = CFDictionaryCreate(NULL,
keys,
nValues,
nElements,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
done :
if (nElements > 0) {
CFIndex i;
for (i = 0; i < nElements; i++) {
if (nValues[i]) CFRelease(nValues[i]);
}
if (keys != keys_q) {
CFAllocatorDeallocate(NULL, keys);
CFAllocatorDeallocate(NULL, oValues);
CFAllocatorDeallocate(NULL, nValues);
}
}
return newStoreData;
}
__private_extern__
int
__SCDynamicStoreSnapshot(SCDynamicStoreRef store)
{
CFDictionaryRef expandedStoreData;
int fd;
serverSessionRef mySession;
SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
CFDataRef xmlData;
SCLog(_configd_verbose, LOG_DEBUG, CFSTR("__SCDynamicStoreSnapshot:"));
mySession = getSession(storePrivate->server);
if (mySession->callerEUID != 0) {
return kSCStatusAccessError;
}
(void) unlink(SNAPSHOT_PATH_STORE);
fd = open(SNAPSHOT_PATH_STORE, O_WRONLY|O_CREAT|O_TRUNC, 0644);
if (fd < 0) {
return kSCStatusFailed;
}
expandedStoreData = _expandStore(storeData);
xmlData = CFPropertyListCreateXMLData(NULL, expandedStoreData);
CFRelease(expandedStoreData);
if (!xmlData) {
SCLog(TRUE, LOG_ERR, CFSTR("CFPropertyListCreateXMLData() failed"));
close(fd);
return kSCStatusFailed;
}
(void) write(fd, CFDataGetBytePtr(xmlData), CFDataGetLength(xmlData));
(void) close(fd);
CFRelease(xmlData);
(void) unlink(SNAPSHOT_PATH_PATTERN);
fd = open(SNAPSHOT_PATH_PATTERN, O_WRONLY|O_CREAT|O_TRUNC, 0644);
if (fd < 0) {
return kSCStatusFailed;
}
xmlData = CFPropertyListCreateXMLData(NULL, patternData);
if (!xmlData) {
SCLog(TRUE, LOG_ERR, CFSTR("CFPropertyListCreateXMLData() failed"));
close(fd);
return kSCStatusFailed;
}
(void) write(fd, CFDataGetBytePtr(xmlData), CFDataGetLength(xmlData));
(void) close(fd);
CFRelease(xmlData);
(void) unlink(SNAPSHOT_PATH_SESSION);
fd = open(SNAPSHOT_PATH_SESSION, O_WRONLY|O_CREAT|O_TRUNC, 0644);
if (fd < 0) {
return kSCStatusFailed;
}
xmlData = CFPropertyListCreateXMLData(NULL, sessionData);
if (!xmlData) {
SCLog(TRUE, LOG_ERR, CFSTR("CFPropertyListCreateXMLData() failed"));
close(fd);
return kSCStatusFailed;
}
(void) write(fd, CFDataGetBytePtr(xmlData), CFDataGetLength(xmlData));
(void) close(fd);
CFRelease(xmlData);
return kSCStatusOK;
}
__private_extern__
kern_return_t
_snapshot(mach_port_t server, int *sc_status)
{
serverSessionRef mySession = getSession(server);
SCLog(_configd_verbose, LOG_DEBUG, CFSTR("Snapshot configuration database."));
if (!mySession) {
*sc_status = kSCStatusNoStoreSession;
return KERN_SUCCESS;
}
*sc_status = __SCDynamicStoreSnapshot(mySession->store);
if (*sc_status != kSCStatusOK) {
SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" __SCDynamicStoreSnapshot(): %s"), SCErrorString(*sc_status));
}
return KERN_SUCCESS;
}