]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCPCommit.c
configd-289.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCPCommit.c
1 /*
2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * June 1, 2001 Allan Nathanson <ajn@apple.com>
28 * - public API conversion
29 *
30 * November 9, 2000 Allan Nathanson <ajn@apple.com>
31 * - initial revision
32 */
33
34 #include <SystemConfiguration/SystemConfiguration.h>
35 #include <SystemConfiguration/SCPrivate.h>
36 #include "SCPreferencesInternal.h"
37 #include "SCHelper_client.h"
38
39 #include <fcntl.h>
40 #include <unistd.h>
41 #include <sys/errno.h>
42
43 static Boolean
44 __SCPreferencesCommitChanges_helper(SCPreferencesRef prefs)
45 {
46 CFDataRef data = NULL;
47 Boolean ok;
48 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
49 uint32_t status = kSCStatusOK;
50 CFDataRef reply = NULL;
51
52 if (prefsPrivate->helper == -1) {
53 // if no helper
54 goto fail;
55 }
56
57 if (prefsPrivate->changed) {
58 ok = _SCSerialize(prefsPrivate->prefs, &data, NULL, NULL);
59 if (!ok) {
60 goto fail;
61 }
62 }
63
64 // have the helper "commit" the prefs
65 // status = kSCStatusOK;
66 // reply = NULL;
67 ok = _SCHelperExec(prefsPrivate->helper,
68 SCHELPER_MSG_PREFS_COMMIT,
69 data,
70 &status,
71 &reply);
72 if (data != NULL) CFRelease(data);
73 if (!ok) {
74 goto fail;
75 }
76
77 if (status != kSCStatusOK) {
78 goto error;
79 }
80
81 if (prefsPrivate->changed) {
82 if (prefsPrivate->signature != NULL) CFRelease(prefsPrivate->signature);
83 prefsPrivate->signature = reply;
84 }
85
86 prefsPrivate->changed = FALSE;
87 return TRUE;
88
89 fail :
90
91 // close helper
92 if (prefsPrivate->helper != -1) {
93 _SCHelperClose(prefsPrivate->helper);
94 prefsPrivate->helper = -1;
95 }
96
97 status = kSCStatusAccessError;
98
99 error :
100
101 // return error
102 if (reply != NULL) CFRelease(reply);
103 _SCErrorSet(status);
104 return FALSE;
105 }
106
107
108 static ssize_t
109 writen(int ref, const void *data, size_t len)
110 {
111 size_t left = len;
112 ssize_t n;
113 const void *p = data;
114
115 while (left > 0) {
116 if ((n = write(ref, p, left)) == -1) {
117 if (errno != EINTR) {
118 return -1;
119 }
120 n = 0;
121 }
122 left -= n;
123 p += n;
124 }
125 return len;
126 }
127
128
129 Boolean
130 SCPreferencesCommitChanges(SCPreferencesRef prefs)
131 {
132 Boolean ok = FALSE;
133 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
134 Boolean wasLocked;
135
136 if (prefs == NULL) {
137 /* sorry, you must provide a session */
138 _SCErrorSet(kSCStatusNoPrefsSession);
139 return FALSE;
140 }
141
142 /*
143 * Determine if the we have exclusive access to the preferences
144 * and acquire the lock if necessary.
145 */
146 wasLocked = prefsPrivate->locked;
147 if (!wasLocked) {
148 if (!SCPreferencesLock(prefs, TRUE)) {
149 SCLog(_sc_verbose, LOG_ERR, CFSTR("SCPreferencesCommitChanges SCPreferencesLock() failed"));
150 return FALSE;
151 }
152 }
153
154 if (prefsPrivate->authorizationData != NULL) {
155 ok = __SCPreferencesCommitChanges_helper(prefs);
156 if (ok) {
157 prefsPrivate->changed = FALSE;
158 }
159 goto done;
160 }
161
162 /*
163 * if necessary, apply changes
164 */
165 if (prefsPrivate->changed) {
166 int fd;
167 CFDataRef newPrefs;
168 char * path;
169 int pathLen;
170 struct stat statBuf;
171 char * thePath;
172
173 if (stat(prefsPrivate->path, &statBuf) == -1) {
174 if (errno == ENOENT) {
175 bzero(&statBuf, sizeof(statBuf));
176 statBuf.st_mode = 0644;
177 statBuf.st_uid = geteuid();
178 statBuf.st_gid = getegid();
179 } else {
180 SCLog(_sc_verbose, LOG_ERR, CFSTR("SCPreferencesCommitChanges stat() failed: %s"), strerror(errno));
181 goto done;
182 }
183 }
184
185 /* create the (new) preferences file */
186 path = prefsPrivate->newPath ? prefsPrivate->newPath : prefsPrivate->path;
187 pathLen = strlen(path) + sizeof("-new");
188 thePath = CFAllocatorAllocate(NULL, pathLen, 0);
189 snprintf(thePath, pathLen, "%s-new", path);
190
191 fd = open(thePath, O_WRONLY|O_CREAT, statBuf.st_mode);
192 if (fd == -1) {
193 _SCErrorSet(errno);
194 SCLog(_sc_verbose, LOG_ERR, CFSTR("SCPreferencesCommitChanges open() failed: %s"), strerror(errno));
195 CFAllocatorDeallocate(NULL, thePath);
196 goto done;
197 }
198
199 /* preserve permissions */
200 (void) fchown(fd, statBuf.st_uid, statBuf.st_gid);
201 (void) fchmod(fd, statBuf.st_mode);
202
203 /* write the new preferences */
204 newPrefs = CFPropertyListCreateXMLData(NULL, prefsPrivate->prefs);
205 if (!newPrefs) {
206 _SCErrorSet(kSCStatusFailed);
207 SCLog(_sc_verbose, LOG_ERR, CFSTR("SCPreferencesCommitChanges CFPropertyListCreateXMLData() failed"));
208 SCLog(_sc_verbose, LOG_ERR, CFSTR(" prefs = %s"), path);
209 CFAllocatorDeallocate(NULL, thePath);
210 (void) close(fd);
211 goto done;
212 }
213 if (writen(fd, (const void *)CFDataGetBytePtr(newPrefs), CFDataGetLength(newPrefs)) == -1) {
214 _SCErrorSet(errno);
215 SCLog(_sc_verbose, LOG_ERR, CFSTR("SCPreferencesCommitChanges write() failed: %s"), strerror(errno));
216 SCLog(_sc_verbose, LOG_ERR, CFSTR(" path = %s"), thePath);
217 (void) unlink(thePath);
218 CFAllocatorDeallocate(NULL, thePath);
219 (void) close(fd);
220 CFRelease(newPrefs);
221 goto done;
222 }
223
224 #if !TARGET_OS_IPHONE
225 /* synchronize the file's in-core state with that on disk */
226 if (fsync(fd) == -1) {
227 _SCErrorSet(errno);
228 SCLog(_sc_verbose, LOG_ERR, CFSTR("SCPreferencesCommitChanges fsync() failed: %s"), strerror(errno));
229 SCLog(_sc_verbose, LOG_ERR, CFSTR(" path = %s"), thePath);
230 (void) unlink(thePath);
231 CFAllocatorDeallocate(NULL, thePath);
232 (void) close(fd);
233 CFRelease(newPrefs);
234 goto done;
235 }
236
237 /*
238 * ... and ask the drive to flush to the media
239 *
240 * Note: at present, this only works on HFS filesystems
241 */
242 (void) fcntl(fd, F_FULLFSYNC, 0);
243 #endif // !TARGET_OS_IPHONE
244
245 /* new preferences have been written */
246 if (close(fd) == -1) {
247 _SCErrorSet(errno);
248 SCLog(_sc_verbose, LOG_ERR, CFSTR("SCPreferencesCommitChanges close() failed: %s"), strerror(errno));
249 SCLog(_sc_verbose, LOG_ERR, CFSTR(" path = %s"), thePath);
250 (void) unlink(thePath);
251 CFAllocatorDeallocate(NULL, thePath);
252 CFRelease(newPrefs);
253 goto done;
254 }
255 CFRelease(newPrefs);
256
257 /* rename new->old */
258 if (rename(thePath, path) == -1) {
259 _SCErrorSet(errno);
260 SCLog(_sc_verbose, LOG_ERR, CFSTR("SCPreferencesCommitChanges rename() failed: %s"), strerror(errno));
261 SCLog(_sc_verbose, LOG_ERR, CFSTR(" path = %s --> %s"), thePath, path);
262 CFAllocatorDeallocate(NULL, thePath);
263 goto done;
264 }
265 CFAllocatorDeallocate(NULL, thePath);
266
267 if (prefsPrivate->newPath) {
268 /* prefs file saved in "new" directory */
269 (void) unlink(prefsPrivate->path);
270 (void) symlink(prefsPrivate->newPath, prefsPrivate->path);
271 CFAllocatorDeallocate(NULL, prefsPrivate->path);
272 prefsPrivate->path = path;
273 prefsPrivate->newPath = NULL;
274 }
275
276 /* update signature */
277 if (stat(path, &statBuf) == -1) {
278 _SCErrorSet(errno);
279 SCLog(_sc_verbose, LOG_ERR, CFSTR("SCPreferencesCommitChanges stat() failed: %s"), strerror(errno));
280 SCLog(_sc_verbose, LOG_ERR, CFSTR(" path = %s"), thePath);
281 goto done;
282 }
283 if (prefsPrivate->signature != NULL) CFRelease(prefsPrivate->signature);
284 prefsPrivate->signature = __SCPSignatureFromStatbuf(&statBuf);
285 }
286
287 /* post notification */
288 if (prefsPrivate->session == NULL) {
289 ok = TRUE;
290 } else {
291 ok = SCDynamicStoreNotifyValue(prefsPrivate->session, prefsPrivate->sessionKeyCommit);
292 if (!ok) {
293 SCLog(_sc_verbose, LOG_ERR, CFSTR("SCPreferencesCommitChanges SCDynamicStoreNotifyValue() failed"));
294 _SCErrorSet(kSCStatusFailed);
295 goto done;
296 }
297 }
298
299 prefsPrivate->changed = FALSE;
300
301 done :
302
303 if (!wasLocked) (void) SCPreferencesUnlock(prefs);
304 return ok;
305 }