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