]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCPLock.c
configd-42.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCPLock.c
1 /*
2 * Copyright(c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23 /*
24 * Modification History
25 *
26 * June 1, 2001 Allan Nathanson <ajn@apple.com>
27 * - public API conversion
28 *
29 * November 9, 2000 Allan Nathanson <ajn@apple.com>
30 * - initial revision
31 */
32
33 #include <SystemConfiguration/SystemConfiguration.h>
34 #include <SystemConfiguration/SCPrivate.h>
35 #include "SCPreferencesInternal.h"
36
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <sys/errno.h>
40
41 Boolean
42 SCPreferencesLock(SCPreferencesRef session, Boolean wait)
43 {
44 CFArrayRef changes;
45 CFDataRef currentSignature = NULL;
46 Boolean haveLock = FALSE;
47 SCPreferencesPrivateRef sessionPrivate = (SCPreferencesPrivateRef)session;
48 struct stat statBuf;
49 CFDateRef value = NULL;
50
51 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("SCPreferencesLock:"));
52
53 if (sessionPrivate->locked) {
54 /* sorry, you already have the lock */
55 _SCErrorSet(kSCStatusLocked);
56 return FALSE;
57 }
58
59 if (!sessionPrivate->isRoot) {
60 if (!sessionPrivate->perUser) {
61 _SCErrorSet(kSCStatusAccessError);
62 return FALSE;
63 } else {
64 /* CONFIGD REALLY NEEDS NON-ROOT WRITE ACCESS */
65 goto perUser;
66 }
67 }
68
69 if (sessionPrivate->session == NULL) {
70 /* open a session */
71 sessionPrivate->session = SCDynamicStoreCreate(NULL,
72 CFSTR("SCPreferencesLock"),
73 NULL,
74 NULL);
75 if (!sessionPrivate->session) {
76 SCLog(_sc_verbose, LOG_INFO, CFSTR("SCDynamicStoreCreate() failed"));
77 return FALSE;
78 }
79 }
80
81 if (sessionPrivate->sessionKeyLock == NULL) {
82 /* create the session "lock" key */
83 sessionPrivate->sessionKeyLock = _SCPNotificationKey(NULL,
84 sessionPrivate->prefsID,
85 sessionPrivate->perUser,
86 sessionPrivate->user,
87 kSCPreferencesKeyLock);
88 }
89
90 if (!SCDynamicStoreAddWatchedKey(sessionPrivate->session,
91 sessionPrivate->sessionKeyLock,
92 FALSE)) {
93 SCLog(_sc_verbose, LOG_INFO, CFSTR("SCDynamicStoreAddWatchedKey() failed"));
94 goto error;
95 }
96
97 value = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
98
99 while (TRUE) {
100 CFArrayRef changedKeys;
101
102 /*
103 * Attempt to acquire the lock
104 */
105 if (SCDynamicStoreAddTemporaryValue(sessionPrivate->session,
106 sessionPrivate->sessionKeyLock,
107 value)) {
108 haveLock = TRUE;
109 goto done;
110 } else {
111 if (!wait) {
112 _SCErrorSet(kSCStatusPrefsBusy);
113 goto error;
114 }
115 }
116
117 /*
118 * Wait for the lock to be released
119 */
120 if (!SCDynamicStoreNotifyWait(sessionPrivate->session)) {
121 SCLog(_sc_verbose, LOG_INFO, CFSTR("SCDynamicStoreNotifyWait() failed"));
122 goto error;
123 }
124 changedKeys = SCDynamicStoreCopyNotifiedKeys(sessionPrivate->session);
125 if (!changedKeys) {
126 SCLog(_sc_verbose, LOG_INFO, CFSTR("SCDynamicStoreCopyNotifiedKeys() failed"));
127 goto error;
128 }
129 CFRelease(changedKeys);
130 }
131
132 done :
133
134 CFRelease(value);
135 value = NULL;
136
137 if (!SCDynamicStoreRemoveWatchedKey(sessionPrivate->session,
138 sessionPrivate->sessionKeyLock,
139 0)) {
140 SCLog(_sc_verbose, LOG_INFO, CFSTR("SCDynamicStoreRemoveWatchedKey() failed"));
141 goto error;
142 }
143
144 changes = SCDynamicStoreCopyNotifiedKeys(sessionPrivate->session);
145 if (!changes) {
146 SCLog(_sc_verbose, LOG_INFO, CFSTR("SCDynamicStoreCopyNotifiedKeys() failed"));
147 goto error;
148 }
149 CFRelease(changes);
150
151 perUser:
152
153 /*
154 * Check the signature
155 */
156 if (stat(sessionPrivate->path, &statBuf) == -1) {
157 if (errno == ENOENT) {
158 bzero(&statBuf, sizeof(statBuf));
159 } else {
160 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("stat() failed: %s"), strerror(errno));
161 _SCErrorSet(kSCStatusStale);
162 goto error;
163 }
164 }
165
166 currentSignature = __SCPSignatureFromStatbuf(&statBuf);
167 if (!CFEqual(sessionPrivate->signature, currentSignature)) {
168 if (sessionPrivate->accessed) {
169 /*
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.
173 */
174 _SCErrorSet(kSCStatusStale);
175 goto error;
176 } else {
177 /*
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.
182 */
183 SCPreferencesRef newPrefs;
184 SCPreferencesPrivateRef newPrivate;
185
186 newPrefs = __SCPreferencesCreate(NULL,
187 sessionPrivate->name,
188 sessionPrivate->prefsID,
189 sessionPrivate->perUser,
190 sessionPrivate->user);
191 if (!newPrefs) {
192 /* if updated preferences could not be loaded */
193 _SCErrorSet(kSCStatusStale);
194 goto error;
195 }
196
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);
203 CFRelease(newPrefs);
204 }
205 }
206 CFRelease(currentSignature);
207
208 sessionPrivate->locked = TRUE;
209 return TRUE;
210
211 error :
212
213 if (haveLock) {
214 SCDynamicStoreRemoveValue(sessionPrivate->session,
215 sessionPrivate->sessionKeyLock);
216 }
217 if (currentSignature) CFRelease(currentSignature);
218 if (value) CFRelease(value);
219
220 return FALSE;
221 }