2 * Copyright(c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1(the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
24 * Modification History
26 * June 1, 2001 Allan Nathanson <ajn@apple.com>
27 * - public API conversion
29 * November 9, 2000 Allan Nathanson <ajn@apple.com>
33 #include <SystemConfiguration/SystemConfiguration.h>
34 #include <SystemConfiguration/SCPrivate.h>
35 #include "SCPreferencesInternal.h"
39 #include <sys/errno.h>
42 SCPreferencesLock(SCPreferencesRef session
, Boolean wait
)
45 CFDataRef currentSignature
= NULL
;
46 Boolean haveLock
= FALSE
;
47 SCPreferencesPrivateRef sessionPrivate
= (SCPreferencesPrivateRef
)session
;
49 CFDateRef value
= NULL
;
51 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("SCPreferencesLock:"));
53 if (sessionPrivate
->locked
) {
54 /* sorry, you already have the lock */
55 _SCErrorSet(kSCStatusLocked
);
59 if (!sessionPrivate
->isRoot
) {
60 if (!sessionPrivate
->perUser
) {
61 _SCErrorSet(kSCStatusAccessError
);
64 /* CONFIGD REALLY NEEDS NON-ROOT WRITE ACCESS */
69 if (sessionPrivate
->session
== NULL
) {
71 sessionPrivate
->session
= SCDynamicStoreCreate(NULL
,
72 CFSTR("SCPreferencesLock"),
75 if (!sessionPrivate
->session
) {
76 SCLog(_sc_verbose
, LOG_INFO
, CFSTR("SCDynamicStoreCreate() failed"));
81 if (sessionPrivate
->sessionKeyLock
== NULL
) {
82 /* create the session "lock" key */
83 sessionPrivate
->sessionKeyLock
= _SCPNotificationKey(NULL
,
84 sessionPrivate
->prefsID
,
85 sessionPrivate
->perUser
,
87 kSCPreferencesKeyLock
);
90 if (!SCDynamicStoreAddWatchedKey(sessionPrivate
->session
,
91 sessionPrivate
->sessionKeyLock
,
93 SCLog(_sc_verbose
, LOG_INFO
, CFSTR("SCDynamicStoreAddWatchedKey() failed"));
97 value
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent());
100 CFArrayRef changedKeys
;
103 * Attempt to acquire the lock
105 if (SCDynamicStoreAddTemporaryValue(sessionPrivate
->session
,
106 sessionPrivate
->sessionKeyLock
,
112 _SCErrorSet(kSCStatusPrefsBusy
);
118 * Wait for the lock to be released
120 if (!SCDynamicStoreNotifyWait(sessionPrivate
->session
)) {
121 SCLog(_sc_verbose
, LOG_INFO
, CFSTR("SCDynamicStoreNotifyWait() failed"));
124 changedKeys
= SCDynamicStoreCopyNotifiedKeys(sessionPrivate
->session
);
126 SCLog(_sc_verbose
, LOG_INFO
, CFSTR("SCDynamicStoreCopyNotifiedKeys() failed"));
129 CFRelease(changedKeys
);
137 if (!SCDynamicStoreRemoveWatchedKey(sessionPrivate
->session
,
138 sessionPrivate
->sessionKeyLock
,
140 SCLog(_sc_verbose
, LOG_INFO
, CFSTR("SCDynamicStoreRemoveWatchedKey() failed"));
144 changes
= SCDynamicStoreCopyNotifiedKeys(sessionPrivate
->session
);
146 SCLog(_sc_verbose
, LOG_INFO
, CFSTR("SCDynamicStoreCopyNotifiedKeys() failed"));
154 * Check the signature
156 if (stat(sessionPrivate
->path
, &statBuf
) == -1) {
157 if (errno
== ENOENT
) {
158 bzero(&statBuf
, sizeof(statBuf
));
160 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("stat() failed: %s"), strerror(errno
));
161 _SCErrorSet(kSCStatusStale
);
166 currentSignature
= __SCPSignatureFromStatbuf(&statBuf
);
167 if (!CFEqual(sessionPrivate
->signature
, currentSignature
)) {
168 if (sessionPrivate
->accessed
) {
170 * the preferences have been accessed since the
171 * session was created so we've got no choice
172 * but to deny the lock request.
174 _SCErrorSet(kSCStatusStale
);
178 * the file contents have changed but since we
179 * haven't accessed any of the preferences we
180 * don't need to return an error. Simply reload
181 * the stored data and proceed.
183 SCPreferencesRef newPrefs
;
184 SCPreferencesPrivateRef newPrivate
;
186 newPrefs
= __SCPreferencesCreate(NULL
,
187 sessionPrivate
->name
,
188 sessionPrivate
->prefsID
,
189 sessionPrivate
->perUser
,
190 sessionPrivate
->user
);
192 /* if updated preferences could not be loaded */
193 _SCErrorSet(kSCStatusStale
);
197 /* synchronize this sessions prefs/signature */
198 newPrivate
= (SCPreferencesPrivateRef
)newPrefs
;
199 CFRelease(sessionPrivate
->prefs
);
200 sessionPrivate
->prefs
= CFRetain(newPrivate
->prefs
);
201 CFRelease(sessionPrivate
->signature
);
202 sessionPrivate
->signature
= CFRetain(newPrivate
->signature
);
206 CFRelease(currentSignature
);
208 sessionPrivate
->locked
= TRUE
;
214 SCDynamicStoreRemoveValue(sessionPrivate
->session
,
215 sessionPrivate
->sessionKeyLock
);
217 if (currentSignature
) CFRelease(currentSignature
);
218 if (value
) CFRelease(value
);