2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
27 * Modification History
29 * June 1, 2001 Allan Nathanson <ajn@apple.com>
30 * - public API conversion
32 * November 9, 2000 Allan Nathanson <ajn@apple.com>
37 #include <sys/types.h>
38 #include <sys/socket.h>
47 static struct sigaction
*oact
= NULL
;
50 static CFComparisonResult
51 sort_keys(const void *p1
, const void *p2
, void *context
) {
52 CFStringRef key1
= (CFStringRef
)p1
;
53 CFStringRef key2
= (CFStringRef
)p2
;
54 return CFStringCompare(key1
, key2
, 0);
59 storeCallback(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *info
)
64 SCPrint(TRUE
, stdout
, CFSTR("notification callback (store address = %p).\n"), store
);
66 n
= CFArrayGetCount(changedKeys
);
68 for (i
= 0; i
< n
; i
++) {
71 CFSTR(" changed key [%d] = %@\n"),
73 CFArrayGetValueAtIndex(changedKeys
, i
));
76 SCPrint(TRUE
, stdout
, CFSTR(" no changed key's.\n"));
84 do_notify_list(int argc
, char **argv
)
89 Boolean isRegex
= FALSE
;
90 CFMutableArrayRef sortedList
;
93 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(kSCStatusNoStoreSession
));
100 list
= isRegex
? watchedPatterns
: watchedKeys
;
104 CFSTR(" no notifier %s.\n"),
105 isRegex
? "patterns" : "keys");
109 listCnt
= CFArrayGetCount(list
);
110 sortedList
= CFArrayCreateMutableCopy(NULL
, listCnt
, list
);
111 CFArraySortValues(sortedList
,
112 CFRangeMake(0, listCnt
),
117 for (i
= 0; i
< listCnt
; i
++) {
120 CFSTR(" notifier %s [%d] = %@\n"),
121 isRegex
? "pattern" : "key",
123 CFArrayGetValueAtIndex(sortedList
, i
));
128 CFSTR(" no notifier %s.\n"),
129 isRegex
? "patterns" : "keys");
131 CFRelease(sortedList
);
138 do_notify_add(int argc
, char **argv
)
141 CFMutableArrayRef keys
;
142 Boolean isRegex
= FALSE
;
145 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(kSCStatusNoStoreSession
));
149 key
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingMacRoman
);
154 keys
= isRegex
? watchedPatterns
: watchedKeys
;
155 if (CFArrayContainsValue(keys
, CFRangeMake(0, CFArrayGetCount(keys
)), key
)) {
156 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(kSCStatusKeyExists
));
161 CFArrayAppendValue(keys
, key
);
164 if (!SCDynamicStoreSetNotificationKeys(store
, watchedKeys
, watchedPatterns
)) {
165 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
173 do_notify_remove(int argc
, char **argv
)
176 CFMutableArrayRef keys
;
178 Boolean isRegex
= FALSE
;
181 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(kSCStatusNoStoreSession
));
185 key
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingMacRoman
);
190 keys
= isRegex
? watchedPatterns
: watchedKeys
;
191 i
= CFArrayGetFirstIndexOfValue(keys
, CFRangeMake(0, CFArrayGetCount(keys
)), key
);
194 if (i
== kCFNotFound
) {
195 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(kSCStatusNoKey
));
199 CFArrayRemoveValueAtIndex(keys
, i
);
201 if (!SCDynamicStoreSetNotificationKeys(store
, watchedKeys
, watchedPatterns
)) {
202 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
210 do_notify_changes(int argc
, char **argv
)
216 list
= SCDynamicStoreCopyNotifiedKeys(store
);
218 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
222 listCnt
= CFArrayGetCount(list
);
224 for (i
= 0; i
< listCnt
; i
++) {
227 CFSTR(" changedKey [%d] = %@\n"),
229 CFArrayGetValueAtIndex(list
, i
));
232 SCPrint(TRUE
, stdout
, CFSTR(" no changedKey's.\n"));
243 notifyRl
= CFRunLoopGetCurrent();
245 SCPrint(TRUE
, stdout
, CFSTR(" CFRunLoopGetCurrent() failed\n"));
249 notifyRls
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
251 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
254 CFRunLoopAddSource(notifyRl
, notifyRls
, kCFRunLoopDefaultMode
);
261 do_notify_watch(int argc
, char **argv
)
263 pthread_attr_t tattr
;
270 pthread_attr_init(&tattr
);
271 pthread_attr_setscope(&tattr
, PTHREAD_SCOPE_SYSTEM
);
272 pthread_attr_setdetachstate(&tattr
, PTHREAD_CREATE_DETACHED
);
273 // pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
274 pthread_create(&tid
, &tattr
, _watcher
, NULL
);
275 pthread_attr_destroy(&tattr
);
282 do_notify_wait(int argc
, char **argv
)
284 if (!SCDynamicStoreNotifyWait(store
)) {
285 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
294 notificationWatcher(SCDynamicStoreRef store
, void *arg
)
296 SCPrint(TRUE
, stdout
, CFSTR("notification callback (store address = %p).\n"), store
);
297 SCPrint(TRUE
, stdout
, CFSTR(" arg = %s.\n"), (char *)arg
);
303 notificationWatcherVerbose(SCDynamicStoreRef store
, void *arg
)
305 SCPrint(TRUE
, stdout
, CFSTR("notification callback (store address = %p).\n"), store
);
306 SCPrint(TRUE
, stdout
, CFSTR(" arg = %s.\n"), (char *)arg
);
307 do_notify_changes(0, NULL
); /* report the keys which changed */
313 do_notify_callback(int argc
, char **argv
)
315 SCDynamicStoreCallBack_v1 func
= notificationWatcher
;
317 if ((argc
== 1) && (strcmp(argv
[0], "verbose") == 0)) {
318 func
= notificationWatcherVerbose
;
321 if (!SCDynamicStoreNotifyCallback(store
, CFRunLoopGetCurrent(), func
, "Changed detected by callback handler!")) {
322 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
331 do_notify_file(int argc
, char **argv
)
343 if ((sscanf(argv
[0], "%d", &reqID
) != 1)) {
344 SCPrint(TRUE
, stdout
, CFSTR("invalid identifier.\n"));
349 if (!SCDynamicStoreNotifyFileDescriptor(store
, reqID
, &fd
)) {
350 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
354 bzero(buf
.data
, sizeof(buf
.data
));
355 bufPtr
= &buf
.data
[0];
356 needed
= sizeof(buf
.gotID
);
360 got
= read(fd
, bufPtr
, needed
);
362 /* if error detected */
363 SCPrint(TRUE
, stdout
, CFSTR("read() failed: %s.\n"), strerror(errno
));
368 /* if end of file detected */
369 SCPrint(TRUE
, stdout
, CFSTR("read(): detected end of file.\n"));
373 SCPrint(TRUE
, stdout
, CFSTR("Received %d bytes.\n"), got
);
378 if (needed
!= sizeof(buf
.gotID
)) {
379 SCPrint(TRUE
, stdout
, CFSTR(" Received notification, identifier = %d.\n"), buf
.gotID
);
382 /* this utility only allows processes one notification per "n.file" request */
383 (void) SCDynamicStoreNotifyCancel(store
);
385 (void) close(fd
); /* close my side of the file descriptor */
392 signalCatcher(int signum
)
396 SCPrint(TRUE
, stdout
, CFSTR("Received sig%s (#%d).\n"), sys_signame
[signum
], n
++);
402 do_notify_signal(int argc
, char **argv
)
406 struct sigaction nact
;
409 if (isdigit(*argv
[0])) {
410 if ((sscanf(argv
[0], "%d", &sig
) != 1) || (sig
<= 0) || (sig
>= NSIG
)) {
411 SCPrint(TRUE
, stdout
, CFSTR("signal must be in the range of 1 .. %d.\n"), NSIG
-1);
415 for (sig
= 1; sig
< NSIG
; sig
++) {
416 if (strcasecmp(argv
[0], sys_signame
[sig
]) == 0)
420 CFMutableStringRef str
;
422 SCPrint(TRUE
, stdout
, CFSTR("Signal must be one of the following:\n"));
424 str
= CFStringCreateMutable(NULL
, 0);
425 for (sig
= 1; sig
< NSIG
; sig
++) {
426 CFStringAppendFormat(str
, NULL
, CFSTR(" %-6s"), sys_signame
[sig
]);
427 if ((sig
% 10) == 0) {
428 CFStringAppendFormat(str
, NULL
, CFSTR("\n"));
431 if ((sig
% 10) != 0) {
432 CFStringAppendFormat(str
, NULL
, CFSTR("\n"));
434 SCPrint(TRUE
, stdout
, CFSTR("%@"), str
);
441 if ((argc
!= 2) || (sscanf(argv
[1], "%d", &pid
) != 1)) {
446 ret
= sigaction(osig
, oact
, NULL
); /* restore original signal handler */
448 oact
= malloc(sizeof(struct sigaction
));
451 nact
.sa_handler
= signalCatcher
;
452 sigemptyset(&nact
.sa_mask
);
453 nact
.sa_flags
= SA_RESTART
;
454 ret
= sigaction(sig
, &nact
, oact
);
456 SCPrint(TRUE
, stdout
, CFSTR("signal handler started.\n"));
458 if (!SCDynamicStoreNotifySignal(store
, pid
, sig
)) {
459 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
468 do_notify_cancel(int argc
, char **argv
)
473 CFRunLoopRemoveSource(notifyRl
, notifyRls
, kCFRunLoopDefaultMode
);
474 CFRelease(notifyRls
);
479 CFRunLoopStop(notifyRl
);
483 if (!SCDynamicStoreNotifyCancel(store
)) {
484 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
489 ret
= sigaction(osig
, oact
, NULL
); /* restore original signal handler */