2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * June 1, 2001 Allan Nathanson <ajn@apple.com>
28 * - public API conversion
30 * November 9, 2000 Allan Nathanson <ajn@apple.com>
34 #include <SystemConfiguration/SystemConfiguration.h>
35 #include <SystemConfiguration/SCPrivate.h>
36 #include "SCPreferencesInternal.h"
37 #include "SCHelper_client.h"
41 #include <sys/errno.h>
44 __SCPreferencesCommitChanges_helper(SCPreferencesRef prefs
)
46 CFDataRef data
= NULL
;
48 SCPreferencesPrivateRef prefsPrivate
= (SCPreferencesPrivateRef
)prefs
;
49 uint32_t status
= kSCStatusOK
;
50 CFDataRef reply
= NULL
;
52 if (prefsPrivate
->helper
== -1) {
57 if (prefsPrivate
->changed
) {
58 ok
= _SCSerialize(prefsPrivate
->prefs
, &data
, NULL
, NULL
);
64 // have the helper "commit" the prefs
65 // status = kSCStatusOK;
67 ok
= _SCHelperExec(prefsPrivate
->helper
,
68 SCHELPER_MSG_PREFS_COMMIT
,
72 if (data
!= NULL
) CFRelease(data
);
77 if (status
!= kSCStatusOK
) {
81 if (prefsPrivate
->changed
) {
82 if (prefsPrivate
->signature
!= NULL
) CFRelease(prefsPrivate
->signature
);
83 prefsPrivate
->signature
= reply
;
86 prefsPrivate
->changed
= FALSE
;
92 if (prefsPrivate
->helper
!= -1) {
93 _SCHelperClose(prefsPrivate
->helper
);
94 prefsPrivate
->helper
= -1;
97 status
= kSCStatusAccessError
;
102 if (reply
!= NULL
) CFRelease(reply
);
109 writen(int ref
, const void *data
, size_t len
)
113 const void *p
= data
;
116 if ((n
= write(ref
, p
, left
)) == -1) {
117 if (errno
!= EINTR
) {
130 SCPreferencesCommitChanges(SCPreferencesRef prefs
)
133 SCPreferencesPrivateRef prefsPrivate
= (SCPreferencesPrivateRef
)prefs
;
137 /* sorry, you must provide a session */
138 _SCErrorSet(kSCStatusNoPrefsSession
);
143 * Determine if the we have exclusive access to the preferences
144 * and acquire the lock if necessary.
146 wasLocked
= prefsPrivate
->locked
;
148 if (!SCPreferencesLock(prefs
, TRUE
)) {
149 SCLog(_sc_verbose
, LOG_ERR
, CFSTR("SCPreferencesCommitChanges SCPreferencesLock() failed"));
154 if (prefsPrivate
->authorizationData
!= NULL
) {
155 ok
= __SCPreferencesCommitChanges_helper(prefs
);
157 prefsPrivate
->changed
= FALSE
;
163 * if necessary, apply changes
165 if (prefsPrivate
->changed
) {
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();
180 SCLog(_sc_verbose
, LOG_ERR
, CFSTR("SCPreferencesCommitChanges stat() failed: %s"), strerror(errno
));
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
);
191 fd
= open(thePath
, O_WRONLY
|O_CREAT
, statBuf
.st_mode
);
194 SCLog(_sc_verbose
, LOG_ERR
, CFSTR("SCPreferencesCommitChanges open() failed: %s"), strerror(errno
));
195 CFAllocatorDeallocate(NULL
, thePath
);
199 /* preserve permissions */
200 (void) fchown(fd
, statBuf
.st_uid
, statBuf
.st_gid
);
201 (void) fchmod(fd
, statBuf
.st_mode
);
203 /* write the new preferences */
204 newPrefs
= CFPropertyListCreateXMLData(NULL
, prefsPrivate
->prefs
);
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
);
213 if (writen(fd
, (const void *)CFDataGetBytePtr(newPrefs
), CFDataGetLength(newPrefs
)) == -1) {
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
);
224 #if !TARGET_OS_IPHONE
225 /* synchronize the file's in-core state with that on disk */
226 if (fsync(fd
) == -1) {
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
);
238 * ... and ask the drive to flush to the media
240 * Note: at present, this only works on HFS filesystems
242 (void) fcntl(fd
, F_FULLFSYNC
, 0);
243 #endif // !TARGET_OS_IPHONE
245 /* new preferences have been written */
246 if (close(fd
) == -1) {
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
);
257 /* rename new->old */
258 if (rename(thePath
, path
) == -1) {
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
);
265 CFAllocatorDeallocate(NULL
, thePath
);
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
;
276 /* update signature */
277 if (stat(path
, &statBuf
) == -1) {
279 SCLog(_sc_verbose
, LOG_ERR
, CFSTR("SCPreferencesCommitChanges stat() failed: %s"), strerror(errno
));
280 SCLog(_sc_verbose
, LOG_ERR
, CFSTR(" path = %s"), thePath
);
283 if (prefsPrivate
->signature
!= NULL
) CFRelease(prefsPrivate
->signature
);
284 prefsPrivate
->signature
= __SCPSignatureFromStatbuf(&statBuf
);
287 /* post notification */
288 if (prefsPrivate
->session
== NULL
) {
291 ok
= SCDynamicStoreNotifyValue(prefsPrivate
->session
, prefsPrivate
->sessionKeyCommit
);
293 SCLog(_sc_verbose
, LOG_ERR
, CFSTR("SCPreferencesCommitChanges SCDynamicStoreNotifyValue() failed"));
294 _SCErrorSet(kSCStatusFailed
);
299 prefsPrivate
->changed
= FALSE
;
303 if (!wasLocked
) (void) SCPreferencesUnlock(prefs
);