]> git.saurik.com Git - apple/configd.git/blob - scutil.tproj/notify.c
configd-42.tar.gz
[apple/configd.git] / scutil.tproj / notify.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 <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/un.h>
36 #include <unistd.h>
37
38 #include "scutil.h"
39
40 #include <SystemConfiguration/SCPrivate.h>
41 #include "v1Compatibility.h"
42
43
44 static int osig;
45 static struct sigaction *oact = NULL;
46
47
48 static CFComparisonResult
49 sort_keys(const void *p1, const void *p2, void *context) {
50 CFStringRef key1 = (CFStringRef)p1;
51 CFStringRef key2 = (CFStringRef)p2;
52 return CFStringCompare(key1, key2, 0);
53 }
54
55
56 void
57 storeCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
58 {
59 int i;
60 CFIndex n;
61
62 SCPrint(TRUE, stdout, CFSTR("notification callback (store address = %p).\n"), store);
63
64 n = CFArrayGetCount(changedKeys);
65 if (n > 0) {
66 for (i=0; i<n; i++) {
67 SCPrint(TRUE,
68 stdout,
69 CFSTR(" changedKey [%d] = %@\n"),
70 i,
71 CFArrayGetValueAtIndex(changedKeys, i));
72 }
73 } else {
74 SCPrint(TRUE, stdout, CFSTR(" no changedKey's.\n"));
75 }
76
77 return;
78 }
79
80
81 void
82 do_notify_list(int argc, char **argv)
83 {
84 int i;
85 CFArrayRef list;
86 CFIndex listCnt;
87 Boolean isRegex = FALSE;
88 CFMutableArrayRef sortedList;
89
90 if (argc == 1)
91 isRegex = TRUE;
92
93 list = SCDynamicStoreCopyWatchedKeyList(store, isRegex);
94 if (!list) {
95 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
96 return;
97 }
98
99 listCnt = CFArrayGetCount(list);
100 sortedList = CFArrayCreateMutableCopy(NULL, listCnt, list);
101 CFRelease(list);
102 CFArraySortValues(sortedList,
103 CFRangeMake(0, listCnt),
104 sort_keys,
105 NULL);
106
107 if (listCnt > 0) {
108 for (i=0; i<listCnt; i++) {
109 SCPrint(TRUE,
110 stdout,
111 CFSTR(" notifierKey [%d] = %@\n"),
112 i,
113 CFArrayGetValueAtIndex(sortedList, i));
114 }
115 } else {
116 SCPrint(TRUE, stdout, CFSTR(" no notifierKey's.\n"));
117 }
118 CFRelease(sortedList);
119
120 return;
121 }
122
123
124 void
125 do_notify_add(int argc, char **argv)
126 {
127 CFStringRef key;
128 Boolean isRegex = FALSE;
129
130 key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman);
131
132 if (argc == 2)
133 isRegex = TRUE;
134
135 if (!SCDynamicStoreAddWatchedKey(store, key, isRegex)) {
136 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
137 }
138 CFRelease(key);
139 return;
140 }
141
142
143 void
144 do_notify_remove(int argc, char **argv)
145 {
146 CFStringRef key;
147 Boolean isRegex = FALSE;
148
149 key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman);
150
151 if (argc == 2)
152 isRegex = TRUE;
153
154 if (!SCDynamicStoreRemoveWatchedKey(store, key, isRegex)) {
155 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
156 }
157 CFRelease(key);
158 return;
159 }
160
161
162 void
163 do_notify_changes(int argc, char **argv)
164 {
165 CFArrayRef list;
166 CFIndex listCnt;
167 int i;
168
169 list = SCDynamicStoreCopyNotifiedKeys(store);
170 if (!list) {
171 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
172 return;
173 }
174
175 listCnt = CFArrayGetCount(list);
176 if (listCnt > 0) {
177 for (i=0; i<listCnt; i++) {
178 SCPrint(TRUE,
179 stdout,
180 CFSTR(" changedKey [%d] = %@\n"),
181 i,
182 CFArrayGetValueAtIndex(list, i));
183 }
184 } else {
185 SCPrint(TRUE, stdout, CFSTR(" no changedKey's.\n"));
186 }
187 CFRelease(list);
188
189 return;
190 }
191
192
193 void
194 do_notify_watch(int argc, char **argv)
195 {
196 notifyRls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
197 if (!notifyRls) {
198 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
199 return;
200 }
201
202 CFRunLoopAddSource(CFRunLoopGetCurrent(), notifyRls, kCFRunLoopDefaultMode);
203 return;
204 }
205
206
207 void
208 do_notify_wait(int argc, char **argv)
209 {
210 if (!SCDynamicStoreNotifyWait(store)) {
211 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
212 return;
213 }
214
215 return;
216 }
217
218
219 static boolean_t
220 notificationWatcher(SCDynamicStoreRef store, void *arg)
221 {
222 SCPrint(TRUE, stdout, CFSTR("notification callback (store address = %p).\n"), store);
223 SCPrint(TRUE, stdout, CFSTR(" arg = %s.\n"), (char *)arg);
224 return TRUE;
225 }
226
227
228 static boolean_t
229 notificationWatcherVerbose(SCDynamicStoreRef store, void *arg)
230 {
231 SCPrint(TRUE, stdout, CFSTR("notification callback (store address = %p).\n"), store);
232 SCPrint(TRUE, stdout, CFSTR(" arg = %s.\n"), (char *)arg);
233 do_notify_changes(0, NULL); /* report the keys which changed */
234 return TRUE;
235 }
236
237
238 void
239 do_notify_callback(int argc, char **argv)
240 {
241 SCDynamicStoreCallBack_v1 func = notificationWatcher;
242
243 if ((argc == 1) && (strcmp(argv[0], "verbose") == 0)) {
244 func = notificationWatcherVerbose;
245 }
246
247 if (!SCDynamicStoreNotifyCallback(store, CFRunLoopGetCurrent(), func, "Changed detected by callback handler!")) {
248 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
249 return;
250 }
251
252 return;
253 }
254
255
256 void
257 do_notify_file(int argc, char **argv)
258 {
259 int32_t reqID = 0;
260 int fd;
261 union {
262 char data[4];
263 int32_t gotID;
264 } buf;
265 char *bufPtr;
266 int needed;
267
268 if (argc == 1) {
269 if ((sscanf(argv[0], "%d", &reqID) != 1)) {
270 SCPrint(TRUE, stdout, CFSTR("invalid identifier.\n"));
271 return;
272 }
273 }
274
275 if (!SCDynamicStoreNotifyFileDescriptor(store, reqID, &fd)) {
276 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
277 return;
278 }
279
280 bzero(buf.data, sizeof(buf.data));
281 bufPtr = &buf.data[0];
282 needed = sizeof(buf.gotID);
283 while (needed > 0) {
284 int got;
285
286 got = read(fd, bufPtr, needed);
287 if (got == -1) {
288 /* if error detected */
289 SCPrint(TRUE, stdout, CFSTR("read() failed: %s.\n"), strerror(errno));
290 break;
291 }
292
293 if (got == 0) {
294 /* if end of file detected */
295 SCPrint(TRUE, stdout, CFSTR("read(): detected end of file.\n"));
296 break;
297 }
298
299 SCPrint(TRUE, stdout, CFSTR("Received %d bytes.\n"), got);
300 bufPtr += got;
301 needed -= got;
302 }
303
304 if (needed != sizeof(buf.gotID)) {
305 SCPrint(TRUE, stdout, CFSTR(" Received notification, identifier = %d.\n"), buf.gotID);
306 }
307
308 /* this utility only allows processes one notification per "n.file" request */
309 (void) SCDynamicStoreNotifyCancel(store);
310
311 (void) close(fd); /* close my side of the file descriptor */
312
313 return;
314 }
315
316
317 static char *signames[] = {
318 "" , "HUP" , "INT" , "QUIT", "ILL" , "TRAP", "ABRT", "EMT" ,
319 "FPE" , "KILL", "BUS" , "SEGV", "SYS" , "PIPE", "ALRM", "TERM",
320 "URG" , "STOP", "TSTP" , "CONT", "CHLD" , "TTIN", "TTOU", "IO" ,
321 "XCPU", "XFSZ", "VTALRM", "PROF", "WINCH", "INFO", "USR1",
322 "USR2"
323 };
324
325
326 static void
327 signalCatcher(int signum)
328 {
329 static int n = 0;
330
331 SCPrint(TRUE, stdout, CFSTR("Received SIG%s (#%d).\n"), signames[signum], n++);
332 return;
333 }
334
335
336 void
337 do_notify_signal(int argc, char **argv)
338 {
339 int sig;
340 pid_t pid;
341 struct sigaction nact;
342 int ret;
343
344 if (isdigit(*argv[0])) {
345 if ((sscanf(argv[0], "%d", &sig) != 1) || (sig <= 0) || (sig >= NSIG)) {
346 SCPrint(TRUE, stdout, CFSTR("signal must be in the range of 1 .. %d.\n"), NSIG-1);
347 return;
348 }
349 } else {
350 for (sig=1; sig<NSIG; sig++) {
351 if (strcasecmp(argv[0], signames[sig]) == 0)
352 break;
353 }
354 if (sig >= NSIG) {
355 CFMutableStringRef str;
356
357 SCPrint(TRUE, stdout, CFSTR("Signal must be one of the following:\n"));
358
359 str = CFStringCreateMutable(NULL, 0);
360 for (sig=1; sig<NSIG; sig++) {
361 CFStringAppendFormat(str, NULL, CFSTR(" %-6s"), signames[sig]);
362 if ((sig % 10) == 0) {
363 CFStringAppendFormat(str, NULL, CFSTR("\n"));
364 }
365 }
366 if ((sig % 10) != 0) {
367 CFStringAppendFormat(str, NULL, CFSTR("\n"));
368 }
369 SCPrint(TRUE, stdout, CFSTR("%@"), str);
370 CFRelease(str);
371 return;
372 }
373
374 }
375
376 if ((argc != 2) || (sscanf(argv[1], "%d", &pid) != 1)) {
377 pid = getpid();
378 }
379
380 if (oact != NULL) {
381 ret = sigaction(osig, oact, NULL); /* restore original signal handler */
382 } else {
383 oact = malloc(sizeof(struct sigaction));
384 }
385
386 nact.sa_handler = signalCatcher;
387 sigemptyset(&nact.sa_mask);
388 nact.sa_flags = SA_RESTART;
389 ret = sigaction(sig, &nact, oact);
390 osig = sig;
391 SCPrint(TRUE, stdout, CFSTR("signal handler started.\n"));
392
393 if (!SCDynamicStoreNotifySignal(store, pid, sig)) {
394 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
395 return;
396 }
397
398 return;
399 }
400
401
402 void
403 do_notify_cancel(int argc, char **argv)
404 {
405 int ret;
406
407 if (notifyRls) {
408 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), notifyRls, kCFRunLoopDefaultMode);
409 CFRelease(notifyRls);
410 notifyRls = NULL;
411 }
412
413 if (!SCDynamicStoreNotifyCancel(store)) {
414 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
415 return;
416 }
417
418 if (oact != NULL) {
419 ret = sigaction(osig, oact, NULL); /* restore original signal handler */
420 free(oact);
421 oact = NULL;
422 }
423
424 return;
425 }