]> git.saurik.com Git - apple/configd.git/blob - scutil.tproj/notify.c
configd-84.6.tar.gz
[apple/configd.git] / scutil.tproj / notify.c
1 /*
2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * June 1, 2001 Allan Nathanson <ajn@apple.com>
28 * - public API conversion
29 *
30 * November 9, 2000 Allan Nathanson <ajn@apple.com>
31 * - initial revision
32 */
33
34 #include <pthread.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <sys/un.h>
38 #include <unistd.h>
39
40 #include "scutil.h"
41 #include "notify.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(" changed key [%d] = %@\n"),
70 i,
71 CFArrayGetValueAtIndex(changedKeys, i));
72 }
73 } else {
74 SCPrint(TRUE, stdout, CFSTR(" no changed key'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 (!store) {
91 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(kSCStatusNoStoreSession));
92 return;
93 }
94
95 if (argc == 1)
96 isRegex = TRUE;
97
98 list = isRegex ? watchedPatterns : watchedKeys;
99 if (!list) {
100 SCPrint(TRUE,
101 stdout,
102 CFSTR(" no notifier %s.\n"),
103 isRegex ? "patterns" : "keys");
104 return;
105 }
106
107 listCnt = CFArrayGetCount(list);
108 sortedList = CFArrayCreateMutableCopy(NULL, listCnt, list);
109 CFArraySortValues(sortedList,
110 CFRangeMake(0, listCnt),
111 sort_keys,
112 NULL);
113
114 if (listCnt > 0) {
115 for (i = 0; i < listCnt; i++) {
116 SCPrint(TRUE,
117 stdout,
118 CFSTR(" notifier %s [%d] = %@\n"),
119 isRegex ? "pattern" : "key",
120 i,
121 CFArrayGetValueAtIndex(sortedList, i));
122 }
123 } else {
124 SCPrint(TRUE,
125 stdout,
126 CFSTR(" no notifier %s.\n"),
127 isRegex ? "patterns" : "keys");
128 }
129 CFRelease(sortedList);
130
131 return;
132 }
133
134
135 void
136 do_notify_add(int argc, char **argv)
137 {
138 CFStringRef key;
139 CFMutableArrayRef keys;
140 Boolean isRegex = FALSE;
141
142 if (!store) {
143 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(kSCStatusNoStoreSession));
144 return;
145 }
146
147 key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman);
148
149 if (argc == 2)
150 isRegex = TRUE;
151
152 keys = isRegex ? watchedPatterns : watchedKeys;
153 if (CFArrayContainsValue(keys, CFRangeMake(0, CFArrayGetCount(keys)), key)) {
154 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(kSCStatusKeyExists));
155 CFRelease(key);
156 return;
157 }
158
159 CFArrayAppendValue(keys, key);
160 CFRelease(key);
161
162 if (!SCDynamicStoreSetNotificationKeys(store, watchedKeys, watchedPatterns)) {
163 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
164 }
165
166 return;
167 }
168
169
170 void
171 do_notify_remove(int argc, char **argv)
172 {
173 CFStringRef key;
174 CFMutableArrayRef keys;
175 CFIndex i;
176 Boolean isRegex = FALSE;
177
178 if (!store) {
179 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(kSCStatusNoStoreSession));
180 return;
181 }
182
183 key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman);
184
185 if (argc == 2)
186 isRegex = TRUE;
187
188 keys = isRegex ? watchedPatterns : watchedKeys;
189 i = CFArrayGetFirstIndexOfValue(keys, CFRangeMake(0, CFArrayGetCount(keys)), key);
190 CFRelease(key);
191
192 if (i == kCFNotFound) {
193 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(kSCStatusNoKey));
194 return;
195 }
196
197 CFArrayRemoveValueAtIndex(keys, i);
198
199 if (!SCDynamicStoreSetNotificationKeys(store, watchedKeys, watchedPatterns)) {
200 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
201 }
202
203 return;
204 }
205
206
207 void
208 do_notify_changes(int argc, char **argv)
209 {
210 CFArrayRef list;
211 CFIndex listCnt;
212 int i;
213
214 list = SCDynamicStoreCopyNotifiedKeys(store);
215 if (!list) {
216 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
217 return;
218 }
219
220 listCnt = CFArrayGetCount(list);
221 if (listCnt > 0) {
222 for (i = 0; i < listCnt; i++) {
223 SCPrint(TRUE,
224 stdout,
225 CFSTR(" changedKey [%d] = %@\n"),
226 i,
227 CFArrayGetValueAtIndex(list, i));
228 }
229 } else {
230 SCPrint(TRUE, stdout, CFSTR(" no changedKey's.\n"));
231 }
232 CFRelease(list);
233
234 return;
235 }
236
237
238 static void *
239 _watcher(void *arg)
240 {
241 notifyRl = CFRunLoopGetCurrent();
242 if (!notifyRl) {
243 SCPrint(TRUE, stdout, CFSTR(" CFRunLoopGetCurrent() failed\n"));
244 return NULL;
245 }
246
247 notifyRls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
248 if (!notifyRls) {
249 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
250 return NULL;
251 }
252 CFRunLoopAddSource(notifyRl, notifyRls, kCFRunLoopDefaultMode);
253
254 CFRunLoopRun();
255 return NULL;
256 }
257
258 void
259 do_notify_watch(int argc, char **argv)
260 {
261 pthread_attr_t tattr;
262 pthread_t tid;
263
264 if (notifyRl) {
265 return;
266 }
267
268 pthread_attr_init(&tattr);
269 pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);
270 pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
271 // pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
272 pthread_create(&tid, &tattr, _watcher, NULL);
273 pthread_attr_destroy(&tattr);
274
275 return;
276 }
277
278
279 void
280 do_notify_wait(int argc, char **argv)
281 {
282 if (!SCDynamicStoreNotifyWait(store)) {
283 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
284 return;
285 }
286
287 return;
288 }
289
290
291 static boolean_t
292 notificationWatcher(SCDynamicStoreRef store, void *arg)
293 {
294 SCPrint(TRUE, stdout, CFSTR("notification callback (store address = %p).\n"), store);
295 SCPrint(TRUE, stdout, CFSTR(" arg = %s.\n"), (char *)arg);
296 return TRUE;
297 }
298
299
300 static boolean_t
301 notificationWatcherVerbose(SCDynamicStoreRef store, void *arg)
302 {
303 SCPrint(TRUE, stdout, CFSTR("notification callback (store address = %p).\n"), store);
304 SCPrint(TRUE, stdout, CFSTR(" arg = %s.\n"), (char *)arg);
305 do_notify_changes(0, NULL); /* report the keys which changed */
306 return TRUE;
307 }
308
309
310 void
311 do_notify_callback(int argc, char **argv)
312 {
313 SCDynamicStoreCallBack_v1 func = notificationWatcher;
314
315 if ((argc == 1) && (strcmp(argv[0], "verbose") == 0)) {
316 func = notificationWatcherVerbose;
317 }
318
319 if (!SCDynamicStoreNotifyCallback(store, CFRunLoopGetCurrent(), func, "Changed detected by callback handler!")) {
320 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
321 return;
322 }
323
324 return;
325 }
326
327
328 void
329 do_notify_file(int argc, char **argv)
330 {
331 int32_t reqID = 0;
332 int fd;
333 union {
334 char data[4];
335 int32_t gotID;
336 } buf;
337 char *bufPtr;
338 int needed;
339
340 if (argc == 1) {
341 if ((sscanf(argv[0], "%d", &reqID) != 1)) {
342 SCPrint(TRUE, stdout, CFSTR("invalid identifier.\n"));
343 return;
344 }
345 }
346
347 if (!SCDynamicStoreNotifyFileDescriptor(store, reqID, &fd)) {
348 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
349 return;
350 }
351
352 bzero(buf.data, sizeof(buf.data));
353 bufPtr = &buf.data[0];
354 needed = sizeof(buf.gotID);
355 while (needed > 0) {
356 int got;
357
358 got = read(fd, bufPtr, needed);
359 if (got == -1) {
360 /* if error detected */
361 SCPrint(TRUE, stdout, CFSTR("read() failed: %s.\n"), strerror(errno));
362 break;
363 }
364
365 if (got == 0) {
366 /* if end of file detected */
367 SCPrint(TRUE, stdout, CFSTR("read(): detected end of file.\n"));
368 break;
369 }
370
371 SCPrint(TRUE, stdout, CFSTR("Received %d bytes.\n"), got);
372 bufPtr += got;
373 needed -= got;
374 }
375
376 if (needed != sizeof(buf.gotID)) {
377 SCPrint(TRUE, stdout, CFSTR(" Received notification, identifier = %d.\n"), buf.gotID);
378 }
379
380 /* this utility only allows processes one notification per "n.file" request */
381 (void) SCDynamicStoreNotifyCancel(store);
382
383 (void) close(fd); /* close my side of the file descriptor */
384
385 return;
386 }
387
388
389 static void
390 signalCatcher(int signum)
391 {
392 static int n = 0;
393
394 SCPrint(TRUE, stdout, CFSTR("Received sig%s (#%d).\n"), sys_signame[signum], n++);
395 return;
396 }
397
398
399 void
400 do_notify_signal(int argc, char **argv)
401 {
402 int sig;
403 pid_t pid;
404 struct sigaction nact;
405 int ret;
406
407 if (isdigit(*argv[0])) {
408 if ((sscanf(argv[0], "%d", &sig) != 1) || (sig <= 0) || (sig >= NSIG)) {
409 SCPrint(TRUE, stdout, CFSTR("signal must be in the range of 1 .. %d.\n"), NSIG-1);
410 return;
411 }
412 } else {
413 for (sig = 1; sig < NSIG; sig++) {
414 if (strcasecmp(argv[0], sys_signame[sig]) == 0)
415 break;
416 }
417 if (sig >= NSIG) {
418 CFMutableStringRef str;
419
420 SCPrint(TRUE, stdout, CFSTR("Signal must be one of the following:\n"));
421
422 str = CFStringCreateMutable(NULL, 0);
423 for (sig = 1; sig < NSIG; sig++) {
424 CFStringAppendFormat(str, NULL, CFSTR(" %-6s"), sys_signame[sig]);
425 if ((sig % 10) == 0) {
426 CFStringAppendFormat(str, NULL, CFSTR("\n"));
427 }
428 }
429 if ((sig % 10) != 0) {
430 CFStringAppendFormat(str, NULL, CFSTR("\n"));
431 }
432 SCPrint(TRUE, stdout, CFSTR("%@"), str);
433 CFRelease(str);
434 return;
435 }
436
437 }
438
439 if ((argc != 2) || (sscanf(argv[1], "%d", &pid) != 1)) {
440 pid = getpid();
441 }
442
443 if (oact != NULL) {
444 ret = sigaction(osig, oact, NULL); /* restore original signal handler */
445 } else {
446 oact = malloc(sizeof(struct sigaction));
447 }
448
449 nact.sa_handler = signalCatcher;
450 sigemptyset(&nact.sa_mask);
451 nact.sa_flags = SA_RESTART;
452 ret = sigaction(sig, &nact, oact);
453 osig = sig;
454 SCPrint(TRUE, stdout, CFSTR("signal handler started.\n"));
455
456 if (!SCDynamicStoreNotifySignal(store, pid, sig)) {
457 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
458 return;
459 }
460
461 return;
462 }
463
464
465 void
466 do_notify_cancel(int argc, char **argv)
467 {
468 int ret;
469
470 if (notifyRls) {
471 CFRunLoopRemoveSource(notifyRl, notifyRls, kCFRunLoopDefaultMode);
472 CFRelease(notifyRls);
473 notifyRls = NULL;
474 }
475
476 if (notifyRl) {
477 CFRunLoopStop(notifyRl);
478 notifyRl = NULL;
479 }
480
481 if (!SCDynamicStoreNotifyCancel(store)) {
482 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
483 return;
484 }
485
486 if (oact != NULL) {
487 ret = sigaction(osig, oact, NULL); /* restore original signal handler */
488 free(oact);
489 oact = NULL;
490 }
491
492 return;
493 }