]> git.saurik.com Git - apple/configd.git/blame - scutil.tproj/scutil.c
configd-212.2.tar.gz
[apple/configd.git] / scutil.tproj / scutil.c
CommitLineData
5958d7c0 1/*
edebe297 2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
5958d7c0
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
009ee3c6 5 *
009ee3c6
A
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
5958d7c0
A
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
009ee3c6
A
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 *
5958d7c0
A
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
0fae82ee
A
24/*
25 * Modification History
26 *
edebe297
A
27 * June 13, 2005 Allan Nathanson <ajn@apple.com>
28 * - added SCPreferences support
29 *
dbf6a266
A
30 * August 4, 2004 Allan Nathanson <ajn@apple.com>
31 * - added network configuration (prefs) support
32 *
009ee3c6
A
33 * September 25, 2002 Allan Nathanson <ajn@apple.com>
34 * - added command line history & editing
35 *
0fae82ee
A
36 * July 9, 2001 Allan Nathanson <ajn@apple.com>
37 * - added "-r" option for checking network reachability
38 * - added "-w" option to check/wait for the presence of a
39 * dynamic store key.
40 *
41 * June 1, 2001 Allan Nathanson <ajn@apple.com>
42 * - public API conversion
43 *
44 * November 9, 2000 Allan Nathanson <ajn@apple.com>
45 * - initial revision
46 */
47
5958d7c0 48#include <ctype.h>
009ee3c6 49#include <getopt.h>
5958d7c0
A
50#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
009ee3c6 53#include <termios.h>
5958d7c0
A
54#include <unistd.h>
55#include <sysexits.h>
56
57#ifdef DEBUG
58#include <mach/mach.h>
59#include <mach/mach_error.h>
60#endif /* DEBUG */
61
62#include "scutil.h"
5958d7c0
A
63#include "commands.h"
64#include "dictionary.h"
dbf6a266 65#include "net.h"
009ee3c6 66#include "prefs.h"
dbf6a266
A
67#include "session.h"
68#include "tests.h"
0fae82ee 69
0fae82ee
A
70#include "SCDynamicStoreInternal.h"
71
5958d7c0
A
72
73#define LINE_LENGTH 256
74
0fae82ee 75
edebe297 76__private_extern__ AuthorizationRef authorization = NULL;
dbf6a266
A
77__private_extern__ InputRef currentInput = NULL;
78__private_extern__ int nesting = 0;
79__private_extern__ CFRunLoopRef notifyRl = NULL;
80__private_extern__ CFRunLoopSourceRef notifyRls = NULL;
81__private_extern__ SCPreferencesRef prefs = NULL;
82__private_extern__ SCDynamicStoreRef store = NULL;
83__private_extern__ CFPropertyListRef value = NULL;
84__private_extern__ CFMutableArrayRef watchedKeys = NULL;
85__private_extern__ CFMutableArrayRef watchedPatterns = NULL;
009ee3c6 86
dbf6a266 87static const struct option longopts[] = {
009ee3c6
A
88// { "debug", no_argument, NULL, 'd' },
89// { "verbose", no_argument, NULL, 'v' },
90// { "SPI", no_argument, NULL, 'p' },
dbf6a266 91// { "check-reachability", required_argument, NULL, 'r' },
009ee3c6
A
92// { "timeout", required_argument, NULL, 't' },
93// { "wait-key", required_argument, NULL, 'w' },
dbf6a266 94 { "dns", no_argument, NULL, 0 },
009ee3c6
A
95 { "get", required_argument, NULL, 0 },
96 { "help", no_argument, NULL, '?' },
dbf6a266 97 { "net", no_argument, NULL, 0 },
edebe297 98 { "prefs", no_argument, NULL, 0 },
dbf6a266 99 { "proxy", no_argument, NULL, 0 },
009ee3c6 100 { "set", required_argument, NULL, 0 },
dbf6a266 101 { NULL, 0, NULL, 0 }
009ee3c6 102};
5958d7c0
A
103
104
105static char *
009ee3c6 106getLine(char *buf, int len, InputRef src)
5958d7c0 107{
009ee3c6 108 int n;
5958d7c0 109
009ee3c6
A
110 if (src->el) {
111 int count;
112 const char *line;
5958d7c0 113
009ee3c6
A
114 line = el_gets(src->el, &count);
115 if (line == NULL)
116 return NULL;
117
118 strncpy(buf, line, len);
5958d7c0 119 } else {
009ee3c6
A
120 if (fgets(buf, len, src->fp) == NULL)
121 return NULL;
122 }
123
124 n = strlen(buf);
125 if (buf[n-1] == '\n') {
126 /* the entire line fit in the buffer, remove the newline */
127 buf[n-1] = '\0';
128 } else if (!src->el) {
5958d7c0
A
129 /* eat the remainder of the line */
130 do {
009ee3c6
A
131 n = fgetc(src->fp);
132 } while ((n != '\n') && (n != EOF));
133 }
134
135 if (src->h) {
136 HistEvent ev;
137
138 history(src->h, &ev, H_ENTER, buf);
5958d7c0
A
139 }
140
ba83da55 141
5958d7c0
A
142 return buf;
143}
144
145
dbf6a266 146static char *
5958d7c0
A
147getString(char **line)
148{
149 char *s, *e, c, *string;
150 int i, isQuoted = 0, escaped = 0;
151
152 if (*line == NULL) return NULL;
153 if (**line == '\0') return NULL;
154
155 /* Skip leading white space */
156 while (isspace(**line)) *line += 1;
157
158 /* Grab the next string */
159 s = *line;
160 if (*s == '\0') {
161 return NULL; /* no string available */
162 } else if (*s == '"') {
163 isQuoted = 1; /* it's a quoted string */
164 s++;
165 }
166
167 for (e = s; (c = *e) != '\0'; e++) {
168 if (isQuoted && (c == '"'))
169 break; /* end of quoted string */
170 if (c == '\\') {
171 e++;
172 if (*e == '\0')
173 break; /* if premature end-of-string */
174 if ((*e == '"') || isspace(*e))
175 escaped++; /* if escaped quote or white space */
176 }
177 if (!isQuoted && isspace(c))
178 break; /* end of non-quoted string */
179 }
180
181 string = malloc(e - s - escaped + 1);
182
183 for (i = 0; s < e; s++) {
184 string[i] = *s;
185 if (!((s[0] == '\\') && ((s[1] == '"') || isspace(s[1])))) i++;
186 }
187 string[i] = '\0';
188
189 if (isQuoted)
190 e++; /* move past end of quoted string */
191
192 *line = e;
193 return string;
194}
195
196
dbf6a266 197__private_extern__
0fae82ee 198Boolean
009ee3c6 199process_line(InputRef src)
5958d7c0 200{
dbf6a266
A
201 char *arg;
202 int argc = 0;
203 char **argv = NULL;
204 int i;
205 char line[LINE_LENGTH];
206 char *s = line;
207
208 // if end-of-file, exit
009ee3c6 209 if (getLine(line, sizeof(line), src) == NULL)
5958d7c0
A
210 return FALSE;
211
0fae82ee 212 if (nesting > 0) {
a5f60add 213 SCPrint(TRUE, stdout, CFSTR("%d> %s\n"), nesting, line);
5958d7c0
A
214 }
215
dbf6a266 216 // break up the input line
5958d7c0
A
217 while ((arg = getString(&s)) != NULL) {
218 if (argc == 0)
219 argv = (char **)malloc(2 * sizeof(char *));
220 else
dbf6a266 221 argv = (char **)reallocf(argv, ((argc + 2) * sizeof(char *)));
5958d7c0
A
222 argv[argc++] = arg;
223 }
224
dbf6a266
A
225 if (argc == 0) {
226 return TRUE; // if no arguments
227 }
5958d7c0 228
dbf6a266
A
229 /* process the command */
230 if (*argv[0] != '#') {
231 argv[argc] = NULL; // just in case...
232 currentInput = src;
233 do_command(argc, argv);
234 }
5958d7c0 235
dbf6a266
A
236 /* free the arguments */
237 for (i = 0; i < argc; i++) {
238 free(argv[i]);
5958d7c0 239 }
dbf6a266 240 free(argv);
5958d7c0 241
dbf6a266 242 return !termRequested;
5958d7c0
A
243}
244
245
dbf6a266 246static void
0fae82ee
A
247usage(const char *command)
248{
249 SCPrint(TRUE, stderr, CFSTR("usage: %s\n"), command);
009ee3c6
A
250 SCPrint(TRUE, stderr, CFSTR("\tinteractive access to the dynamic store.\n"));
251 SCPrint(TRUE, stderr, CFSTR("\n"));
edebe297
A
252 SCPrint(TRUE, stderr, CFSTR(" or: %s --prefs\n"), command);
253 SCPrint(TRUE, stderr, CFSTR("\tinteractive access to the [raw] stored preferences.\n"));
254 SCPrint(TRUE, stderr, CFSTR("\n"));
009ee3c6
A
255 SCPrint(TRUE, stderr, CFSTR(" or: %s -r nodename\n"), command);
256 SCPrint(TRUE, stderr, CFSTR(" or: %s -r address\n"), command);
257 SCPrint(TRUE, stderr, CFSTR(" or: %s -r local-address remote-address\n"), command);
258 SCPrint(TRUE, stderr, CFSTR("\tcheck reachability of node, address, or address pair.\n"));
259 SCPrint(TRUE, stderr, CFSTR("\n"));
0fae82ee
A
260 SCPrint(TRUE, stderr, CFSTR(" or: %s -w dynamic-store-key [ -t timeout ]\n"), command);
261 SCPrint(TRUE, stderr, CFSTR("\t-w\twait for presense of dynamic store key\n"));
262 SCPrint(TRUE, stderr, CFSTR("\t-t\ttime to wait for key\n"));
263 SCPrint(TRUE, stderr, CFSTR("\n"));
009ee3c6
A
264 SCPrint(TRUE, stderr, CFSTR(" or: %s --get pref\n"), command);
265 SCPrint(TRUE, stderr, CFSTR(" or: %s --set pref [newval]\n"), command);
266 SCPrint(TRUE, stderr, CFSTR("\tpref\tdisplay (or set) the specified preference. Valid preferences\n"));
267 SCPrint(TRUE, stderr, CFSTR("\t\tinclude:\n"));
edebe297 268 SCPrint(TRUE, stderr, CFSTR("\t\t\tComputerName, LocalHostName, HostName\n"));
009ee3c6
A
269 SCPrint(TRUE, stderr, CFSTR("\tnewval\tNew preference value to be set. If not specified,\n"));
270 SCPrint(TRUE, stderr, CFSTR("\t\tthe new value will be read from standard input.\n"));
dbf6a266
A
271 SCPrint(TRUE, stderr, CFSTR("\n"));
272 SCPrint(TRUE, stderr, CFSTR(" or: %s --dns\n"), command);
273 SCPrint(TRUE, stderr, CFSTR("\tshow DNS configuration.\n"));
274 SCPrint(TRUE, stderr, CFSTR("\n"));
275 SCPrint(TRUE, stderr, CFSTR(" or: %s --proxy\n"), command);
276 SCPrint(TRUE, stderr, CFSTR("\tshow \"proxy\" configuration.\n"));
277
278 if (getenv("ENABLE_EXPERIMENTAL_SCUTIL_COMMANDS")) {
279 SCPrint(TRUE, stderr, CFSTR("\n"));
280 SCPrint(TRUE, stderr, CFSTR(" or: %s --net\n"), command);
281 SCPrint(TRUE, stderr, CFSTR("\tmanage network configuration.\n"));
282 }
283
0fae82ee
A
284 exit (EX_USAGE);
285}
286
287
009ee3c6
A
288static char *
289prompt(EditLine *el)
290{
291 return "> ";
292}
293
294
5958d7c0 295int
a5f60add 296main(int argc, char * const argv[])
5958d7c0 297{
edebe297
A
298 Boolean doDNS = FALSE;
299 Boolean doNet = FALSE;
300 Boolean doPrefs = FALSE;
301 Boolean doProxy = FALSE;
302 Boolean doReach = FALSE;
009ee3c6 303 char *get = NULL;
0fae82ee
A
304 extern int optind;
305 int opt;
009ee3c6 306 int opti;
0fae82ee 307 const char *prog = argv[0];
009ee3c6
A
308 char *set = NULL;
309 InputRef src;
0fae82ee
A
310 int timeout = 15; /* default timeout (in seconds) */
311 char *wait = NULL;
009ee3c6 312 int xStore = 0; /* non dynamic store command line options */
5958d7c0
A
313
314 /* process any arguments */
315
009ee3c6 316 while ((opt = getopt_long(argc, argv, "dvprt:w:", longopts, &opti)) != -1)
5958d7c0
A
317 switch(opt) {
318 case 'd':
0fae82ee
A
319 _sc_debug = TRUE;
320 _sc_log = FALSE; /* enable framework logging */
5958d7c0
A
321 break;
322 case 'v':
0fae82ee
A
323 _sc_verbose = TRUE;
324 _sc_log = FALSE; /* enable framework logging */
325 break;
326 case 'p':
327 enablePrivateAPI = TRUE;
5958d7c0
A
328 break;
329 case 'r':
edebe297 330 doReach = TRUE;
009ee3c6 331 xStore++;
0fae82ee
A
332 break;
333 case 't':
334 timeout = atoi(optarg);
335 break;
336 case 'w':
337 wait = optarg;
009ee3c6
A
338 xStore++;
339 break;
340 case 0:
dbf6a266 341 if (strcmp(longopts[opti].name, "dns") == 0) {
edebe297 342 doDNS = TRUE;
dbf6a266
A
343 xStore++;
344 } else if (strcmp(longopts[opti].name, "get") == 0) {
009ee3c6
A
345 get = optarg;
346 xStore++;
dbf6a266 347 } else if (strcmp(longopts[opti].name, "net") == 0) {
edebe297
A
348 doNet = TRUE;
349 xStore++;
350 } else if (strcmp(longopts[opti].name, "prefs") == 0) {
351 doPrefs = TRUE;
dbf6a266
A
352 xStore++;
353 } else if (strcmp(longopts[opti].name, "proxy") == 0) {
edebe297 354 doProxy = TRUE;
dbf6a266 355 xStore++;
009ee3c6
A
356 } else if (strcmp(longopts[opti].name, "set") == 0) {
357 set = optarg;
358 xStore++;
359 }
5958d7c0
A
360 break;
361 case '?':
362 default :
0fae82ee 363 usage(prog);
a5f60add 364 }
5958d7c0
A
365 argc -= optind;
366 argv += optind;
367
009ee3c6
A
368 if (xStore > 1) {
369 // if we are attempting to process more than one type of request
0fae82ee
A
370 usage(prog);
371 }
372
373 /* are we checking the reachability of a host/address */
edebe297 374 if (doReach) {
009ee3c6
A
375 if ((argc < 1) || (argc > 2)) {
376 usage(prog);
377 }
378 do_checkReachability(argc, (char **)argv);
0fae82ee
A
379 /* NOT REACHED */
380 }
381
382 /* are we waiting on the presense of a dynamic store key */
383 if (wait) {
384 do_wait(wait, timeout);
385 /* NOT REACHED */
386 }
387
dbf6a266 388 /* are we looking up the DNS configuration */
edebe297 389 if (doDNS) {
dbf6a266
A
390 do_showDNSConfiguration(argc, (char **)argv);
391 /* NOT REACHED */
392 }
393
009ee3c6
A
394 /* are we looking up a preference value */
395 if (get) {
396 if (findPref(get) < 0) {
397 usage(prog);
398 }
399 do_getPref(get, argc, (char **)argv);
400 /* NOT REACHED */
401 }
402
dbf6a266 403 /* are we looking up the proxy configuration */
edebe297 404 if (doProxy) {
dbf6a266
A
405 do_showProxyConfiguration(argc, (char **)argv);
406 /* NOT REACHED */
407 }
408
009ee3c6
A
409 /* are we changing a preference value */
410 if (set) {
411 if (findPref(set) < 0) {
412 usage(prog);
413 }
414 do_setPref(set, argc, (char **)argv);
415 /* NOT REACHED */
416 }
417
edebe297 418 if (doNet) {
dbf6a266 419 /* if we are going to be managing the network configuration */
edebe297
A
420 commands = (cmdInfo *)commands_net;
421 nCommands = nCommands_net;
dbf6a266
A
422
423 if (!getenv("ENABLE_EXPERIMENTAL_SCUTIL_COMMANDS")) {
424 usage(prog);
425 }
426
427 do_net_init(); /* initialization */
428 do_net_open(0, NULL); /* open default prefs */
edebe297
A
429 } else if (doPrefs) {
430 /* if we are going to be managing the network configuration */
431 commands = (cmdInfo *)commands_prefs;
432 nCommands = nCommands_prefs;
433
434 do_dictInit(0, NULL); /* start with an empty dictionary */
435 do_prefs_init(); /* initialization */
436 do_prefs_open(0, NULL); /* open default prefs */
dbf6a266
A
437 } else {
438 /* if we are going to be managing the dynamic store */
439 commands = (cmdInfo *)commands_store;
440 nCommands = nCommands_store;
441
442 do_dictInit(0, NULL); /* start with an empty dictionary */
443 do_open(0, NULL); /* open the dynamic store */
444 }
5958d7c0 445
009ee3c6
A
446 /* allocate command input stream */
447 src = (InputRef)CFAllocatorAllocate(NULL, sizeof(Input), 0);
448 src->fp = stdin;
449 src->el = NULL;
450 src->h = NULL;
451
452 if (isatty(fileno(src->fp))) {
453 int editmode = 1;
454 HistEvent ev;
455 struct termios t;
456
457 if (tcgetattr(fileno(src->fp), &t) != -1) {
458 if ((t.c_lflag & ECHO) == 0) {
459 editmode = 0;
460 }
461 }
462 src->el = el_init(prog, src->fp, stdout, stderr);
463 src->h = history_init();
464
465 (void)history(src->h, &ev, H_SETSIZE, INT_MAX);
466 el_set(src->el, EL_HIST, history, src->h);
5958d7c0 467
009ee3c6
A
468 if (!editmode) {
469 el_set(src->el, EL_EDITMODE, 0);
470 }
5958d7c0 471
009ee3c6
A
472 el_set(src->el, EL_EDITOR, "emacs");
473 el_set(src->el, EL_PROMPT, prompt);
5958d7c0 474
009ee3c6 475 el_source(src->el, NULL);
5958d7c0 476
009ee3c6
A
477 if ((el_get(src->el, EL_EDITMODE, &editmode) != -1) && editmode != 0) {
478 el_set(src->el, EL_SIGNAL, 1);
479 } else {
480 history_end(src->h);
481 src->h = NULL;
482 el_end(src->el);
483 src->el = NULL;
484 }
485 }
5958d7c0 486
009ee3c6
A
487 while (process_line(src) == TRUE) {
488 /* debug information, diagnostics */
489 __showMachPortStatus();
5958d7c0
A
490 }
491
009ee3c6
A
492 /* close the socket, free resources */
493 if (src->h) history_end(src->h);
494 if (src->el) el_end(src->el);
495 (void)fclose(src->fp);
496 CFAllocatorDeallocate(NULL, src);
5958d7c0
A
497
498 exit (EX_OK); // insure the process exit status is 0
499 return 0; // ...and make main fit the ANSI spec.
500}