2 * ConsoleMessage.c - ConsoleMessage main
3 * Wilfredo Sanchez | wsanchez@opensource.apple.com
4 * Kevin Van Vechten | kevinvv@uclink4.berkeley.edu
7 * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
9 * @APPLE_LICENSE_HEADER_START@
11 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
12 * Reserved. This file contains Original Code and/or Modifications of
13 * Original Code as defined in and that are subject to the Apple Public
14 * Source License Version 1.1 (the "License"). You may not use this file
15 * except in compliance with the License. Please obtain a copy of the
16 * License at http://www.apple.com/publicsource and read it before using
19 * The Original Code and all software distributed under the License are
20 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
21 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
22 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
24 * License for the specific language governing rights and limitations
27 * @APPLE_LICENSE_HEADER_END@
29 * The ConsoleMessage utility sends an IPC message to SystemStarter
30 * containing the message specified on the command line. SystemStarter
31 * will perform the localization. The message is also printed to
36 #include <crt_externs.h>
38 #include <mach/mach.h>
39 #include <mach/message.h>
40 #include <mach/mach_error.h>
41 #include <servers/bootstrap.h>
42 #include <CoreFoundation/CoreFoundation.h>
43 #include "SystemStarterIPC.h"
45 static CFDataRef
sendIPCMessage(CFStringRef aPortName
, CFDataRef aData
, CFStringRef aRunLoopMode
);
47 static void usage() __attribute__((__noreturn__
));
51 /* char* aProgram = **_NSGetArgv(); */
52 fprintf(stderr
, "usage:\n"
53 "\tConsoleMessage [-v] <message>\n"
54 "\tConsoleMessage [-v] -S\n"
55 "\tConsoleMessage [-v] -F\n"
56 "\tConsoleMessage [-v] -s <service>\n"
57 "\tConsoleMessage [-v] -f <service>\n"
58 "\tConsoleMessage [-v] -q <setting>\n"
59 "\tConsoleMessage [-v] -b <path>\n"
60 "\tConsoleMessage [-v] -u\n"
62 "\t-v: verbose (prints errors to stdout)\n"
63 "\t-S: mark all services as successful\n"
64 "\t-F: mark all services as failed\n"
65 "\t-s: mark a specific service as successful\n"
66 "\t-f: mark a specific service as failed\n"
67 "\t-q: query a configuration setting\n"
74 kActionConsoleMessage
,
81 main(int argc
, char *argv
[])
85 int anAction
= kActionConsoleMessage
;
86 char *aProgram
= argv
[0];
87 char *anArgCStr
= NULL
;
93 * Handle command line.
95 while ((c
= getopt(argc
, argv
, "?vSFs:f:q:b:u")) != -1) {
104 anAction
= kActionSuccess
;
108 anAction
= kActionFailure
;
112 anAction
= kActionSuccess
;
116 anAction
= kActionFailure
;
120 anAction
= kActionQuery
;
127 w4lw_f
= fopen("/var/run/waiting4loginwindow.pid", "r");
129 fscanf(w4lw_f
, "%d\n", &w4lw_pid
);
131 kill(w4lw_pid
, SIGTERM
);
136 fprintf(stderr
, "ignoring unknown option '-%c'\n", c
);
143 if ((anAction
== kActionConsoleMessage
&& argc
!= 1) ||
144 (anAction
== kActionSuccess
&& argc
!= 0) ||
145 (anAction
== kActionFailure
&& argc
!= 0) ||
146 (anAction
== kActionQuery
&& argc
!= 0)) {
150 fprintf(stderr
, "you must be root to run %s\n", aProgram
);
153 CFMutableDictionaryRef anIPCMessage
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
154 &kCFTypeDictionaryValueCallBacks
);
157 CFStringRef anArg
= NULL
;
158 CFIndex aPID
= getppid();
159 CFNumberRef aPIDNumber
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &aPID
);
162 * Parent process id is the process id of the startup
163 * item that called ConsoleMessage.
165 CFDictionarySetValue(anIPCMessage
, kIPCProcessIDKey
, aPIDNumber
);
166 CFRelease(aPIDNumber
);
169 anArg
= CFStringCreateWithCString(NULL
, anArgCStr
, kCFStringEncodingUTF8
);
171 if (anAction
== kActionSuccess
|| anAction
== kActionFailure
) {
172 CFBooleanRef aStatus
= (anAction
== kActionSuccess
) ? kCFBooleanTrue
: kCFBooleanFalse
;
173 CFDictionarySetValue(anIPCMessage
, kIPCMessageKey
, kIPCStatusMessage
);
174 CFDictionarySetValue(anIPCMessage
, kIPCStatusKey
, aStatus
);
176 CFDictionarySetValue(anIPCMessage
, kIPCServiceNameKey
, anArg
);
177 } else if (anAction
== kActionQuery
&& anArg
) {
178 CFDictionarySetValue(anIPCMessage
, kIPCMessageKey
, kIPCQueryMessage
);
179 CFDictionarySetValue(anIPCMessage
, kIPCConfigSettingKey
, anArg
);
180 } else if (anAction
== kActionConsoleMessage
) {
181 char *aConsoleMessageCStr
= argv
[0];
182 CFStringRef aConsoleMessage
= CFStringCreateWithCString(NULL
, aConsoleMessageCStr
, kCFStringEncodingUTF8
);
184 syslog(LOG_INFO
, "%s", aConsoleMessageCStr
);
186 CFDictionarySetValue(anIPCMessage
, kIPCMessageKey
, kIPCConsoleMessage
);
187 CFDictionarySetValue(anIPCMessage
, kIPCConsoleMessageKey
, aConsoleMessage
);
188 CFRelease(aConsoleMessage
);
194 CFDataRef aData
= CFPropertyListCreateXMLData(NULL
, anIPCMessage
);
196 CFDataRef aResultData
= sendIPCMessage(CFSTR(kSystemStarterMessagePort
), aData
, kCFRunLoopDefaultMode
);
198 /* aResultData should be ASCIZ */
200 fprintf(stdout
, "%s", CFDataGetBytePtr(aResultData
));
201 CFRelease(aResultData
);
203 char *aConsoleMessageCStr
= argv
[0];
204 fprintf(stdout
, "%s\n", aConsoleMessageCStr
);
207 fprintf(stderr
, "%s could not connect to SystemStarter.\n", aProgram
);
213 fprintf(stderr
, "%s: not enough memory to create IPC message.\n", aProgram
);
219 fprintf(stderr
, "%s: not enough memory to create IPC message.\n", aProgram
);
232 static void replyCallback(CFMachPortRef port
__attribute__((unused
)), void *aPtr
, CFIndex aSize
__attribute__((unused
)), CFDataRef
* aReply
) {
233 SystemStarterIPCMessage
*aMessage
= (SystemStarterIPCMessage
*) aPtr
;
235 if (aReply
!= NULL
&&
236 aMessage
->aProtocol
== kIPCProtocolVersion
&&
237 aMessage
->aByteLength
>= 0) {
238 *aReply
= CFDataCreate(NULL
, (char *) aMessage
+ aMessage
->aByteLength
, aMessage
->aByteLength
);
239 } else if (aReply
!= NULL
) {
246 sendIPCMessage(CFStringRef aPortName
, CFDataRef aData
, CFStringRef aRunLoopMode
)
248 SystemStarterIPCMessage
*aMessage
= NULL
;
249 CFRunLoopSourceRef aSource
= NULL
;
250 CFMachPortRef aMachPort
= NULL
, aReplyPort
= NULL
;
251 CFMachPortContext aContext
;
252 kern_return_t aKernReturn
= KERN_FAILURE
;
253 mach_port_t aBootstrapPort
, aNativePort
;
254 char *aPortNameUTF8String
;
255 CFDataRef aReply
= NULL
;
258 aContext
.version
= 0;
259 aContext
.info
= (void *) NULL
;
261 aContext
.release
= 0;
262 aContext
.copyDescription
= 0;
264 /* Look up the remote port by name */
266 aStrLen
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(aPortName
) + 1, kCFStringEncodingUTF8
);
267 aPortNameUTF8String
= malloc(aStrLen
);
268 if (aPortNameUTF8String
) {
269 CFStringGetCString(aPortName
, aPortNameUTF8String
, aStrLen
, kCFStringEncodingUTF8
);
270 task_get_bootstrap_port(mach_task_self(), &aBootstrapPort
);
271 aKernReturn
= bootstrap_look_up(aBootstrapPort
, aPortNameUTF8String
, &aNativePort
);
272 aMachPort
= (KERN_SUCCESS
== aKernReturn
) ? CFMachPortCreateWithPort(NULL
, aNativePort
, (CFMachPortCallBack
) dummyCallback
, &aContext
, NULL
) : NULL
;
273 free(aPortNameUTF8String
);
275 /* Create a reply port and associated run loop source */
276 aContext
.info
= &aReply
;
277 aReplyPort
= CFMachPortCreate(NULL
, (CFMachPortCallBack
) replyCallback
, &aContext
, NULL
);
279 aSource
= CFMachPortCreateRunLoopSource(NULL
, aReplyPort
, 0);
281 CFRunLoopAddSource(CFRunLoopGetCurrent(), aSource
, aRunLoopMode
);
284 /* Allocate a buffer for the message */
285 if (aData
&& aMachPort
&& aReplyPort
) {
286 SInt32 aSize
= (sizeof(SystemStarterIPCMessage
) + (CFDataGetLength(aData
) + 3)) & ~0x3;
287 aMessage
= (SystemStarterIPCMessage
*) malloc(aSize
);
289 aMessage
->aHeader
.msgh_id
= 1;
290 aMessage
->aHeader
.msgh_size
= aSize
;
291 aMessage
->aHeader
.msgh_remote_port
= CFMachPortGetPort(aMachPort
);
292 aMessage
->aHeader
.msgh_local_port
= CFMachPortGetPort(aReplyPort
);
293 aMessage
->aHeader
.msgh_reserved
= 0;
294 aMessage
->aHeader
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
, MACH_MSG_TYPE_MAKE_SEND_ONCE
);
295 aMessage
->aBody
.msgh_descriptor_count
= 0;
296 aMessage
->aProtocol
= kIPCProtocolVersion
;
297 aMessage
->aByteLength
= CFDataGetLength(aData
);
298 memmove((uint8_t *) aMessage
+ sizeof(SystemStarterIPCMessage
),
299 CFDataGetBytePtr(aData
),
300 CFDataGetLength(aData
));
303 /* Wait up to 1 second to send the message */
305 aKernReturn
= mach_msg((mach_msg_header_t
*) aMessage
, MACH_SEND_MSG
| MACH_SEND_TIMEOUT
, aMessage
->aHeader
.msgh_size
, 0, MACH_PORT_NULL
, 1000.0, MACH_PORT_NULL
);
308 /* Wait up to 30 seconds for the reply */
309 if (aSource
&& aKernReturn
== MACH_MSG_SUCCESS
) {
310 CFRetain(aReplyPort
);
311 CFRunLoopRunInMode(aRunLoopMode
, 30.0, true);
313 * aReplyPort's replyCallback will set the local aReply
316 CFRelease(aReplyPort
);
319 CFRelease(aMachPort
);
321 CFRelease(aReplyPort
);
323 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), aSource
, aRunLoopMode
);