]> git.saurik.com Git - apple/configd.git/blob - configd.tproj/configd.m
configd-42.tar.gz
[apple/configd.git] / configd.tproj / configd.m
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 * 24 March 2000 Allan Nathanson (ajn@apple.com)
30 * - created
31 */
32
33 #include <stdio.h>
34 #include <sysexits.h>
35 #include <syslog.h>
36 #include <unistd.h>
37 #include <paths.h>
38 #include <fcntl.h>
39 #include <sys/types.h>
40 #include <sys/wait.h>
41 #include <objc/objc-runtime.h>
42
43 #include "configd.h"
44 #include "configd_server.h"
45 #include "plugin_support.h"
46
47 Boolean _configd_fork = TRUE; /* TRUE if process should be run in the background */
48 Boolean _configd_verbose = FALSE; /* TRUE if verbose logging enabled */
49 CFMutableSetRef _plugins_exclude = NULL; /* bundle identifiers to exclude from loading */
50 CFMutableSetRef _plugins_verbose = NULL; /* bundle identifiers to enable verbose logging */
51
52 static const char *signames[] = {
53 "" , "HUP" , "INT" , "QUIT", "ILL" , "TRAP", "ABRT", "EMT" ,
54 "FPE" , "KILL", "BUS" , "SEGV", "SYS" , "PIPE", "ALRM", "TERM",
55 "URG" , "STOP", "TSTP" , "CONT", "CHLD" , "TTIN", "TTOU", "IO" ,
56 "XCPU", "XFSZ", "VTALRM", "PROF", "WINCH", "INFO", "USR1", "USR2"
57 };
58
59
60 static void
61 usage(const char *prog)
62 {
63 SCPrint(TRUE, stderr, CFSTR("%s: [-d] [-v] [-V bundleID] [-b] [-B bundleID] [-t plugin-path]\n"), prog);
64 SCPrint(TRUE, stderr, CFSTR("options:\n"));
65 SCPrint(TRUE, stderr, CFSTR("\t-d\tdisable daemon/run in foreground\n"));
66 SCPrint(TRUE, stderr, CFSTR("\t-v\tenable verbose logging\n"));
67 SCPrint(TRUE, stderr, CFSTR("\t-V\tenable verbose logging for the specified plug-in\n"));
68 SCPrint(TRUE, stderr, CFSTR("\t-b\tdisable loading of ALL plug-ins\n"));
69 SCPrint(TRUE, stderr, CFSTR("\t-B\tdisable loading of the specified plug-in\n"));
70 SCPrint(TRUE, stderr, CFSTR("\t-t\tload/test the specified plug-in\n"));
71 SCPrint(TRUE, stderr, CFSTR("\t\t (Note: only the plug-in will be started)\n"), prog);
72 exit (EX_USAGE);
73 }
74
75
76 static void
77 catcher(int signum)
78 {
79 /*
80 * log the signal
81 *
82 * Note: we can't use SCLog() since the signal may be received while the
83 * logging thread lock is held.
84 */
85 if (_configd_verbose) {
86 syslog (LOG_INFO, "caught SIG%s" , signames[signum]);
87 } else {
88 fprintf(stderr, "caught SIG%s\n", signames[signum]);
89 fflush (stderr);
90 }
91
92 return;
93 }
94
95 static void
96 parent_exit(int i)
97 {
98 _exit (0);
99 }
100
101 static int
102 fork_child()
103 {
104 int child_pid;
105 int fd;
106
107 signal(SIGTERM, parent_exit);
108 child_pid = fork();
109 switch (child_pid) {
110 case -1: {
111 return -1;
112 }
113 case 0: {
114 /* child: becomes the daemon (see below) */
115 signal(SIGTERM, SIG_DFL);
116 break;
117 }
118 default: {
119 /* parent: wait for signal, then exit */
120 int status;
121
122 (void) wait4(child_pid, (int *)&status, 0, 0);
123 if (WIFEXITED(status)) {
124 fprintf(stderr,
125 "*** configd (daemon) failed to start, exit status=%d",
126 WEXITSTATUS(status));
127 } else {
128 fprintf(stderr,
129 "*** configd (daemon) failed to start, received signal=%d",
130 WTERMSIG(status));
131 }
132 fflush (stderr);
133 exit (EX_SOFTWARE);
134 }
135 }
136
137 if (setsid() == -1)
138 return -1;
139
140 (void) chdir("/");
141
142 if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
143 (void) dup2(fd, STDIN_FILENO);
144 (void) dup2(fd, STDOUT_FILENO);
145 (void) dup2(fd, STDERR_FILENO);
146 if (fd > 2)
147 (void) close(fd);
148 }
149
150 return 0;
151 }
152
153 int
154 main(int argc, const char *argv[])
155 {
156 Boolean loadBundles = TRUE;
157 struct sigaction nact;
158 int opt;
159 extern int optind;
160 const char *prog = argv[0];
161 CFStringRef str;
162 const char *testBundle = NULL;
163
164 _plugins_exclude = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
165 _plugins_verbose = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
166
167 /* process any arguments */
168
169 while ((opt = getopt(argc, argv, "bB:dt:vV:")) != -1) {
170 switch(opt) {
171 case 'b':
172 loadBundles = FALSE;
173 break;
174 case 'B':
175 str = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingMacRoman);
176 CFSetSetValue(_plugins_exclude, str);
177 CFRelease(str);
178 break;
179 case 'd':
180 _configd_fork = FALSE;
181 break;
182 case 't':
183 testBundle = optarg;
184 break;
185 case 'v':
186 _configd_verbose = TRUE;
187 break;
188 case 'V':
189 if (strcmp(optarg, "com.apple.SystemConfiguration") == 0) {
190 _sc_verbose = TRUE;
191 } else {
192 str = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingMacRoman);
193 CFSetSetValue(_plugins_verbose, str);
194 CFRelease(str);
195 }
196 break;
197 case '?':
198 default :
199 usage(prog);
200 }
201 }
202 argc -= optind;
203 argv += optind;
204
205 /*
206 * display an error if configd is already running and we are
207 * not executing/testing a bundle.
208 */
209 if ((testBundle == NULL) && (server_active() == TRUE)) {
210 exit (EX_UNAVAILABLE);
211 }
212
213 /* check credentials */
214 if (getuid() != 0) {
215 fprintf(stderr, "%s: permission denied.\n", prog);
216 exit (EX_NOPERM);
217 }
218
219 if (_configd_fork) {
220 if (fork_child() == -1) {
221 fprintf(stderr, "configd: fork() failed, %s\n", strerror(errno));
222 exit (1);
223 }
224 /* now the child process, parent waits in fork_child */
225 }
226
227 /* open syslog() facility */
228 if (_configd_fork) {
229 int logopt = LOG_NDELAY|LOG_PID;
230
231 if (_configd_verbose)
232 logopt |= LOG_CONS;
233 openlog("configd", logopt, LOG_DAEMON);
234 } else {
235 _sc_log = FALSE; /* redirect SCLog() to stdout/stderr */
236 }
237
238 /* add signal handler to catch a SIGHUP */
239
240 nact.sa_handler = catcher;
241 sigemptyset(&nact.sa_mask);
242 nact.sa_flags = SA_RESTART;
243
244 if (sigaction(SIGHUP, &nact, NULL) == -1) {
245 SCLog(_configd_verbose, LOG_ERR,
246 CFSTR("sigaction(SIGHUP, ...) failed: %s"),
247 strerror(errno));
248 }
249
250 /* add signal handler to catch a SIGPIPE */
251
252 if (sigaction(SIGPIPE, &nact, NULL) == -1) {
253 SCLog(_configd_verbose, LOG_ERR,
254 CFSTR("sigaction(SIGPIPE, ...) failed: %s"),
255 strerror(errno));
256 }
257
258 /* get set */
259
260 objc_setMultithreaded(YES);
261
262 if (testBundle == NULL) {
263 /* initialize primary (store management) thread */
264 server_init();
265
266 /* load/initialize/start bundles into the secondary thread */
267 if (loadBundles) {
268 plugin_init();
269 } else {
270 if (_configd_fork) {
271 /* synchronize with parent process */
272 kill(getppid(), SIGTERM);
273 }
274 }
275 }
276
277 /* go */
278
279 if (testBundle == NULL) {
280 /* start primary (store management) thread */
281 server_loop();
282 } else {
283 /* load/initialize/start specified plug-in */
284 plugin_exec((void *)testBundle);
285 }
286
287 exit (EX_OK); // insure the process exit status is 0
288 return 0; // ...and make main fit the ANSI spec.
289 }