2 * Copyright(c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
27 * Modification History
29 * June 1, 2001 Allan Nathanson <ajn@apple.com>
30 * - public API conversion
32 * November 9, 2000 Allan Nathanson <ajn@apple.com>
36 #include <SystemConfiguration/SystemConfiguration.h>
37 #include <SystemConfiguration/SCPrivate.h>
38 #include "SCPreferencesInternal.h"
42 #include <sys/errno.h>
45 SCPreferencesLock(SCPreferencesRef session
, Boolean wait
)
47 CFAllocatorRef allocator
= CFGetAllocator(session
);
49 CFDataRef currentSignature
= NULL
;
50 Boolean haveLock
= FALSE
;
51 SCPreferencesPrivateRef sessionPrivate
= (SCPreferencesPrivateRef
)session
;
53 CFDateRef value
= NULL
;
55 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("SCPreferencesLock:"));
57 if (sessionPrivate
->locked
) {
58 /* sorry, you already have the lock */
59 _SCErrorSet(kSCStatusLocked
);
63 if (!sessionPrivate
->isRoot
) {
64 if (!sessionPrivate
->perUser
) {
65 _SCErrorSet(kSCStatusAccessError
);
68 /* CONFIGD REALLY NEEDS NON-ROOT WRITE ACCESS */
73 if (sessionPrivate
->session
== NULL
) {
75 sessionPrivate
->session
= SCDynamicStoreCreate(allocator
,
76 CFSTR("SCPreferencesLock"),
79 if (!sessionPrivate
->session
) {
80 SCLog(_sc_verbose
, LOG_INFO
, CFSTR("SCDynamicStoreCreate() failed"));
85 if (sessionPrivate
->sessionKeyLock
== NULL
) {
86 /* create the session "lock" key */
87 sessionPrivate
->sessionKeyLock
= _SCPNotificationKey(allocator
,
88 sessionPrivate
->prefsID
,
89 sessionPrivate
->perUser
,
91 kSCPreferencesKeyLock
);
94 if (!SCDynamicStoreAddWatchedKey(sessionPrivate
->session
,
95 sessionPrivate
->sessionKeyLock
,
97 SCLog(_sc_verbose
, LOG_INFO
, CFSTR("SCDynamicStoreAddWatchedKey() failed"));
101 value
= CFDateCreate(allocator
, CFAbsoluteTimeGetCurrent());
104 CFArrayRef changedKeys
;
107 * Attempt to acquire the lock
109 if (SCDynamicStoreAddTemporaryValue(sessionPrivate
->session
,
110 sessionPrivate
->sessionKeyLock
,
116 _SCErrorSet(kSCStatusPrefsBusy
);
122 * Wait for the lock to be released
124 if (!SCDynamicStoreNotifyWait(sessionPrivate
->session
)) {
125 SCLog(_sc_verbose
, LOG_INFO
, CFSTR("SCDynamicStoreNotifyWait() failed"));
128 changedKeys
= SCDynamicStoreCopyNotifiedKeys(sessionPrivate
->session
);
130 SCLog(_sc_verbose
, LOG_INFO
, CFSTR("SCDynamicStoreCopyNotifiedKeys() failed"));
133 CFRelease(changedKeys
);
141 if (!SCDynamicStoreRemoveWatchedKey(sessionPrivate
->session
,
142 sessionPrivate
->sessionKeyLock
,
144 SCLog(_sc_verbose
, LOG_INFO
, CFSTR("SCDynamicStoreRemoveWatchedKey() failed"));
148 changes
= SCDynamicStoreCopyNotifiedKeys(sessionPrivate
->session
);
150 SCLog(_sc_verbose
, LOG_INFO
, CFSTR("SCDynamicStoreCopyNotifiedKeys() failed"));
158 * Check the signature
160 if (stat(sessionPrivate
->path
, &statBuf
) == -1) {
161 if (errno
== ENOENT
) {
162 bzero(&statBuf
, sizeof(statBuf
));
164 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("stat() failed: %s"), strerror(errno
));
165 _SCErrorSet(kSCStatusStale
);
170 currentSignature
= __SCPSignatureFromStatbuf(&statBuf
);
171 if (!CFEqual(sessionPrivate
->signature
, currentSignature
)) {
172 if (sessionPrivate
->accessed
) {
174 * the preferences have been accessed since the
175 * session was created so we've got no choice
176 * but to deny the lock request.
178 _SCErrorSet(kSCStatusStale
);
182 * the file contents have changed but since we
183 * haven't accessed any of the preferences we
184 * don't need to return an error. Simply reload
185 * the stored data and proceed.
187 SCPreferencesRef newPrefs
;
188 SCPreferencesPrivateRef newPrivate
;
190 newPrefs
= __SCPreferencesCreate(allocator
,
191 sessionPrivate
->name
,
192 sessionPrivate
->prefsID
,
193 sessionPrivate
->perUser
,
194 sessionPrivate
->user
);
196 /* if updated preferences could not be loaded */
197 _SCErrorSet(kSCStatusStale
);
201 /* synchronize this sessions prefs/signature */
202 newPrivate
= (SCPreferencesPrivateRef
)newPrefs
;
203 CFRelease(sessionPrivate
->prefs
);
204 sessionPrivate
->prefs
= newPrivate
->prefs
;
205 CFRetain(sessionPrivate
->prefs
);
206 CFRelease(sessionPrivate
->signature
);
207 sessionPrivate
->signature
= CFRetain(newPrivate
->signature
);
211 CFRelease(currentSignature
);
213 sessionPrivate
->locked
= TRUE
;
219 SCDynamicStoreRemoveValue(sessionPrivate
->session
,
220 sessionPrivate
->sessionKeyLock
);
222 if (currentSignature
) CFRelease(currentSignature
);
223 if (value
) CFRelease(value
);