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