]> git.saurik.com Git - apple/configd.git/blob - scutil.tproj/commands.c
configd-24.tar.gz
[apple/configd.git] / scutil.tproj / commands.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 <stdio.h>
24 #include <string.h>
25 #include <sys/errno.h>
26
27 #include "scutil.h"
28 #include "commands.h"
29 #include "dictionary.h"
30 #include "session.h"
31 #include "cache.h"
32 #include "notify.h"
33 #include "tests.h"
34
35 #include "SCDPrivate.h"
36
37 const cmdInfo commands[] = {
38 /* cmd minArgs maxArgs func */
39 /* usage */
40
41 { "help", 0, 0, do_help, 0,
42 " help : list available commands" },
43
44 { "f.read", 1, 1, do_readFile, 0,
45 " f.read file : process commands from file" },
46
47 /* local dictionary manipulation commands */
48
49 { "d.init", 0, 0, do_dictInit, 1,
50 " d.init : initialize (empty) dictionary" },
51
52 { "d.show", 0, 0, do_dictShow, 1,
53 " d.show : show dictionary contents" },
54
55 { "d.add", 2, 101, do_dictSetKey, 1,
56 " d.add key [*#?] val [v2 ...] : add information to dictionary\n"
57 " (*=array, #=number, ?=boolean)" },
58
59 { "d.remove", 1, 1, do_dictRemoveKey, 1,
60 " d.remove key : remove key from dictionary" },
61
62 /* data store manipulation commands */
63
64 { "open", 0, 0, do_open, 2,
65 " open : open a session with \"configd\"" },
66
67 { "close", 0, 0, do_close, 2,
68 " close : close current \"configd\" session" },
69
70 { "lock", 0, 0, do_lock, 3,
71 " lock : secures write access to data store" },
72
73 { "unlock", 0, 0, do_unlock, 3,
74 " unlock : secures write access to data store" },
75
76 { "list", 0, 2, do_list, 4,
77 " list [prefix] [regex] : list keys in data store" },
78
79 { "add", 1, 2, do_add, 4,
80 " add key [session] : add key in data store w/current dict" },
81
82 { "get", 1, 1, do_get, 4,
83 " get key : get dict from data store w/key" },
84
85 { "set", 1, 1, do_set, 4,
86 " set key : set key in data store w/current dict" },
87
88 { "remove", 1, 1, do_remove, 4,
89 " remove key : remove key from data store" },
90
91 { "touch", 1, 1, do_touch, 4,
92 " touch key : touch key in data store" },
93
94 { "n.list", 0, 1, do_notify_list, 5,
95 " n.list [regex] : list notification keys" },
96
97 { "n.add", 1, 2, do_notify_add, 5,
98 " n.add key [regex] : add notification key" },
99
100 { "n.remove", 1, 2, do_notify_remove, 5,
101 " n.remove key [regex] : remove notification key" },
102
103 { "n.changes", 0, 0, do_notify_changes, 5,
104 " n.changes : list changed keys" },
105
106 { "n.wait", 0, 0, do_notify_wait, 5,
107 " n.wait : wait for changes" },
108
109 { "n.watch", 0, 1, do_notify_callback, 5,
110 " n.watch [verbose] : watch for changes" },
111
112 { "n.signal", 1, 2, do_notify_signal, 5,
113 " n.signal sig [pid] : signal changes" },
114
115 { "n.file", 0, 1, do_notify_file, 5,
116 " n.file [identifier] : watch for changes via file" },
117
118 { "n.cancel", 0, 1, do_notify_cancel, 5,
119 " n.cancel : cancel notification requests" },
120
121 { "snapshot", 0, 0, do_snapshot, 9,
122 " snapshot : save snapshot of cache and session data" },
123
124 #ifdef DEBUG
125 { "t.ocleak", 0, 1, test_openCloseLeak, 9,
126 " t.ocleak [#] : test for leaks (open/close)" },
127 #endif /* DEBUG */
128 };
129
130 const int nCommands = (sizeof(commands)/sizeof(cmdInfo));
131
132
133 void
134 do_command(int argc, char **argv)
135 {
136 int i;
137 char *cmd = argv[0];
138
139 for (i=0; i<nCommands; i++) {
140 if (strcasecmp(cmd, commands[i].cmd) == 0) {
141 --argc;
142 argv++;
143 if (argc < commands[i].minArgs) {
144 SCDLog(LOG_INFO, CFSTR("%s: too few arguments"), cmd);
145 return;
146 } else if (argc > commands[i].maxArgs) {
147 SCDLog(LOG_INFO, CFSTR("%s: too many arguments"), cmd);
148 return;
149 }
150 commands[i].func(argc, argv);
151 return;
152 }
153 }
154
155 SCDLog(LOG_INFO, CFSTR("%s: unknown, type \"help\" for command info"), cmd);
156 return;
157 }
158
159
160 void
161 do_help(int argc, char **argv)
162 {
163 int g = -1; /* current group */
164 int i;
165
166 SCDLog(LOG_NOTICE, CFSTR(""));
167 SCDLog(LOG_NOTICE, CFSTR("Available commands:"));
168 for (i=0; i<nCommands; i++) {
169 if (g != commands[i].group) {
170 SCDLog(LOG_NOTICE, CFSTR(""));
171 g = commands[i].group;
172 }
173 SCDLog(LOG_NOTICE, CFSTR("%s"), commands[i].usage);
174 }
175 SCDLog(LOG_NOTICE, CFSTR(""));
176
177 return;
178 }
179
180
181 void
182 do_readFile(int argc, char **argv)
183 {
184 FILE *fp = fopen(argv[0], "r");
185 boolean_t ok;
186
187 if (fp == NULL) {
188 SCDLog(LOG_INFO, CFSTR("f.read: could not open file (%s)."), strerror(errno));
189 return;
190 }
191
192 /* open file, increase nesting level */
193 SCDLog(LOG_DEBUG, CFSTR("f.read: reading file (%s)."), argv[0]);
194 nesting++;
195
196 if (SCDOptionGet(NULL, kSCDOptionUseCFRunLoop)) {
197 CFSocketRef in;
198 CFSocketContext context = { 0, fp, NULL, NULL, NULL };
199 CFRunLoopSourceRef rls;
200
201 /* create a "socket" reference with the file descriptor associated with stdin */
202 in = CFSocketCreateWithNative(NULL,
203 fileno(fp),
204 kCFSocketReadCallBack,
205 runLoopProcessInput,
206 &context);
207
208 /* Create and add a run loop source for the file descriptor */
209 rls = CFSocketCreateRunLoopSource(NULL, in, nesting);
210
211 /*
212 * Remove the current input file from the run loop sources. We
213 * will reactivate the current input file source when we are
214 * finished reading data from the new file.
215 */
216 CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
217 (CFRunLoopSourceRef) CFArrayGetValueAtIndex(sources, 0),
218 kCFRunLoopDefaultMode);
219
220 /* keep track of this new source */
221 CFArrayInsertValueAtIndex(sources, 0, rls);
222
223 /* add this source to the run loop */
224 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
225
226 CFRelease(rls);
227 CFRelease(in);
228 } else {
229 do {
230 /* debug information, diagnostics */
231 _showMachPortStatus();
232
233 /* process command */
234 ok = process_line(fp);
235 } while (ok);
236
237 /* decrement the nesting level */
238 nesting--;
239 }
240
241 return;
242 }