]> git.saurik.com Git - apple/configd.git/blob - scutil.tproj/scutil.c
configd-24.1.tar.gz
[apple/configd.git] / scutil.tproj / scutil.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 #include <ctype.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <sysexits.h>
29
30 #ifdef DEBUG
31 #include <mach/mach.h>
32 #include <mach/mach_error.h>
33 #endif /* DEBUG */
34
35 #include "scutil.h"
36 #include "SCDPrivate.h"
37 #include "commands.h"
38 #include "dictionary.h"
39
40 #define LINE_LENGTH 256
41
42 SCDSessionRef session = NULL;
43 SCDHandleRef data = NULL;
44 int nesting = 0;
45 CFMutableArrayRef sources = NULL;
46
47
48 static char *
49 getLine(char *buf, int len, FILE *fp)
50 {
51 int x;
52
53 if (fgets(buf, len, fp) == NULL)
54 return NULL;
55
56 x = strlen(buf);
57 if (buf[x-1] == '\n') {
58 /* the entire line fit in the buffer, remove the newline */
59 buf[x-1] = '\0';
60 } else {
61 /* eat the remainder of the line */
62 do {
63 x = fgetc(fp);
64 } while ((x != '\n') && (x != EOF));
65 }
66
67 return buf;
68 }
69
70
71 char *
72 getString(char **line)
73 {
74 char *s, *e, c, *string;
75 int i, isQuoted = 0, escaped = 0;
76
77 if (*line == NULL) return NULL;
78 if (**line == '\0') return NULL;
79
80 /* Skip leading white space */
81 while (isspace(**line)) *line += 1;
82
83 /* Grab the next string */
84 s = *line;
85 if (*s == '\0') {
86 return NULL; /* no string available */
87 } else if (*s == '"') {
88 isQuoted = 1; /* it's a quoted string */
89 s++;
90 }
91
92 for (e = s; (c = *e) != '\0'; e++) {
93 if (isQuoted && (c == '"'))
94 break; /* end of quoted string */
95 if (c == '\\') {
96 e++;
97 if (*e == '\0')
98 break; /* if premature end-of-string */
99 if ((*e == '"') || isspace(*e))
100 escaped++; /* if escaped quote or white space */
101 }
102 if (!isQuoted && isspace(c))
103 break; /* end of non-quoted string */
104 }
105
106 string = malloc(e - s - escaped + 1);
107
108 for (i = 0; s < e; s++) {
109 string[i] = *s;
110 if (!((s[0] == '\\') && ((s[1] == '"') || isspace(s[1])))) i++;
111 }
112 string[i] = '\0';
113
114 if (isQuoted)
115 e++; /* move past end of quoted string */
116
117 *line = e;
118 return string;
119 }
120
121
122 boolean_t
123 process_line(FILE *fp)
124 {
125 char line[LINE_LENGTH], *s, *arg, **argv = NULL;
126 int i, argc;
127
128 /* if end-of-file, exit */
129 if (getLine(line, sizeof(line), fp) == NULL)
130 return FALSE;
131
132 if ((nesting > 0) && SCDOptionGet(NULL, kSCDOptionVerbose)) {
133 SCDLog(LOG_NOTICE, CFSTR("%d> %s"), nesting, line);
134 }
135
136 /* if requested, exit */
137 if (strcasecmp(line, "exit") == 0) return FALSE;
138 if (strcasecmp(line, "quit") == 0) return FALSE;
139 if (strcasecmp(line, "q" ) == 0) return FALSE;
140
141 /* break up the input line */
142 s = line;
143 argc = 0;
144 while ((arg = getString(&s)) != NULL) {
145 if (argc == 0)
146 argv = (char **)malloc(2 * sizeof(char *));
147 else
148 argv = (char **)realloc(argv, ((argc + 2) * sizeof(char *)));
149 argv[argc++] = arg;
150 }
151
152 /* process the command */
153 if (argc > 0) {
154 argv[argc] = NULL; /* just in case... */
155
156 if (*argv[0] != '#')
157 do_command(argc, argv);
158
159 for (i = 0; i < argc; i++)
160 free(argv[i]);
161 free(argv);
162 }
163
164 return TRUE;
165 }
166
167
168 void
169 runLoopProcessInput(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
170 {
171 FILE *fp = info;
172
173 if (process_line(fp) == FALSE) {
174 /* we don't want any more input from this stream, stop listening */
175 CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
176 (CFRunLoopSourceRef)CFArrayGetValueAtIndex(sources, 0),
177 kCFRunLoopDefaultMode);
178
179 /* we no longer need the fd (socket) */
180 CFSocketInvalidate(s);
181
182 /* we no longer need to track this source */
183 CFArrayRemoveValueAtIndex(sources, 0);
184
185 if (CFArrayGetCount(sources) > 0) {
186 /* add the previous input source to the run loop */
187 CFRunLoopAddSource(CFRunLoopGetCurrent(),
188 (CFRunLoopSourceRef)CFArrayGetValueAtIndex(sources, 0),
189 kCFRunLoopDefaultMode);
190 } else {
191 /* no more input sources, we're done! */
192 exit (EX_OK);
193 }
194
195 /* decrement the nesting level */
196 nesting--;
197 }
198
199 if (SCDOptionGet(NULL, kSCDOptionUseCFRunLoop)) {
200 /* debug information, diagnostics */
201 _showMachPortStatus();
202
203 /* if necessary, re-issue prompt */
204 if ((CFArrayGetCount(sources) == 1) && isatty(STDIN_FILENO)) {
205 printf("> ");
206 fflush(stdout);
207 }
208 }
209
210 return;
211 }
212
213
214 int
215 main(int argc, const char *argv[])
216 {
217 extern int optind;
218 int opt;
219 boolean_t ok;
220
221 /* process any arguments */
222
223 SCDOptionSet(NULL, kSCDOptionUseCFRunLoop, FALSE);
224
225 while ((opt = getopt(argc, argv, "dvr")) != -1)
226 switch(opt) {
227 case 'd':
228 SCDOptionSet(NULL, kSCDOptionDebug, TRUE);
229 break;
230 case 'v':
231 SCDOptionSet(NULL, kSCDOptionVerbose, TRUE);
232 break;
233 case 'r':
234 SCDOptionSet(NULL, kSCDOptionUseCFRunLoop, TRUE);
235 break;
236 case '?':
237 default :
238 do_help(0, NULL);
239 }
240 argc -= optind;
241 argv += optind;
242
243 /* start with an empty dictionary */
244 do_dictInit(0, NULL);
245
246 if (SCDOptionGet(NULL, kSCDOptionUseCFRunLoop)) {
247 CFSocketRef in;
248 CFSocketContext context = { 0, stdin, NULL, NULL, NULL };
249 CFRunLoopSourceRef rls;
250
251 /* create a "socket" reference with the file descriptor associated with stdin */
252 in = CFSocketCreateWithNative(NULL,
253 STDIN_FILENO,
254 kCFSocketReadCallBack,
255 runLoopProcessInput,
256 &context);
257
258 /* Create a run loop source for the (stdin) file descriptor */
259 rls = CFSocketCreateRunLoopSource(NULL, in, nesting);
260
261 /* keep track of input file sources */
262 sources = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
263 CFArrayAppendValue(sources, rls);
264
265 /* add this source to the run loop */
266 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
267
268 CFRelease(rls);
269 CFRelease(in);
270 }
271
272 do {
273 /* debug information, diagnostics */
274 _showMachPortStatus();
275
276 /* issue prompt */
277 if (isatty(STDIN_FILENO)) {
278 printf("> ");
279 fflush(stdout);
280 }
281
282 if (SCDOptionGet(NULL, kSCDOptionUseCFRunLoop)) {
283 CFRunLoopRun(); /* process input, process events */
284 ok = FALSE; /* if the RunLoop exited */
285 } else {
286 /* process command */
287 ok = process_line(stdin);
288 }
289 } while (ok);
290
291 exit (EX_OK); // insure the process exit status is 0
292 return 0; // ...and make main fit the ANSI spec.
293 }