]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCPCommit.c
configd-84.1.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 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25
26 /*
27 * Modification History
28 *
29 * June 1, 2001 Allan Nathanson <ajn@apple.com>
30 * - public API conversion
31 *
32 * November 9, 2000 Allan Nathanson <ajn@apple.com>
33 * - initial revision
34 */
35
36 #include <SystemConfiguration/SystemConfiguration.h>
37 #include <SystemConfiguration/SCPrivate.h>
38 #include "SCPreferencesInternal.h"
39
40 #include <fcntl.h>
41 #include <unistd.h>
42 #include <sys/errno.h>
43
44 static ssize_t
45 writen(int d, const void *buf, size_t nbytes)
46 {
47 size_t left = nbytes;
48 const void *p = buf;
49
50 while (left > 0) {
51 ssize_t n;
52
53 n = write(d, p, left);
54 if (n >= 0) {
55 left -= n;
56 p += n;
57 } else {
58 if (errno != EINTR) {
59 return -1;
60 }
61 }
62 }
63 return nbytes;
64 }
65
66
67 Boolean
68 SCPreferencesCommitChanges(SCPreferencesRef session)
69 {
70 SCPreferencesPrivateRef sessionPrivate = (SCPreferencesPrivateRef)session;
71 Boolean wasLocked;
72
73 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("SCPreferencesCommitChanges:"));
74
75 /*
76 * Determine if the we have exclusive access to the preferences
77 * and acquire the lock if necessary.
78 */
79 wasLocked = sessionPrivate->locked;
80 if (!wasLocked) {
81 if (!SCPreferencesLock(session, TRUE)) {
82 SCLog(_sc_verbose, LOG_ERR, CFSTR(" SCPreferencesLock() failed"));
83 return FALSE;
84 }
85 }
86
87 /*
88 * if necessary, apply changes
89 */
90 if (sessionPrivate->changed) {
91 int fd;
92 CFDataRef newPrefs;
93 char * path;
94 int pathLen;
95 struct stat statBuf;
96 char * thePath;
97
98 if (stat(sessionPrivate->path, &statBuf) == -1) {
99 if (errno == ENOENT) {
100 bzero(&statBuf, sizeof(statBuf));
101 statBuf.st_mode = 0644;
102 statBuf.st_uid = geteuid();
103 statBuf.st_gid = getegid();
104 } else {
105 SCLog(_sc_verbose, LOG_ERR, CFSTR("stat() failed: %s"), strerror(errno));
106 goto error;
107 }
108 }
109
110 /* create the (new) preferences file */
111 path = sessionPrivate->newPath ? sessionPrivate->newPath : sessionPrivate->path;
112 pathLen = strlen(path) + sizeof("-new");
113 thePath = CFAllocatorAllocate(NULL, pathLen, 0);
114 snprintf(thePath, pathLen, "%s-new", path);
115
116 /* open the (new) preferences file */
117 reopen :
118 fd = open(thePath, O_WRONLY|O_CREAT, statBuf.st_mode);
119 if (fd == -1) {
120 if ((errno == ENOENT) &&
121 ((sessionPrivate->prefsID == NULL) || !CFStringHasPrefix(sessionPrivate->prefsID, CFSTR("/")))) {
122 char *ch;
123
124 ch = strrchr(thePath, '/');
125 if (ch != NULL) {
126 int status;
127
128 *ch = '\0';
129 status = mkdir(thePath, 0755);
130 *ch = '/';
131 if (status == 0) {
132 goto reopen;
133 }
134 }
135 }
136 SCLog(_sc_verbose, LOG_ERR, CFSTR("SCPCommit open() failed: %s"), strerror(errno));
137 CFAllocatorDeallocate(NULL, thePath);
138 goto error;
139 }
140
141 /* preserve permissions */
142 (void) fchown(fd, statBuf.st_uid, statBuf.st_gid);
143 (void) fchmod(fd, statBuf.st_mode);
144
145 /* write the new preferences */
146 newPrefs = CFPropertyListCreateXMLData(NULL, sessionPrivate->prefs);
147 if (!newPrefs) {
148 _SCErrorSet(kSCStatusFailed);
149 SCLog(_sc_verbose, LOG_ERR, CFSTR(" CFPropertyListCreateXMLData() failed"));
150 CFAllocatorDeallocate(NULL, thePath);
151 (void) close(fd);
152 goto error;
153 }
154 if (writen(fd, (void *)CFDataGetBytePtr(newPrefs), CFDataGetLength(newPrefs)) == -1) {
155 _SCErrorSet(errno);
156 SCLog(_sc_verbose, LOG_ERR, CFSTR("write() failed: %s"), strerror(errno));
157 (void) unlink(thePath);
158 CFAllocatorDeallocate(NULL, thePath);
159 (void) close(fd);
160 CFRelease(newPrefs);
161 goto error;
162 }
163 (void) close(fd);
164 CFRelease(newPrefs);
165
166 /* rename new->old */
167 if (rename(thePath, path) == -1) {
168 _SCErrorSet(errno);
169 SCLog(_sc_verbose, LOG_ERR, CFSTR("rename() failed: %s"), strerror(errno));
170 CFAllocatorDeallocate(NULL, thePath);
171 goto error;
172 }
173 CFAllocatorDeallocate(NULL, thePath);
174
175 if (sessionPrivate->newPath) {
176 /* prefs file saved in "new" directory */
177 (void) unlink(sessionPrivate->path);
178 (void) symlink(sessionPrivate->newPath, sessionPrivate->path);
179 CFAllocatorDeallocate(NULL, sessionPrivate->path);
180 sessionPrivate->path = path;
181 sessionPrivate->newPath = NULL;
182 }
183
184 /* update signature */
185 if (stat(path, &statBuf) == -1) {
186 _SCErrorSet(errno);
187 SCLog(_sc_verbose, LOG_ERR, CFSTR("stat() failed: %s"), strerror(errno));
188 goto error;
189 }
190 CFRelease(sessionPrivate->signature);
191 sessionPrivate->signature = __SCPSignatureFromStatbuf(&statBuf);
192 }
193
194 if (!sessionPrivate->isRoot) {
195 /* CONFIGD REALLY NEEDS NON-ROOT WRITE ACCESS */
196 goto perUser;
197 }
198
199 /* if necessary, create the session "commit" key */
200 if (sessionPrivate->sessionKeyCommit == NULL) {
201 sessionPrivate->sessionKeyCommit = _SCPNotificationKey(NULL,
202 sessionPrivate->prefsID,
203 sessionPrivate->perUser,
204 sessionPrivate->user,
205 kSCPreferencesKeyCommit);
206 }
207
208 /* post notification */
209 if (!SCDynamicStoreNotifyValue(sessionPrivate->session,
210 sessionPrivate->sessionKeyCommit)) {
211 SCLog(_sc_verbose, LOG_ERR, CFSTR(" SCDynamicStoreNotifyValue() failed"));
212 _SCErrorSet(kSCStatusFailed);
213 goto error;
214 }
215
216 perUser :
217
218 if (!wasLocked) (void) SCPreferencesUnlock(session);
219 sessionPrivate->changed = FALSE;
220 return TRUE;
221
222 error :
223
224 if (!wasLocked) (void) SCPreferencesUnlock(session);
225 return FALSE;
226 }