2 * Copyright(c) 2000-2003 Apple Computer, 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"
40 #include <sys/errno.h>
43 writen(int d
, const void *buf
, size_t nbytes
)
51 n
= write(d
, p
, left
);
66 SCPreferencesCommitChanges(SCPreferencesRef prefs
)
68 SCPreferencesPrivateRef prefsPrivate
= (SCPreferencesPrivateRef
)prefs
;
72 /* sorry, you must provide a session */
73 _SCErrorSet(kSCStatusNoPrefsSession
);
78 * Determine if the we have exclusive access to the preferences
79 * and acquire the lock if necessary.
81 wasLocked
= prefsPrivate
->locked
;
83 if (!SCPreferencesLock(prefs
, TRUE
)) {
84 SCLog(_sc_verbose
, LOG_ERR
, CFSTR("SCPreferencesCommitChanges SCPreferencesLock() failed"));
90 * if necessary, apply changes
92 if (prefsPrivate
->changed
) {
100 if (stat(prefsPrivate
->path
, &statBuf
) == -1) {
101 if (errno
== ENOENT
) {
102 bzero(&statBuf
, sizeof(statBuf
));
103 statBuf
.st_mode
= 0644;
104 statBuf
.st_uid
= geteuid();
105 statBuf
.st_gid
= getegid();
107 SCLog(_sc_verbose
, LOG_ERR
, CFSTR("SCPreferencesCommitChanges stat() failed: %s"), strerror(errno
));
112 /* create the (new) preferences file */
113 path
= prefsPrivate
->newPath
? prefsPrivate
->newPath
: prefsPrivate
->path
;
114 pathLen
= strlen(path
) + sizeof("-new");
115 thePath
= CFAllocatorAllocate(NULL
, pathLen
, 0);
116 snprintf(thePath
, pathLen
, "%s-new", path
);
118 /* open the (new) preferences file */
120 fd
= open(thePath
, O_WRONLY
|O_CREAT
, statBuf
.st_mode
);
122 if ((errno
== ENOENT
) &&
123 ((prefsPrivate
->prefsID
== NULL
) || !CFStringHasPrefix(prefsPrivate
->prefsID
, CFSTR("/")))) {
126 ch
= strrchr(thePath
, '/');
131 status
= mkdir(thePath
, 0755);
138 SCLog(_sc_verbose
, LOG_ERR
, CFSTR("SCPreferencesCommitChanges open() failed: %s"), strerror(errno
));
139 CFAllocatorDeallocate(NULL
, thePath
);
143 /* preserve permissions */
144 (void) fchown(fd
, statBuf
.st_uid
, statBuf
.st_gid
);
145 (void) fchmod(fd
, statBuf
.st_mode
);
147 /* write the new preferences */
148 newPrefs
= CFPropertyListCreateXMLData(NULL
, prefsPrivate
->prefs
);
150 _SCErrorSet(kSCStatusFailed
);
151 SCLog(_sc_verbose
, LOG_ERR
, CFSTR("SCPreferencesCommitChanges CFPropertyListCreateXMLData() failed"));
152 SCLog(_sc_verbose
, LOG_ERR
, CFSTR(" prefs = %s"), path
);
153 CFAllocatorDeallocate(NULL
, thePath
);
157 if (writen(fd
, (void *)CFDataGetBytePtr(newPrefs
), CFDataGetLength(newPrefs
)) == -1) {
159 SCLog(_sc_verbose
, LOG_ERR
, CFSTR("SCPreferencesCommitChanges write() failed: %s"), strerror(errno
));
160 SCLog(_sc_verbose
, LOG_ERR
, CFSTR(" path = %s"), thePath
);
161 (void) unlink(thePath
);
162 CFAllocatorDeallocate(NULL
, thePath
);
167 if (fsync(fd
) == -1) {
169 SCLog(_sc_verbose
, LOG_ERR
, CFSTR("SCPreferencesCommitChanges fsync() failed: %s"), strerror(errno
));
170 SCLog(_sc_verbose
, LOG_ERR
, CFSTR(" path = %s"), thePath
);
171 (void) unlink(thePath
);
172 CFAllocatorDeallocate(NULL
, thePath
);
177 if (close(fd
) == -1) {
179 SCLog(_sc_verbose
, LOG_ERR
, CFSTR("SCPreferencesCommitChanges close() failed: %s"), strerror(errno
));
180 SCLog(_sc_verbose
, LOG_ERR
, CFSTR(" path = %s"), thePath
);
181 (void) unlink(thePath
);
182 CFAllocatorDeallocate(NULL
, thePath
);
188 /* rename new->old */
189 if (rename(thePath
, path
) == -1) {
191 SCLog(_sc_verbose
, LOG_ERR
, CFSTR("SCPreferencesCommitChanges rename() failed: %s"), strerror(errno
));
192 SCLog(_sc_verbose
, LOG_ERR
, CFSTR(" path = %s --> %s"), thePath
, path
);
193 CFAllocatorDeallocate(NULL
, thePath
);
196 CFAllocatorDeallocate(NULL
, thePath
);
198 if (prefsPrivate
->newPath
) {
199 /* prefs file saved in "new" directory */
200 (void) unlink(prefsPrivate
->path
);
201 (void) symlink(prefsPrivate
->newPath
, prefsPrivate
->path
);
202 CFAllocatorDeallocate(NULL
, prefsPrivate
->path
);
203 prefsPrivate
->path
= path
;
204 prefsPrivate
->newPath
= NULL
;
207 /* update signature */
208 if (stat(path
, &statBuf
) == -1) {
210 SCLog(_sc_verbose
, LOG_ERR
, CFSTR("SCPreferencesCommitChanges stat() failed: %s"), strerror(errno
));
211 SCLog(_sc_verbose
, LOG_ERR
, CFSTR(" path = %s"), thePath
);
214 CFRelease(prefsPrivate
->signature
);
215 prefsPrivate
->signature
= __SCPSignatureFromStatbuf(&statBuf
);
218 if (!prefsPrivate
->isRoot
) {
219 /* CONFIGD REALLY NEEDS NON-ROOT WRITE ACCESS */
223 /* post notification */
224 if (!SCDynamicStoreNotifyValue(prefsPrivate
->session
,
225 prefsPrivate
->sessionKeyCommit
)) {
226 SCLog(_sc_verbose
, LOG_ERR
, CFSTR("SCPreferencesCommitChanges SCDynamicStoreNotifyValue() failed"));
227 _SCErrorSet(kSCStatusFailed
);
233 if (!wasLocked
) (void) SCPreferencesUnlock(prefs
);
234 prefsPrivate
->changed
= FALSE
;
239 if (!wasLocked
) (void) SCPreferencesUnlock(prefs
);