]> git.saurik.com Git - apple/configd.git/blob - configd.tproj/notify.c
0a75827dcdd270a41e9508efed4765ec3f5f0cb6
[apple/configd.git] / configd.tproj / notify.c
1 /*
2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
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
13 * file.
14 *
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.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25
26 /*
27 * Modification History
28 *
29 * June 1, 2001 Allan Nathanson <ajn@apple.com>
30 * - public API conversion
31 *
32 * March 31, 2000 Allan Nathanson <ajn@apple.com>
33 * - initial revision
34 */
35
36
37 #include <unistd.h>
38
39 #include "configd.h"
40 #include "configd_server.h"
41 #include "session.h"
42
43
44 __private_extern__
45 void
46 pushNotifications()
47 {
48 const void **sessionsToNotify;
49 CFIndex notifyCnt;
50 int server;
51 serverSessionRef theSession;
52 SCDynamicStorePrivateRef storePrivate;
53
54 if (needsNotification == NULL)
55 return; /* if no sessions need to be kicked */
56
57 notifyCnt = CFSetGetCount(needsNotification);
58 sessionsToNotify = malloc(notifyCnt * sizeof(CFNumberRef));
59 CFSetGetValues(needsNotification, sessionsToNotify);
60 while (--notifyCnt >= 0) {
61 (void) CFNumberGetValue(sessionsToNotify[notifyCnt],
62 kCFNumberIntType,
63 &server);
64 theSession = getSession(server);
65 storePrivate = (SCDynamicStorePrivateRef)theSession->store;
66
67 /*
68 * deliver notifications to client sessions
69 */
70 if ((storePrivate->notifyStatus == Using_NotifierInformViaMachPort) &&
71 (storePrivate->notifyPort != MACH_PORT_NULL)) {
72 mach_msg_empty_send_t msg;
73 mach_msg_option_t options;
74 kern_return_t status;
75 /*
76 * Post notification as mach message
77 */
78 if (_configd_verbose) {
79 SCLog(TRUE, LOG_DEBUG, CFSTR("sending mach message notification."));
80 SCLog(TRUE, LOG_DEBUG, CFSTR(" port = %d"), storePrivate->notifyPort);
81 SCLog(TRUE, LOG_DEBUG, CFSTR(" msgid = %d"), storePrivate->notifyPortIdentifier);
82 }
83 msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
84 msg.header.msgh_size = sizeof(msg);
85 msg.header.msgh_remote_port = storePrivate->notifyPort;
86 msg.header.msgh_local_port = MACH_PORT_NULL;
87 msg.header.msgh_id = storePrivate->notifyPortIdentifier;
88 options = MACH_SEND_TIMEOUT;
89 status = mach_msg(&msg.header, /* msg */
90 MACH_SEND_MSG|options, /* options */
91 msg.header.msgh_size, /* send_size */
92 0, /* rcv_size */
93 MACH_PORT_NULL, /* rcv_name */
94 0, /* timeout */
95 MACH_PORT_NULL); /* notify */
96 }
97
98 if ((storePrivate->notifyStatus == Using_NotifierInformViaFD) &&
99 (storePrivate->notifyFile >= 0)) {
100 ssize_t written;
101
102 if (_configd_verbose) {
103 SCLog(TRUE, LOG_DEBUG, CFSTR("sending (UNIX domain) socket notification"));
104 SCLog(TRUE, LOG_DEBUG, CFSTR(" fd = %d"), storePrivate->notifyFile);
105 SCLog(TRUE, LOG_DEBUG, CFSTR(" msgid = %d"), storePrivate->notifyFileIdentifier);
106 }
107
108 written = write(storePrivate->notifyFile,
109 &storePrivate->notifyFileIdentifier,
110 sizeof(storePrivate->notifyFileIdentifier));
111 if (written == -1) {
112 if (errno == EWOULDBLOCK) {
113 SCLog(_configd_verbose, LOG_DEBUG,
114 CFSTR("sorry, only one outstanding notification per session."));
115 } else {
116 SCLog(_configd_verbose, LOG_DEBUG,
117 CFSTR("could not send notification, write() failed: %s"),
118 strerror(errno));
119 storePrivate->notifyFile = -1;
120 }
121 } else if (written != sizeof(storePrivate->notifyFileIdentifier)) {
122 SCLog(_configd_verbose, LOG_DEBUG,
123 CFSTR("could not send notification, incomplete write()"));
124 storePrivate->notifyFile = -1;
125 }
126 }
127
128 if ((storePrivate->notifyStatus == Using_NotifierInformViaSignal) &&
129 (storePrivate->notifySignal > 0)) {
130 kern_return_t status;
131 pid_t pid;
132 /*
133 * Post notification as signal
134 */
135 status = pid_for_task(storePrivate->notifySignalTask, &pid);
136 if (status == KERN_SUCCESS) {
137 if (_configd_verbose) {
138 SCLog(TRUE, LOG_DEBUG, CFSTR("sending signal notification"));
139 SCLog(TRUE, LOG_DEBUG, CFSTR(" pid = %d"), pid);
140 SCLog(TRUE, LOG_DEBUG, CFSTR(" signal = %d"), storePrivate->notifySignal);
141 }
142 if (kill(pid, storePrivate->notifySignal) != 0) {
143 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("could not send signal: %s"), strerror(errno));
144 status = KERN_FAILURE;
145 }
146 } else {
147 mach_port_type_t pt;
148
149 if ((mach_port_type(mach_task_self(), storePrivate->notifySignalTask, &pt) == KERN_SUCCESS) &&
150 (pt & MACH_PORT_TYPE_DEAD_NAME)) {
151 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("could not send signal, process died"));
152 } else {
153 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("could not send signal: %s"), mach_error_string(status));
154 }
155 }
156
157 if (status != KERN_SUCCESS) {
158 /* don't bother with any more attempts */
159 (void) mach_port_destroy(mach_task_self(), storePrivate->notifySignalTask);
160 storePrivate->notifySignal = 0;
161 storePrivate->notifySignalTask = TASK_NULL;
162 }
163 }
164 }
165 free(sessionsToNotify);
166
167 /*
168 * this list of notifications have been posted, wait for some more.
169 */
170 CFRelease(needsNotification);
171 needsNotification = NULL;
172
173 return;
174 }