#include <unistd.h>
#include <crt_externs.h>
#include <syslog.h>
#include <CoreFoundation/CoreFoundation.h>
#include "../SystemStarter/SystemStarterIPC.h"
static void usage() __attribute__((__noreturn__));
static void usage()
{
fprintf( stderr, "usage:\n"
"\tConsoleMessage [-v] <message>\n"
"\tConsoleMessage [-v] -S\n"
"\tConsoleMessage [-v] -F\n"
"\tConsoleMessage [-v] -s <service>\n"
"\tConsoleMessage [-v] -f <service>\n"
"\tConsoleMessage [-v] -q <setting>\n"
"\tConsoleMessage [-v] -b <path>\n"
"\tConsoleMessage [-v] -u\n"
"\noptions:\n"
"\t-v: verbose (prints errors to stdout)\n"
"\t-S: mark all services as successful\n"
"\t-F: mark all services as failed\n"
"\t-s: mark a specific service as successful\n"
"\t-f: mark a specific service as failed\n"
"\t-q: query a configuration setting\n"
"\t-b: load the display bundle at the specified path\n"
"\t-u: unload the display bundle\n");
exit(1);
}
enum {
kActionConsoleMessage,
kActionSuccess,
kActionFailure,
kActionQuery,
kActionLoadDisplayBundle,
kActionUnloadDisplayBundle
};
int main (int argc, char *argv[])
{
int anExitCode = 0;
int aVerboseFlag = 0;
int anAction = kActionConsoleMessage;
char* aProgram = argv[0];
char* anArgCStr = NULL;
{
char c;
while ((c = getopt(argc, argv, "?vSFs:f:q:b:u")) != -1) {
switch (c) {
case '?':
usage();
break;
case 'v':
aVerboseFlag = 1;
break;
case 'S':
anAction = kActionSuccess;
anArgCStr = NULL;
break;
case 'F':
anAction = kActionFailure;
anArgCStr = NULL;
break;
case 's':
anAction = kActionSuccess;
anArgCStr = optarg;
break;
case 'f':
anAction = kActionFailure;
anArgCStr = optarg;
break;
case 'q':
anAction = kActionQuery;
anArgCStr = optarg;
break;
case 'b':
anAction = kActionLoadDisplayBundle;
anArgCStr = optarg;
break;
case 'u':
anAction = kActionUnloadDisplayBundle;
break;
default:
fprintf(stderr, "ignoring unknown option '-%c'\n", c);
break;
}
}
argc -= optind;
argv += optind;
}
if ((anAction == kActionConsoleMessage && argc != 1) ||
(anAction == kActionSuccess && argc != 0) ||
(anAction == kActionFailure && argc != 0) ||
(anAction == kActionQuery && argc != 0) ||
(anAction == kActionLoadDisplayBundle && argc != 0) ||
(anAction == kActionUnloadDisplayBundle && argc != 0) )
{
usage();
}
if (getuid() != 0)
{
fprintf(stderr, "you must be root to run %s\n", aProgram);
exit(1);
}
else
{
CFMutableDictionaryRef anIPCMessage = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (anIPCMessage)
{
CFStringRef anArg = NULL;
CFIndex aPID = getppid();
CFNumberRef aPIDNumber = CFNumberCreate(NULL, kCFNumberCFIndexType, &aPID);
CFDictionarySetValue(anIPCMessage, kIPCProcessIDKey, aPIDNumber);
CFRelease(aPIDNumber);
if (anArgCStr)
{
anArg = CFStringCreateWithCString(NULL, anArgCStr, kCFStringEncodingUTF8);
}
if (anAction == kActionSuccess || anAction == kActionFailure)
{
CFBooleanRef aStatus = (anAction == kActionSuccess) ? kCFBooleanTrue : kCFBooleanFalse;
CFDictionarySetValue(anIPCMessage, kIPCMessageKey, kIPCStatusMessage);
CFDictionarySetValue(anIPCMessage, kIPCStatusKey, aStatus);
if (anArg) CFDictionarySetValue(anIPCMessage, kIPCServiceNameKey, anArg);
}
else if (anAction == kActionQuery && anArg)
{
CFDictionarySetValue(anIPCMessage, kIPCMessageKey, kIPCQueryMessage);
CFDictionarySetValue(anIPCMessage, kIPCConfigSettingKey, anArg);
}
else if (anAction == kActionLoadDisplayBundle && anArg)
{
CFDictionarySetValue(anIPCMessage, kIPCMessageKey, kIPCLoadDisplayBundleMessage);
CFDictionarySetValue(anIPCMessage, kIPCDisplayBundlePathKey, anArg);
}
else if (anAction == kActionUnloadDisplayBundle)
{
CFDictionarySetValue(anIPCMessage, kIPCMessageKey, kIPCUnloadDisplayBundleMessage);
}
else if (anAction == kActionConsoleMessage)
{
char* aConsoleMessageCStr = argv[0];
CFStringRef aConsoleMessage = CFStringCreateWithCString(NULL, aConsoleMessageCStr, kCFStringEncodingUTF8);
syslog(LOG_INFO, "%s", aConsoleMessageCStr);
CFDictionarySetValue(anIPCMessage, kIPCMessageKey, kIPCConsoleMessage);
CFDictionarySetValue(anIPCMessage, kIPCConsoleMessageKey, aConsoleMessage);
CFRelease(aConsoleMessage);
}
if (anArg) CFRelease(anArg);
{
CFMessagePortRef aPort = CFMessagePortCreateRemote(NULL, kSystemStarterMessagePort);
if (aPort)
{
CFDataRef aData = CFPropertyListCreateXMLData(NULL, anIPCMessage);
if (aData)
{
CFDataRef aResultData = NULL;
int aResult = CFMessagePortSendRequest(aPort,
kIPCProtocolVersion,
aData,
0.0,
30.0,
kCFRunLoopDefaultMode,
&aResultData);
if (aResult == kCFMessagePortSuccess)
{
if (aResultData)
{
fprintf(stdout, "%s", CFDataGetBytePtr(aResultData));
CFRelease(aResultData);
}
}
else
{
if (aVerboseFlag) fprintf(stderr, "Failed to send message to SystemStarter: %d\n", aResult);
anExitCode = 1;
}
CFRelease(aData);
}
CFRelease(aPort);
}
else
{
char* aConsoleMessageCStr = argv[0];
fprintf(stdout, "%s\n", aConsoleMessageCStr);
if (aVerboseFlag) fprintf(stderr, "%s could not connect to SystemStarter.\n", aProgram);
anExitCode = 0;
}
}
}
else
{
if (aVerboseFlag) fprintf(stderr, "%s: not enough memory to create IPC message.\n", aProgram);
anExitCode = 1;
}
}
exit(anExitCode);
}