]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCPCommit.c
configd-84.6.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 session)
67 {
68 SCPreferencesPrivateRef sessionPrivate = (SCPreferencesPrivateRef)session;
69 Boolean wasLocked;
70
71 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("SCPreferencesCommitChanges:"));
72
73 /*
74 * Determine if the we have exclusive access to the preferences
75 * and acquire the lock if necessary.
76 */
77 wasLocked = sessionPrivate->locked;
78 if (!wasLocked) {
79 if (!SCPreferencesLock(session, TRUE)) {
80 SCLog(_sc_verbose, LOG_ERR, CFSTR(" SCPreferencesLock() failed"));
81 return FALSE;
82 }
83 }
84
85 /*
86 * if necessary, apply changes
87 */
88 if (sessionPrivate->changed) {
89 int fd;
90 CFDataRef newPrefs;
91 char * path;
92 int pathLen;
93 struct stat statBuf;
94 char * thePath;
95
96 if (stat(sessionPrivate->path, &statBuf) == -1) {
97 if (errno == ENOENT) {
98 bzero(&statBuf, sizeof(statBuf));
99 statBuf.st_mode = 0644;
100 statBuf.st_uid = geteuid();
101 statBuf.st_gid = getegid();
102 } else {
103 SCLog(_sc_verbose, LOG_ERR, CFSTR("stat() failed: %s"), strerror(errno));
104 goto error;
105 }
106 }
107
108 /* create the (new) preferences file */
109 path = sessionPrivate->newPath ? sessionPrivate->newPath : sessionPrivate->path;
110 pathLen = strlen(path) + sizeof("-new");
111 thePath = CFAllocatorAllocate(NULL, pathLen, 0);
112 snprintf(thePath, pathLen, "%s-new", path);
113
114 /* open the (new) preferences file */
115 reopen :
116 fd = open(thePath, O_WRONLY|O_CREAT, statBuf.st_mode);
117 if (fd == -1) {
118 if ((errno == ENOENT) &&
119 ((sessionPrivate->prefsID == NULL) || !CFStringHasPrefix(sessionPrivate->prefsID, CFSTR("/")))) {
120 char *ch;
121
122 ch = strrchr(thePath, '/');
123 if (ch != NULL) {
124 int status;
125
126 *ch = '\0';
127 status = mkdir(thePath, 0755);
128 *ch = '/';
129 if (status == 0) {
130 goto reopen;
131 }
132 }
133 }
134 SCLog(_sc_verbose, LOG_ERR, CFSTR("SCPCommit open() failed: %s"), strerror(errno));
135 CFAllocatorDeallocate(NULL, thePath);
136 goto error;
137 }
138
139 /* preserve permissions */
140 (void) fchown(fd, statBuf.st_uid, statBuf.st_gid);
141 (void) fchmod(fd, statBuf.st_mode);
142
143 /* write the new preferences */
144 newPrefs = CFPropertyListCreateXMLData(NULL, sessionPrivate->prefs);
145 if (!newPrefs) {
146 _SCErrorSet(kSCStatusFailed);
147 SCLog(_sc_verbose, LOG_ERR, CFSTR(" CFPropertyListCreateXMLData() failed"));
148 CFAllocatorDeallocate(NULL, thePath);
149 (void) close(fd);
150 goto error;
151 }
152 if (writen(fd, (void *)CFDataGetBytePtr(newPrefs), CFDataGetLength(newPrefs)) == -1) {
153 _SCErrorSet(errno);
154 SCLog(_sc_verbose, LOG_ERR, CFSTR("write() failed: %s"), strerror(errno));
155 (void) unlink(thePath);
156 CFAllocatorDeallocate(NULL, thePath);
157 (void) close(fd);
158 CFRelease(newPrefs);
159 goto error;
160 }
161 (void) close(fd);
162 CFRelease(newPrefs);
163
164 /* rename new->old */
165 if (rename(thePath, path) == -1) {
166 _SCErrorSet(errno);
167 SCLog(_sc_verbose, LOG_ERR, CFSTR("rename() failed: %s"), strerror(errno));
168 CFAllocatorDeallocate(NULL, thePath);
169 goto error;
170 }
171 CFAllocatorDeallocate(NULL, thePath);
172
173 if (sessionPrivate->newPath) {
174 /* prefs file saved in "new" directory */
175 (void) unlink(sessionPrivate->path);
176 (void) symlink(sessionPrivate->newPath, sessionPrivate->path);
177 CFAllocatorDeallocate(NULL, sessionPrivate->path);
178 sessionPrivate->path = path;
179 sessionPrivate->newPath = NULL;
180 }
181
182 /* update signature */
183 if (stat(path, &statBuf) == -1) {
184 _SCErrorSet(errno);
185 SCLog(_sc_verbose, LOG_ERR, CFSTR("stat() failed: %s"), strerror(errno));
186 goto error;
187 }
188 CFRelease(sessionPrivate->signature);
189 sessionPrivate->signature = __SCPSignatureFromStatbuf(&statBuf);
190 }
191
192 if (!sessionPrivate->isRoot) {
193 /* CONFIGD REALLY NEEDS NON-ROOT WRITE ACCESS */
194 goto perUser;
195 }
196
197 /* if necessary, create the session "commit" key */
198 if (sessionPrivate->sessionKeyCommit == NULL) {
199 sessionPrivate->sessionKeyCommit = _SCPNotificationKey(NULL,
200 sessionPrivate->prefsID,
201 sessionPrivate->perUser,
202 sessionPrivate->user,
203 kSCPreferencesKeyCommit);
204 }
205
206 /* post notification */
207 if (!SCDynamicStoreNotifyValue(sessionPrivate->session,
208 sessionPrivate->sessionKeyCommit)) {
209 SCLog(_sc_verbose, LOG_ERR, CFSTR(" SCDynamicStoreNotifyValue() failed"));
210 _SCErrorSet(kSCStatusFailed);
211 goto error;
212 }
213
214 perUser :
215
216 if (!wasLocked) (void) SCPreferencesUnlock(session);
217 sessionPrivate->changed = FALSE;
218 return TRUE;
219
220 error :
221
222 if (!wasLocked) (void) SCPreferencesUnlock(session);
223 return FALSE;
224 }