]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCPCommit.c
configd-130.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCPCommit.c
1 /*
2 * Copyright(c) 2000-2003 Apple Computer, 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
38 #include <fcntl.h>
39 #include <unistd.h>
40 #include <sys/errno.h>
41
42 static ssize_t
43 writen(int d, const void *buf, size_t nbytes)
44 {
45 size_t left = nbytes;
46 const void *p = buf;
47
48 while (left > 0) {
49 ssize_t n;
50
51 n = write(d, p, left);
52 if (n >= 0) {
53 left -= n;
54 p += n;
55 } else {
56 if (errno != EINTR) {
57 return -1;
58 }
59 }
60 }
61 return nbytes;
62 }
63
64
65 Boolean
66 SCPreferencesCommitChanges(SCPreferencesRef prefs)
67 {
68 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
69 Boolean wasLocked;
70
71 if (prefs == NULL) {
72 /* sorry, you must provide a session */
73 _SCErrorSet(kSCStatusNoPrefsSession);
74 return FALSE;
75 }
76
77 /*
78 * Determine if the we have exclusive access to the preferences
79 * and acquire the lock if necessary.
80 */
81 wasLocked = prefsPrivate->locked;
82 if (!wasLocked) {
83 if (!SCPreferencesLock(prefs, TRUE)) {
84 SCLog(_sc_verbose, LOG_ERR, CFSTR("SCPreferencesCommitChanges SCPreferencesLock() failed"));
85 return FALSE;
86 }
87 }
88
89 /*
90 * if necessary, apply changes
91 */
92 if (prefsPrivate->changed) {
93 int fd;
94 CFDataRef newPrefs;
95 char * path;
96 int pathLen;
97 struct stat statBuf;
98 char * thePath;
99
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();
106 } else {
107 SCLog(_sc_verbose, LOG_ERR, CFSTR("SCPreferencesCommitChanges stat() failed: %s"), strerror(errno));
108 goto error;
109 }
110 }
111
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);
117
118 /* open the (new) preferences file */
119 reopen :
120 fd = open(thePath, O_WRONLY|O_CREAT, statBuf.st_mode);
121 if (fd == -1) {
122 if ((errno == ENOENT) &&
123 ((prefsPrivate->prefsID == NULL) || !CFStringHasPrefix(prefsPrivate->prefsID, CFSTR("/")))) {
124 char *ch;
125
126 ch = strrchr(thePath, '/');
127 if (ch != NULL) {
128 int status;
129
130 *ch = '\0';
131 status = mkdir(thePath, 0755);
132 *ch = '/';
133 if (status == 0) {
134 goto reopen;
135 }
136 }
137 }
138 SCLog(_sc_verbose, LOG_ERR, CFSTR("SCPreferencesCommitChanges open() failed: %s"), strerror(errno));
139 CFAllocatorDeallocate(NULL, thePath);
140 goto error;
141 }
142
143 /* preserve permissions */
144 (void) fchown(fd, statBuf.st_uid, statBuf.st_gid);
145 (void) fchmod(fd, statBuf.st_mode);
146
147 /* write the new preferences */
148 newPrefs = CFPropertyListCreateXMLData(NULL, prefsPrivate->prefs);
149 if (!newPrefs) {
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);
154 (void) close(fd);
155 goto error;
156 }
157 if (writen(fd, (void *)CFDataGetBytePtr(newPrefs), CFDataGetLength(newPrefs)) == -1) {
158 _SCErrorSet(errno);
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);
163 (void) close(fd);
164 CFRelease(newPrefs);
165 goto error;
166 }
167 if (fsync(fd) == -1) {
168 _SCErrorSet(errno);
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);
173 (void) close(fd);
174 CFRelease(newPrefs);
175 goto error;
176 }
177 if (close(fd) == -1) {
178 _SCErrorSet(errno);
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);
183 CFRelease(newPrefs);
184 goto error;
185 }
186 CFRelease(newPrefs);
187
188 /* rename new->old */
189 if (rename(thePath, path) == -1) {
190 _SCErrorSet(errno);
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);
194 goto error;
195 }
196 CFAllocatorDeallocate(NULL, thePath);
197
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;
205 }
206
207 /* update signature */
208 if (stat(path, &statBuf) == -1) {
209 _SCErrorSet(errno);
210 SCLog(_sc_verbose, LOG_ERR, CFSTR("SCPreferencesCommitChanges stat() failed: %s"), strerror(errno));
211 SCLog(_sc_verbose, LOG_ERR, CFSTR(" path = %s"), thePath);
212 goto error;
213 }
214 CFRelease(prefsPrivate->signature);
215 prefsPrivate->signature = __SCPSignatureFromStatbuf(&statBuf);
216 }
217
218 if (!prefsPrivate->isRoot) {
219 /* CONFIGD REALLY NEEDS NON-ROOT WRITE ACCESS */
220 goto perUser;
221 }
222
223 /* post notification */
224 if (!SCDynamicStoreNotifyValue(prefsPrivate->session,
225 prefsPrivate->sessionKeyCommit)) {
226 SCLog(_sc_verbose, LOG_ERR, CFSTR("SCPreferencesCommitChanges SCDynamicStoreNotifyValue() failed"));
227 _SCErrorSet(kSCStatusFailed);
228 goto error;
229 }
230
231 perUser :
232
233 if (!wasLocked) (void) SCPreferencesUnlock(prefs);
234 prefsPrivate->changed = FALSE;
235 return TRUE;
236
237 error :
238
239 if (!wasLocked) (void) SCPreferencesUnlock(prefs);
240 return FALSE;
241 }