2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
24 * Modification History
26 * June 1, 2001 Allan Nathanson <ajn@apple.com>
27 * - public API conversion
29 * November 9, 2000 Allan Nathanson <ajn@apple.com>
33 #include <sys/types.h>
34 #include <sys/socket.h>
40 #include <SystemConfiguration/SCPrivate.h>
41 #include "v1Compatibility.h"
45 static struct sigaction
*oact
= NULL
;
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);
57 storeCallback(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *info
)
62 SCPrint(TRUE
, stdout
, CFSTR("notification callback (store address = %p).\n"), store
);
64 n
= CFArrayGetCount(changedKeys
);
69 CFSTR(" changed key [%d] = %@\n"),
71 CFArrayGetValueAtIndex(changedKeys
, i
));
74 SCPrint(TRUE
, stdout
, CFSTR(" no changed key's.\n"));
82 do_notify_list(int argc
, char **argv
)
87 Boolean isRegex
= FALSE
;
88 CFMutableArrayRef sortedList
;
93 list
= SCDynamicStoreCopyWatchedKeyList(store
, isRegex
);
95 if (SCError() != kSCStatusOK
) {
96 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
100 CFSTR(" no notifier %s.\n"),
101 isRegex
? "patterns" : "keys");
106 listCnt
= CFArrayGetCount(list
);
107 sortedList
= CFArrayCreateMutableCopy(NULL
, listCnt
, list
);
109 CFArraySortValues(sortedList
,
110 CFRangeMake(0, listCnt
),
115 for (i
=0; i
<listCnt
; i
++) {
118 CFSTR(" notifier %s [%d] = %@\n"),
119 isRegex
? "pattern" : "key",
121 CFArrayGetValueAtIndex(sortedList
, i
));
126 CFSTR(" no notifier %s.\n"),
127 isRegex
? "patterns" : "keys");
129 CFRelease(sortedList
);
136 do_notify_add(int argc
, char **argv
)
139 Boolean isRegex
= FALSE
;
141 key
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingMacRoman
);
146 if (!SCDynamicStoreAddWatchedKey(store
, key
, isRegex
)) {
147 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
155 do_notify_remove(int argc
, char **argv
)
158 Boolean isRegex
= FALSE
;
160 key
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingMacRoman
);
165 if (!SCDynamicStoreRemoveWatchedKey(store
, key
, isRegex
)) {
166 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
174 do_notify_changes(int argc
, char **argv
)
180 list
= SCDynamicStoreCopyNotifiedKeys(store
);
182 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
186 listCnt
= CFArrayGetCount(list
);
188 for (i
=0; i
<listCnt
; i
++) {
191 CFSTR(" changedKey [%d] = %@\n"),
193 CFArrayGetValueAtIndex(list
, i
));
196 SCPrint(TRUE
, stdout
, CFSTR(" no changedKey's.\n"));
205 do_notify_watch(int argc
, char **argv
)
207 notifyRls
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
209 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
213 CFRunLoopAddSource(CFRunLoopGetCurrent(), notifyRls
, kCFRunLoopDefaultMode
);
219 do_notify_wait(int argc
, char **argv
)
221 if (!SCDynamicStoreNotifyWait(store
)) {
222 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
231 notificationWatcher(SCDynamicStoreRef store
, void *arg
)
233 SCPrint(TRUE
, stdout
, CFSTR("notification callback (store address = %p).\n"), store
);
234 SCPrint(TRUE
, stdout
, CFSTR(" arg = %s.\n"), (char *)arg
);
240 notificationWatcherVerbose(SCDynamicStoreRef store
, void *arg
)
242 SCPrint(TRUE
, stdout
, CFSTR("notification callback (store address = %p).\n"), store
);
243 SCPrint(TRUE
, stdout
, CFSTR(" arg = %s.\n"), (char *)arg
);
244 do_notify_changes(0, NULL
); /* report the keys which changed */
250 do_notify_callback(int argc
, char **argv
)
252 SCDynamicStoreCallBack_v1 func
= notificationWatcher
;
254 if ((argc
== 1) && (strcmp(argv
[0], "verbose") == 0)) {
255 func
= notificationWatcherVerbose
;
258 if (!SCDynamicStoreNotifyCallback(store
, CFRunLoopGetCurrent(), func
, "Changed detected by callback handler!")) {
259 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
268 do_notify_file(int argc
, char **argv
)
280 if ((sscanf(argv
[0], "%d", &reqID
) != 1)) {
281 SCPrint(TRUE
, stdout
, CFSTR("invalid identifier.\n"));
286 if (!SCDynamicStoreNotifyFileDescriptor(store
, reqID
, &fd
)) {
287 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
291 bzero(buf
.data
, sizeof(buf
.data
));
292 bufPtr
= &buf
.data
[0];
293 needed
= sizeof(buf
.gotID
);
297 got
= read(fd
, bufPtr
, needed
);
299 /* if error detected */
300 SCPrint(TRUE
, stdout
, CFSTR("read() failed: %s.\n"), strerror(errno
));
305 /* if end of file detected */
306 SCPrint(TRUE
, stdout
, CFSTR("read(): detected end of file.\n"));
310 SCPrint(TRUE
, stdout
, CFSTR("Received %d bytes.\n"), got
);
315 if (needed
!= sizeof(buf
.gotID
)) {
316 SCPrint(TRUE
, stdout
, CFSTR(" Received notification, identifier = %d.\n"), buf
.gotID
);
319 /* this utility only allows processes one notification per "n.file" request */
320 (void) SCDynamicStoreNotifyCancel(store
);
322 (void) close(fd
); /* close my side of the file descriptor */
329 signalCatcher(int signum
)
333 SCPrint(TRUE
, stdout
, CFSTR("Received sig%s (#%d).\n"), sys_signame
[signum
], n
++);
339 do_notify_signal(int argc
, char **argv
)
343 struct sigaction nact
;
346 if (isdigit(*argv
[0])) {
347 if ((sscanf(argv
[0], "%d", &sig
) != 1) || (sig
<= 0) || (sig
>= NSIG
)) {
348 SCPrint(TRUE
, stdout
, CFSTR("signal must be in the range of 1 .. %d.\n"), NSIG
-1);
352 for (sig
=1; sig
<NSIG
; sig
++) {
353 if (strcasecmp(argv
[0], sys_signame
[sig
]) == 0)
357 CFMutableStringRef str
;
359 SCPrint(TRUE
, stdout
, CFSTR("Signal must be one of the following:\n"));
361 str
= CFStringCreateMutable(NULL
, 0);
362 for (sig
=1; sig
<NSIG
; sig
++) {
363 CFStringAppendFormat(str
, NULL
, CFSTR(" %-6s"), sys_signame
[sig
]);
364 if ((sig
% 10) == 0) {
365 CFStringAppendFormat(str
, NULL
, CFSTR("\n"));
368 if ((sig
% 10) != 0) {
369 CFStringAppendFormat(str
, NULL
, CFSTR("\n"));
371 SCPrint(TRUE
, stdout
, CFSTR("%@"), str
);
378 if ((argc
!= 2) || (sscanf(argv
[1], "%d", &pid
) != 1)) {
383 ret
= sigaction(osig
, oact
, NULL
); /* restore original signal handler */
385 oact
= malloc(sizeof(struct sigaction
));
388 nact
.sa_handler
= signalCatcher
;
389 sigemptyset(&nact
.sa_mask
);
390 nact
.sa_flags
= SA_RESTART
;
391 ret
= sigaction(sig
, &nact
, oact
);
393 SCPrint(TRUE
, stdout
, CFSTR("signal handler started.\n"));
395 if (!SCDynamicStoreNotifySignal(store
, pid
, sig
)) {
396 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
405 do_notify_cancel(int argc
, char **argv
)
410 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), notifyRls
, kCFRunLoopDefaultMode
);
411 CFRelease(notifyRls
);
415 if (!SCDynamicStoreNotifyCancel(store
)) {
416 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
421 ret
= sigaction(osig
, oact
, NULL
); /* restore original signal handler */