http://www.opensource.apple.com/source/launchd/launchd-328/launchd/src/launch.h http://www.opensource.apple.com/source/initng/initng-12/initng/src/launchctl.c
Last active
April 26, 2024 20:24
-
-
Save also/69b592aaf1fdf4056d91 to your computer and use it in GitHub Desktop.
launchd from node
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var ffi = require('ffi'); | |
var ref = require('ref'); | |
var LAUNCH_KEY_CHECKIN = 'CheckIn'; | |
var LAUNCH_JOBKEY_SOCKETS = 'Sockets'; | |
var LAUNCH_DATA_DICTIONARY = 1; | |
var LAUNCH_DATA_ERRNO = 9; | |
var launch_data_t = ref.refType(ref.types.void); | |
var launch_data_type_t = 'int'; | |
var liblaunch = ffi.Library('/usr/lib/system/liblaunch.dylib', { | |
launch_data_new_string: [launch_data_t, [ref.types.CString]], | |
launch_msg: [launch_data_t, [launch_data_t]], | |
launch_data_get_type: [launch_data_type_t, [launch_data_t]], | |
launch_data_get_errno: [launch_data_type_t, [launch_data_t]], | |
launch_data_free: ['void', [launch_data_t]], | |
launch_data_dict_lookup: [launch_data_t, [launch_data_t, ref.types.CString]], | |
launch_data_dict_iterate: ['void', [launch_data_t, ref.refType(ref.types.void)]], | |
launch_data_array_get_count: ['size_t', [launch_data_t]], | |
launch_data_array_get_index: [launch_data_t, [launch_data_t, 'size_t']], | |
launch_data_get_fd: ['int', [launch_data_t]] | |
}); | |
module.exports = function() { | |
var toFree = []; | |
var fds = {}; | |
var sockIterateCallback = new ffi.Callback('void', [launch_data_t, ref.types.CString, 'void'], function(data, name) { | |
var sockCount = liblaunch.launch_data_array_get_count(data); | |
if (sockCount !== 1) { | |
throw new Error('launchd: multiple sockets configured for ' + name); | |
} | |
var socketData = liblaunch.launch_data_array_get_index(data, 0); | |
fds[name] = liblaunch.launch_data_get_fd(socketData); | |
}, null); | |
try { | |
var checkinRequest = liblaunch.launch_data_new_string(LAUNCH_KEY_CHECKIN); | |
toFree.push(checkinRequest); | |
var checkinResponse = liblaunch.launch_msg(checkinRequest); | |
if (checkinResponse.isNull()) { | |
throw new Error('launchd: no checkin response'); | |
} | |
toFree.push(checkinResponse); | |
var checkinResponseType = liblaunch.launch_data_get_type(checkinResponse); | |
if (checkinResponseType === LAUNCH_DATA_ERRNO) { | |
throw new Error('launchd: error ' + liblaunch.launch_data_get_errno(checkinResponse)); | |
} else if (checkinResponseType === LAUNCH_DATA_DICTIONARY) { | |
var dict = liblaunch.launch_data_dict_lookup(checkinResponse, LAUNCH_JOBKEY_SOCKETS); | |
if (dict.isNull()) { | |
throw new Error('launchd: no sockets configured'); | |
} | |
liblaunch.launch_data_dict_iterate(dict, sockIterateCallback); | |
} else { | |
throw new Error('launchd: unexpected response ' + checkinResponseType); | |
} | |
} finally { | |
toFree.forEach(function(data) { liblaunch.launch_data_free(data); }); | |
} | |
return fds; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2005 Apple Computer, Inc. All rights reserved. | |
* | |
* @APPLE_APACHE_LICENSE_HEADER_START@ | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
* | |
* @APPLE_APACHE_LICENSE_HEADER_END@ | |
*/ | |
#ifndef _LAUNCH_H_ | |
#define _LAUNCH_H_ | |
#include <mach/mach.h> | |
#include <sys/cdefs.h> | |
#include <stddef.h> | |
#include <stdbool.h> | |
#pragma GCC visibility push(default) | |
__BEGIN_DECLS | |
#ifdef __GNUC__ | |
#define __ld_normal __attribute__((__nothrow__)) | |
#define __ld_setter __attribute__((__nothrow__, __nonnull__)) | |
#define __ld_getter __attribute__((__nothrow__, __nonnull__, __pure__, __warn_unused_result__)) | |
#define __ld_iterator(x, y) __attribute__((__nonnull__(x, y))) | |
#define __ld_allocator __attribute__((__nothrow__, __malloc__, __nonnull__, __warn_unused_result__)) | |
#else | |
#define __ld_normal | |
#define __ld_setter | |
#define __ld_getter | |
#define __ld_iterator(x, y) | |
#define __ld_allocator | |
#endif | |
#define LAUNCH_KEY_SUBMITJOB "SubmitJob" | |
#define LAUNCH_KEY_REMOVEJOB "RemoveJob" | |
#define LAUNCH_KEY_STARTJOB "StartJob" | |
#define LAUNCH_KEY_STOPJOB "StopJob" | |
#define LAUNCH_KEY_GETJOB "GetJob" | |
#define LAUNCH_KEY_GETJOBS "GetJobs" | |
#define LAUNCH_KEY_CHECKIN "CheckIn" | |
#define LAUNCH_JOBKEY_LABEL "Label" | |
#define LAUNCH_JOBKEY_DISABLED "Disabled" | |
#define LAUNCH_JOBKEY_USERNAME "UserName" | |
#define LAUNCH_JOBKEY_GROUPNAME "GroupName" | |
#define LAUNCH_JOBKEY_TIMEOUT "TimeOut" | |
#define LAUNCH_JOBKEY_EXITTIMEOUT "ExitTimeOut" | |
#define LAUNCH_JOBKEY_INITGROUPS "InitGroups" | |
#define LAUNCH_JOBKEY_SOCKETS "Sockets" | |
#define LAUNCH_JOBKEY_MACHSERVICES "MachServices" | |
#define LAUNCH_JOBKEY_MACHSERVICELOOKUPPOLICIES "MachServiceLookupPolicies" | |
#define LAUNCH_JOBKEY_INETDCOMPATIBILITY "inetdCompatibility" | |
#define LAUNCH_JOBKEY_ENABLEGLOBBING "EnableGlobbing" | |
#define LAUNCH_JOBKEY_PROGRAMARGUMENTS "ProgramArguments" | |
#define LAUNCH_JOBKEY_PROGRAM "Program" | |
#define LAUNCH_JOBKEY_ONDEMAND "OnDemand" | |
#define LAUNCH_JOBKEY_KEEPALIVE "KeepAlive" | |
#define LAUNCH_JOBKEY_LIMITLOADTOHOSTS "LimitLoadToHosts" | |
#define LAUNCH_JOBKEY_LIMITLOADFROMHOSTS "LimitLoadFromHosts" | |
#define LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE "LimitLoadToSessionType" | |
#define LAUNCH_JOBKEY_RUNATLOAD "RunAtLoad" | |
#define LAUNCH_JOBKEY_ROOTDIRECTORY "RootDirectory" | |
#define LAUNCH_JOBKEY_WORKINGDIRECTORY "WorkingDirectory" | |
#define LAUNCH_JOBKEY_ENVIRONMENTVARIABLES "EnvironmentVariables" | |
#define LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES "UserEnvironmentVariables" | |
#define LAUNCH_JOBKEY_UMASK "Umask" | |
#define LAUNCH_JOBKEY_NICE "Nice" | |
#define LAUNCH_JOBKEY_HOPEFULLYEXITSFIRST "HopefullyExitsFirst" | |
#define LAUNCH_JOBKEY_HOPEFULLYEXITSLAST "HopefullyExitsLast" | |
#define LAUNCH_JOBKEY_LOWPRIORITYIO "LowPriorityIO" | |
#define LAUNCH_JOBKEY_SESSIONCREATE "SessionCreate" | |
#define LAUNCH_JOBKEY_STARTONMOUNT "StartOnMount" | |
#define LAUNCH_JOBKEY_SOFTRESOURCELIMITS "SoftResourceLimits" | |
#define LAUNCH_JOBKEY_HARDRESOURCELIMITS "HardResourceLimits" | |
#define LAUNCH_JOBKEY_STANDARDINPATH "StandardInPath" | |
#define LAUNCH_JOBKEY_STANDARDOUTPATH "StandardOutPath" | |
#define LAUNCH_JOBKEY_STANDARDERRORPATH "StandardErrorPath" | |
#define LAUNCH_JOBKEY_DEBUG "Debug" | |
#define LAUNCH_JOBKEY_WAITFORDEBUGGER "WaitForDebugger" | |
#define LAUNCH_JOBKEY_QUEUEDIRECTORIES "QueueDirectories" | |
#define LAUNCH_JOBKEY_WATCHPATHS "WatchPaths" | |
#define LAUNCH_JOBKEY_STARTINTERVAL "StartInterval" | |
#define LAUNCH_JOBKEY_STARTCALENDARINTERVAL "StartCalendarInterval" | |
#define LAUNCH_JOBKEY_BONJOURFDS "BonjourFDs" | |
#define LAUNCH_JOBKEY_LASTEXITSTATUS "LastExitStatus" | |
#define LAUNCH_JOBKEY_PID "PID" | |
#define LAUNCH_JOBKEY_THROTTLEINTERVAL "ThrottleInterval" | |
#define LAUNCH_JOBKEY_LAUNCHONLYONCE "LaunchOnlyOnce" | |
#define LAUNCH_JOBKEY_ABANDONPROCESSGROUP "AbandonProcessGroup" | |
#define LAUNCH_JOBKEY_IGNOREPROCESSGROUPATSHUTDOWN "IgnoreProcessGroupAtShutdown" | |
#define LAUNCH_JOBKEY_POLICIES "Policies" | |
#define LAUNCH_JOBKEY_ENABLETRANSACTIONS "EnableTransactions" | |
#define LAUNCH_JOBPOLICY_DENYCREATINGOTHERJOBS "DenyCreatingOtherJobs" | |
#define LAUNCH_JOBINETDCOMPATIBILITY_WAIT "Wait" | |
#define LAUNCH_JOBKEY_MACH_RESETATCLOSE "ResetAtClose" | |
#define LAUNCH_JOBKEY_MACH_HIDEUNTILCHECKIN "HideUntilCheckIn" | |
#define LAUNCH_JOBKEY_MACH_DRAINMESSAGESONCRASH "DrainMessagesOnCrash" | |
#define LAUNCH_JOBKEY_KEEPALIVE_SUCCESSFULEXIT "SuccessfulExit" | |
#define LAUNCH_JOBKEY_KEEPALIVE_NETWORKSTATE "NetworkState" | |
#define LAUNCH_JOBKEY_KEEPALIVE_PATHSTATE "PathState" | |
#define LAUNCH_JOBKEY_KEEPALIVE_OTHERJOBACTIVE "OtherJobActive" | |
#define LAUNCH_JOBKEY_KEEPALIVE_OTHERJOBENABLED "OtherJobEnabled" | |
#define LAUNCH_JOBKEY_KEEPALIVE_AFTERINITIALDEMAND "AfterInitialDemand" | |
#define LAUNCH_JOBKEY_CAL_MINUTE "Minute" | |
#define LAUNCH_JOBKEY_CAL_HOUR "Hour" | |
#define LAUNCH_JOBKEY_CAL_DAY "Day" | |
#define LAUNCH_JOBKEY_CAL_WEEKDAY "Weekday" | |
#define LAUNCH_JOBKEY_CAL_MONTH "Month" | |
#define LAUNCH_JOBKEY_RESOURCELIMIT_CORE "Core" | |
#define LAUNCH_JOBKEY_RESOURCELIMIT_CPU "CPU" | |
#define LAUNCH_JOBKEY_RESOURCELIMIT_DATA "Data" | |
#define LAUNCH_JOBKEY_RESOURCELIMIT_FSIZE "FileSize" | |
#define LAUNCH_JOBKEY_RESOURCELIMIT_MEMLOCK "MemoryLock" | |
#define LAUNCH_JOBKEY_RESOURCELIMIT_NOFILE "NumberOfFiles" | |
#define LAUNCH_JOBKEY_RESOURCELIMIT_NPROC "NumberOfProcesses" | |
#define LAUNCH_JOBKEY_RESOURCELIMIT_RSS "ResidentSetSize" | |
#define LAUNCH_JOBKEY_RESOURCELIMIT_STACK "Stack" | |
#define LAUNCH_JOBKEY_DISABLED_MACHINETYPE "MachineType" | |
#define LAUNCH_JOBKEY_DISABLED_MODELNAME "ModelName" | |
#define LAUNCH_JOBSOCKETKEY_TYPE "SockType" | |
#define LAUNCH_JOBSOCKETKEY_PASSIVE "SockPassive" | |
#define LAUNCH_JOBSOCKETKEY_BONJOUR "Bonjour" | |
#define LAUNCH_JOBSOCKETKEY_SECUREWITHKEY "SecureSocketWithKey" | |
#define LAUNCH_JOBSOCKETKEY_PATHNAME "SockPathName" | |
#define LAUNCH_JOBSOCKETKEY_PATHMODE "SockPathMode" | |
#define LAUNCH_JOBSOCKETKEY_NODENAME "SockNodeName" | |
#define LAUNCH_JOBSOCKETKEY_SERVICENAME "SockServiceName" | |
#define LAUNCH_JOBSOCKETKEY_FAMILY "SockFamily" | |
#define LAUNCH_JOBSOCKETKEY_PROTOCOL "SockProtocol" | |
#define LAUNCH_JOBSOCKETKEY_MULTICASTGROUP "MulticastGroup" | |
typedef struct _launch_data *launch_data_t; | |
typedef enum { | |
LAUNCH_DATA_DICTIONARY = 1, | |
LAUNCH_DATA_ARRAY, | |
LAUNCH_DATA_FD, | |
LAUNCH_DATA_INTEGER, | |
LAUNCH_DATA_REAL, | |
LAUNCH_DATA_BOOL, | |
LAUNCH_DATA_STRING, | |
LAUNCH_DATA_OPAQUE, | |
LAUNCH_DATA_ERRNO, | |
LAUNCH_DATA_MACHPORT, | |
} launch_data_type_t; | |
launch_data_t launch_data_alloc(launch_data_type_t) __ld_allocator; | |
launch_data_t launch_data_copy(launch_data_t) __ld_allocator; | |
launch_data_type_t launch_data_get_type(const launch_data_t) __ld_getter; | |
void launch_data_free(launch_data_t) __ld_setter; | |
/* Generic Dictionaries */ | |
/* the value should not be changed while iterating */ | |
bool launch_data_dict_insert(launch_data_t, const launch_data_t, const char *) __ld_setter; | |
launch_data_t launch_data_dict_lookup(const launch_data_t, const char *) __ld_getter; | |
bool launch_data_dict_remove(launch_data_t, const char *) __ld_setter; | |
void launch_data_dict_iterate(const launch_data_t, void (*)(const launch_data_t, const char *, void *), void *) __ld_iterator(1, 2); | |
size_t launch_data_dict_get_count(const launch_data_t) __ld_getter; | |
/* Generic Arrays */ | |
bool launch_data_array_set_index(launch_data_t, const launch_data_t, size_t) __ld_setter; | |
launch_data_t launch_data_array_get_index(const launch_data_t, size_t) __ld_getter; | |
size_t launch_data_array_get_count(const launch_data_t) __ld_getter; | |
launch_data_t launch_data_new_fd(int) __ld_allocator; | |
launch_data_t launch_data_new_machport(mach_port_t) __ld_allocator; | |
launch_data_t launch_data_new_integer(long long) __ld_allocator; | |
launch_data_t launch_data_new_bool(bool) __ld_allocator; | |
launch_data_t launch_data_new_real(double) __ld_allocator; | |
launch_data_t launch_data_new_string(const char *) __ld_allocator; | |
launch_data_t launch_data_new_opaque(const void *, size_t) __ld_allocator; | |
bool launch_data_set_fd(launch_data_t, int) __ld_setter; | |
bool launch_data_set_machport(launch_data_t, mach_port_t) __ld_setter; | |
bool launch_data_set_integer(launch_data_t, long long) __ld_setter; | |
bool launch_data_set_bool(launch_data_t, bool) __ld_setter; | |
bool launch_data_set_real(launch_data_t, double) __ld_setter; | |
bool launch_data_set_string(launch_data_t, const char *) __ld_setter; | |
bool launch_data_set_opaque(launch_data_t, const void *, size_t) __ld_setter; | |
int launch_data_get_fd(const launch_data_t) __ld_getter; | |
mach_port_t launch_data_get_machport(const launch_data_t) __ld_getter; | |
long long launch_data_get_integer(const launch_data_t) __ld_getter; | |
bool launch_data_get_bool(const launch_data_t) __ld_getter; | |
double launch_data_get_real(const launch_data_t) __ld_getter; | |
const char * launch_data_get_string(const launch_data_t) __ld_getter; | |
void * launch_data_get_opaque(const launch_data_t) __ld_getter; | |
size_t launch_data_get_opaque_size(const launch_data_t) __ld_getter; | |
int launch_data_get_errno(const launch_data_t) __ld_getter; | |
/* launch_get_fd() | |
* | |
* Use this to get the FD if you're doing asynchronous I/O with select(), | |
* poll() or kevent(). | |
*/ | |
int launch_get_fd(void) __ld_normal; | |
/* launch_msg() | |
* | |
* Use this API to send and receive messages. | |
* Calling launch_msg() with no message to send is a valid way to get | |
* asynchronously received messages. | |
* | |
* If a message was to be sent, it returns NULL and errno on failure. | |
* | |
* If no messages were to be sent, it returns NULL and errno is set to zero if | |
* no more asynchronous messages are available. | |
*/ | |
launch_data_t launch_msg(const launch_data_t) __ld_normal; | |
__END_DECLS | |
#pragma GCC visibility pop | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <CoreFoundation/CoreFoundation.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <sys/socket.h> | |
#include <sys/un.h> | |
#include <netinet/in.h> | |
#include <unistd.h> | |
#include <dirent.h> | |
#include <pwd.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <pwd.h> | |
#include <grp.h> | |
#include <netdb.h> | |
#include "launch.h" | |
#define LAUNCH_SECDIR "/tmp/launch-XXXXXX" | |
static const char *argv0 = NULL; | |
static void distill_config_file(launch_data_t); | |
static void sock_dict_cb(launch_data_t what, const char *key, void *context); | |
static launch_data_t CF2launch_data(CFTypeRef); | |
static CFPropertyListRef CreateMyPropertyListFromFile(const char *); | |
static void usage(FILE *) __attribute__((noreturn)); | |
static void loadcfg(const char *); | |
static void unloadcfg(const char *); | |
static void get_launchd_env(void); | |
static void set_launchd_env(const char *); | |
static void unset_launchd_env(const char *); | |
static void set_launchd_envkv(const char *key, const char *val); | |
int main(int argc, char *argv[]) | |
{ | |
int ch; | |
argv0 = argv[0]; | |
while ((ch = getopt(argc, argv, "U:ES:hl:u:")) != -1) { | |
switch (ch) { | |
case 'U': | |
unset_launchd_env(optarg); | |
break; | |
case 'E': | |
get_launchd_env(); | |
break; | |
case 'S': | |
set_launchd_env(optarg); | |
break; | |
case 'l': | |
loadcfg(optarg); | |
break; | |
case 'u': | |
unloadcfg(optarg); | |
break; | |
case 'h': | |
usage(stdout); | |
break; | |
case '?': | |
default: | |
usage(stderr); | |
break; | |
} | |
} | |
exit(EXIT_SUCCESS); | |
} | |
static void print_launchd_env(launch_data_t obj, const char *key, void *context) | |
{ | |
if (context) | |
fprintf(stdout, "setenv %s %s;\n", key, launch_data_get_string(obj)); | |
else | |
fprintf(stdout, "%s=%s; export %s;\n", key, launch_data_get_string(obj), key); | |
} | |
static void unset_launchd_env(const char *arg) | |
{ | |
launch_data_t resp, tmp, req = launch_data_alloc(LAUNCH_DATA_DICTIONARY); | |
tmp = launch_data_alloc(LAUNCH_DATA_STRING); | |
launch_data_set_string(tmp, arg); | |
launch_data_dict_insert(req, tmp, "UnsetUserEnvironment"); | |
resp = launch_msg(req); | |
launch_data_free(req); | |
if (resp) { | |
launch_data_free(resp); | |
} else { | |
fprintf(stderr, "launch_msg(\"UnsetUserEnvironment\"): %s\n", strerror(errno)); | |
} | |
} | |
static void set_launchd_env(const char *arg) | |
{ | |
const char *key = arg, *val = strchr(arg, '='); | |
if (val) { | |
*val = '\0'; | |
val++; | |
} else | |
val = ""; | |
set_launchd_envkv(key, val); | |
} | |
static void set_launchd_envkv(const char *key, const char *val) | |
{ | |
launch_data_t resp, tmp, tmpv, req = launch_data_alloc(LAUNCH_DATA_DICTIONARY); | |
tmp = launch_data_alloc(LAUNCH_DATA_DICTIONARY); | |
tmpv = launch_data_alloc(LAUNCH_DATA_STRING); | |
launch_data_set_string(tmpv, val); | |
launch_data_dict_insert(tmp, tmpv, key); | |
launch_data_dict_insert(req, tmp, "SetUserEnvironment"); | |
resp = launch_msg(req); | |
launch_data_free(req); | |
if (resp) { | |
launch_data_free(resp); | |
} else { | |
fprintf(stderr, "launch_msg(\"SetUserEnvironment\"): %s\n", strerror(errno)); | |
} | |
} | |
static void get_launchd_env(void) | |
{ | |
launch_data_t resp, req = launch_data_alloc(LAUNCH_DATA_STRING); | |
char *s = getenv("SHELL"); | |
launch_data_set_string(req, "GetUserEnvironment"); | |
resp = launch_msg(req); | |
if (resp) { | |
launch_data_dict_iterate(resp, print_launchd_env, s ? strstr(s, "csh") : NULL); | |
launch_data_free(resp); | |
} else { | |
fprintf(stderr, "launch_msg(\"GetUserEnvironment\"): %s\n", strerror(errno)); | |
} | |
} | |
static void unloadcfg(const char *what) | |
{ | |
CFPropertyListRef plist = CreateMyPropertyListFromFile(what); | |
launch_data_t resp, tmp, tmps, msg, id_plist; | |
if (!plist) { | |
fprintf(stderr, "%s: no plist was returned for: %s\n", argv0, what); | |
return; | |
} | |
id_plist = CF2launch_data(plist); | |
msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); | |
tmp = launch_data_alloc(LAUNCH_DATA_STRING); | |
tmps = launch_data_dict_lookup(id_plist, "Label"); | |
launch_data_set_string(tmp, launch_data_get_string(tmps)); | |
launch_data_free(id_plist); | |
launch_data_dict_insert(msg, tmp, "RemoveJob"); | |
resp = launch_msg(msg); | |
launch_data_free(msg); | |
if (LAUNCH_DATA_STRING == launch_data_get_type(resp)) { | |
if (strcmp("Success", launch_data_get_string(resp))) | |
fprintf(stderr, "%s\n", launch_data_get_string(resp)); | |
} | |
launch_data_free(resp); | |
} | |
static void loadcfg(const char *what) | |
{ | |
CFPropertyListRef plist; | |
DIR *d; | |
struct dirent *de; | |
struct stat sb; | |
char *foo; | |
launch_data_t resp, msg, tmp, tmpa, id_plist; | |
if (stat(what, &sb) == -1) | |
return; | |
if (S_ISREG(sb.st_mode)) { | |
msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); | |
plist = CreateMyPropertyListFromFile(what); | |
if (!plist) { | |
fprintf(stderr, "%s: no plist was returned for: %s\n", argv0, what); | |
return; | |
} | |
id_plist = CF2launch_data(plist); | |
if ((tmp = launch_data_dict_lookup(id_plist, "Disabled"))) { | |
if (launch_data_get_bool(tmp)) { | |
launch_data_free(id_plist); | |
return; | |
} | |
} | |
distill_config_file(id_plist); | |
launch_data_dict_insert(msg, id_plist, "SubmitJob"); | |
} else { | |
msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); | |
tmpa = launch_data_alloc(LAUNCH_DATA_ARRAY); | |
if ((d = opendir(what)) == NULL) { | |
fprintf(stderr, "%s: opendir() failed to open the directory\n", argv0); | |
exit(EXIT_FAILURE); | |
} | |
while ((de = readdir(d)) != NULL) { | |
if ((de->d_name[0] == '.')) | |
continue; | |
asprintf(&foo, "%s/%s", what, de->d_name); | |
plist = CreateMyPropertyListFromFile(foo); | |
if (!plist) { | |
fprintf(stderr, "%s: no plist was returned for: %s\n", argv0, foo); | |
free(foo); | |
continue; | |
} | |
free(foo); | |
id_plist = CF2launch_data(plist); | |
if ((tmp = launch_data_dict_lookup(id_plist, "Disabled"))) { | |
if (launch_data_get_bool(tmp)) { | |
launch_data_free(id_plist); | |
continue; | |
} | |
} | |
distill_config_file(id_plist); | |
launch_data_array_set_index(tmpa, id_plist, launch_data_array_get_count(tmpa)); | |
} | |
closedir(d); | |
launch_data_dict_insert(msg, tmpa, "SubmitJobs"); | |
} | |
resp = launch_msg(msg); | |
if (resp) { | |
if (LAUNCH_DATA_STRING == launch_data_get_type(resp)) { | |
if (strcmp("Success", launch_data_get_string(resp))) | |
fprintf(stderr, "%s\n", launch_data_get_string(resp)); | |
} | |
launch_data_free(resp); | |
} else { | |
fprintf(stderr, "launch_msg(): %s\n", strerror(errno)); | |
} | |
} | |
static launch_data_t ccfile = NULL; | |
static void distill_config_file(launch_data_t id_plist) | |
{ | |
launch_data_t tmp, oldargs, newargs, tmps; | |
size_t i; | |
ccfile = id_plist; | |
if ((tmp = launch_data_dict_lookup(id_plist, "UserName"))) { | |
struct passwd *pwe = getpwnam(launch_data_get_string(tmp)); | |
launch_data_dict_remove(id_plist, "UserName"); | |
if (pwe) { | |
launch_data_t ntmp = launch_data_alloc(LAUNCH_DATA_INTEGER); | |
launch_data_set_integer(ntmp, pwe->pw_uid); | |
launch_data_dict_insert(id_plist, ntmp, "UID"); | |
} | |
} | |
if ((tmp = launch_data_dict_lookup(id_plist, "GroupName"))) { | |
struct group *gre = getgrnam(launch_data_get_string(tmp)); | |
launch_data_dict_remove(id_plist, "GroupName"); | |
if (gre) { | |
launch_data_t ntmp = launch_data_alloc(LAUNCH_DATA_INTEGER); | |
launch_data_set_integer(ntmp, gre->gr_gid); | |
launch_data_dict_insert(id_plist, ntmp, "GID"); | |
} | |
} | |
if ((tmp = launch_data_dict_lookup(id_plist, "Sockets"))) { | |
launch_data_t ntmp = launch_data_alloc(LAUNCH_DATA_DICTIONARY); | |
launch_data_dict_iterate(tmp, sock_dict_cb, ntmp); | |
launch_data_dict_insert(id_plist, ntmp, "EventSources"); | |
launch_data_dict_remove(id_plist, "Sockets"); | |
} | |
if ((tmp = launch_data_dict_lookup(id_plist, "inetdCompatWait"))) { | |
oldargs = launch_data_dict_lookup(id_plist, "ProgramArguments"); | |
newargs = launch_data_alloc(LAUNCH_DATA_ARRAY); | |
tmps = launch_data_alloc(LAUNCH_DATA_STRING); | |
launch_data_set_string(tmps, "/usr/libexec/launchproxy"); | |
launch_data_array_set_index(newargs, tmps, launch_data_array_get_count(newargs)); | |
tmps = launch_data_alloc(LAUNCH_DATA_STRING); | |
launch_data_set_string(tmps, launch_data_get_bool(tmp) ? "--inetd_mt" : "--inetd_st"); | |
launch_data_array_set_index(newargs, tmps, launch_data_array_get_count(newargs)); | |
if ((tmp = launch_data_dict_lookup(id_plist, "Program"))) { | |
tmps = launch_data_alloc(LAUNCH_DATA_STRING); | |
launch_data_set_string(tmps, "--program"); | |
launch_data_array_set_index(newargs, tmps, launch_data_array_get_count(newargs)); | |
tmps = launch_data_alloc(LAUNCH_DATA_STRING); | |
launch_data_set_string(tmps, launch_data_get_string(tmp)); | |
launch_data_array_set_index(newargs, tmps, launch_data_array_get_count(newargs)); | |
} | |
tmps = launch_data_alloc(LAUNCH_DATA_STRING); | |
launch_data_set_string(tmps, "--"); | |
launch_data_array_set_index(newargs, tmps, launch_data_array_get_count(newargs)); | |
for (i = 0; i < launch_data_array_get_count(oldargs); i++) { | |
tmps = launch_data_alloc(LAUNCH_DATA_STRING); | |
launch_data_set_string(tmps, launch_data_get_string(launch_data_array_get_index(oldargs, i))); | |
launch_data_array_set_index(newargs, tmps, launch_data_array_get_count(newargs)); | |
} | |
launch_data_dict_insert(id_plist, newargs, "ProgramArguments"); | |
} | |
} | |
static void sock_dict_cb(launch_data_t what, const char *key, void *context) | |
{ | |
launch_data_t where = context; | |
launch_data_t evarray = launch_data_alloc(LAUNCH_DATA_ARRAY); | |
launch_data_t tmp, val; | |
size_t i; | |
for (i = 0; i < launch_data_array_get_count(what); i++) { | |
int sfd, st = SOCK_STREAM; | |
bool passive = true; | |
tmp = launch_data_array_get_index(what, i); | |
if ((val = launch_data_dict_lookup(tmp, "SockType"))) { | |
if (!strcmp(launch_data_get_string(val), "SOCK_STREAM")) { | |
st = SOCK_STREAM; | |
} else if (!strcmp(launch_data_get_string(val), "SOCK_DGRAM")) { | |
st = SOCK_DGRAM; | |
} else if (!strcmp(launch_data_get_string(val), "SOCK_SEQPACKET")) { | |
st = SOCK_SEQPACKET; | |
} | |
} | |
if ((val = launch_data_dict_lookup(tmp, "SockPassive"))) | |
passive = launch_data_get_bool(val); | |
if ((val = launch_data_dict_lookup(tmp, "SecureSocketWithKey"))) { | |
launch_data_t t, a; | |
char secdir[sizeof(LAUNCH_SECDIR)], buf[1024]; | |
strcpy(secdir, LAUNCH_SECDIR); | |
mkdtemp(secdir); | |
sprintf(buf, "%s/%s", secdir, key); | |
if (!(t = launch_data_dict_lookup(ccfile, "UserEnvironmentVariables"))) { | |
t = launch_data_alloc(LAUNCH_DATA_DICTIONARY); | |
launch_data_dict_insert(ccfile, t, "UserEnvironmentVariables"); | |
} | |
a = launch_data_alloc(LAUNCH_DATA_STRING); | |
launch_data_set_string(a, buf); | |
launch_data_dict_insert(tmp, a, "SockPathName"); | |
a = launch_data_alloc(LAUNCH_DATA_STRING); | |
launch_data_set_string(a, buf); | |
launch_data_dict_insert(t, a, launch_data_get_string(val)); | |
} | |
if ((val = launch_data_dict_lookup(tmp, "SockPathName"))) { | |
struct sockaddr_un sun; | |
memset(&sun, 0, sizeof(sun)); | |
sun.sun_family = AF_UNIX; | |
strncpy(sun.sun_path, launch_data_get_string(val), sizeof(sun.sun_path)); | |
if ((sfd = socket(AF_UNIX, st, 0)) == -1) | |
continue; | |
if (passive) { | |
if (unlink(sun.sun_path) == -1 && errno != ENOENT) { | |
close(sfd); | |
continue; | |
} | |
if (bind(sfd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { | |
close(sfd); | |
continue; | |
} | |
if ((st == SOCK_STREAM || st == SOCK_SEQPACKET) | |
&& listen(sfd, SOMAXCONN) == -1) { | |
close(sfd); | |
continue; | |
} | |
} else if (connect(sfd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { | |
close(sfd); | |
continue; | |
} | |
val = launch_data_alloc(LAUNCH_DATA_FD); | |
launch_data_set_fd(val, sfd); | |
launch_data_array_set_index(evarray, val, launch_data_array_get_count(evarray)); | |
} else { | |
const char *node = NULL, *serv = NULL; | |
char servnbuf[50]; | |
struct addrinfo hints, *res0, *res; | |
int gerr, sock_opt = 1; | |
memset(&hints, 0, sizeof(hints)); | |
hints.ai_socktype = st; | |
if (passive) | |
hints.ai_flags |= AI_PASSIVE; | |
if ((val = launch_data_dict_lookup(tmp, "SockNodeName"))) | |
node = launch_data_get_string(val); | |
if ((val = launch_data_dict_lookup(tmp, "SockServiceName"))) { | |
if (LAUNCH_DATA_INTEGER == launch_data_get_type(val)) { | |
sprintf(servnbuf, "%lld", launch_data_get_integer(val)); | |
serv = servnbuf; | |
} else { | |
serv = launch_data_get_string(val); | |
} | |
} | |
if ((val = launch_data_dict_lookup(tmp, "SockFamily"))) { | |
if (!strcmp("AF_INET", launch_data_get_string(val))) | |
hints.ai_family = AF_INET; | |
else if (!strcmp("AF_INET6", launch_data_get_string(val))) | |
hints.ai_family = AF_INET6; | |
} | |
if ((val = launch_data_dict_lookup(tmp, "SockProtocol"))) { | |
if (!strcmp("IPPROTO_TCP", launch_data_get_string(val))) | |
hints.ai_protocol = IPPROTO_TCP; | |
} | |
if ((gerr = getaddrinfo(node, serv, &hints, &res0)) != 0) { | |
fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(gerr)); | |
continue; | |
} | |
for (res = res0; res; res = res->ai_next) { | |
if ((sfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) { | |
fprintf(stderr, "socket(): %s\n", strerror(errno)); | |
continue; | |
} | |
if (hints.ai_flags & AI_PASSIVE) { | |
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&sock_opt, sizeof(sock_opt)) == -1) { | |
fprintf(stderr, "socket(): %s\n", strerror(errno)); | |
continue; | |
} | |
if (bind(sfd, res->ai_addr, res->ai_addrlen) == -1) { | |
fprintf(stderr, "bind(): %s\n", strerror(errno)); | |
continue; | |
} | |
if ((res->ai_socktype == SOCK_STREAM || res->ai_socktype == SOCK_SEQPACKET) | |
&& listen(sfd, SOMAXCONN) == -1) { | |
fprintf(stderr, "listen(): %s\n", strerror(errno)); | |
continue; | |
} | |
} else { | |
if (connect(sfd, res->ai_addr, res->ai_addrlen) == -1) { | |
fprintf(stderr, "connect(): %s\n", strerror(errno)); | |
continue; | |
} | |
} | |
val = launch_data_alloc(LAUNCH_DATA_FD); | |
launch_data_set_fd(val, sfd); | |
launch_data_array_set_index(evarray, val, launch_data_array_get_count(evarray)); | |
} | |
} | |
} | |
launch_data_dict_insert(where, evarray, key); | |
} | |
static CFPropertyListRef CreateMyPropertyListFromFile(const char *posixfile) | |
{ | |
CFPropertyListRef propertyList; | |
CFStringRef errorString; | |
CFDataRef resourceData; | |
SInt32 errorCode; | |
CFURLRef fileURL; | |
fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, posixfile, strlen(posixfile), false); | |
if (!fileURL) | |
fprintf(stderr, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", argv0, posixfile); | |
if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, fileURL, &resourceData, NULL, NULL, &errorCode)) | |
fprintf(stderr, "%s: CFURLCreateDataAndPropertiesFromResource(%s) failed: %d\n", argv0, posixfile, (int)errorCode); | |
propertyList = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resourceData, kCFPropertyListImmutable, &errorString); | |
if (!propertyList) | |
fprintf(stderr, "%s: propertyList is NULL\n", argv0); | |
return propertyList; | |
} | |
void myCFDictionaryApplyFunction(const void *key, const void *value, void *context) | |
{ | |
launch_data_t ik, iw, where = context; | |
ik = CF2launch_data(key); | |
iw = CF2launch_data(value); | |
launch_data_dict_insert(where, iw, launch_data_get_string(ik)); | |
launch_data_free(ik); | |
} | |
static launch_data_t CF2launch_data(CFTypeRef cfr) | |
{ | |
launch_data_t r; | |
CFTypeID cft = CFGetTypeID(cfr); | |
if (cft == CFStringGetTypeID()) { | |
char buf[4096]; | |
CFStringGetCString(cfr, buf, sizeof(buf), kCFStringEncodingUTF8); | |
r = launch_data_alloc(LAUNCH_DATA_STRING); | |
launch_data_set_string(r, buf); | |
} else if (cft == CFBooleanGetTypeID()) { | |
r = launch_data_alloc(LAUNCH_DATA_BOOL); | |
launch_data_set_bool(r, CFBooleanGetValue(cfr)); | |
} else if (cft == CFArrayGetTypeID()) { | |
CFIndex i, ac = CFArrayGetCount(cfr); | |
r = launch_data_alloc(LAUNCH_DATA_ARRAY); | |
for (i = 0; i < ac; i++) { | |
CFTypeRef v = CFArrayGetValueAtIndex(cfr, i); | |
if (v) { | |
launch_data_t iv = CF2launch_data(v); | |
launch_data_array_set_index(r, iv, i); | |
} | |
} | |
} else if (cft == CFDictionaryGetTypeID()) { | |
r = launch_data_alloc(LAUNCH_DATA_DICTIONARY); | |
CFDictionaryApplyFunction(cfr, myCFDictionaryApplyFunction, r); | |
} else if (cft == CFDataGetTypeID()) { | |
r = launch_data_alloc(LAUNCH_DATA_ARRAY); | |
launch_data_set_opaque(r, CFDataGetBytePtr(cfr), CFDataGetLength(cfr)); | |
} else if (cft == CFNumberGetTypeID()) { | |
long long n; | |
double d; | |
CFNumberType cfnt = CFNumberGetType(cfr); | |
switch (cfnt) { | |
case kCFNumberSInt8Type: | |
case kCFNumberSInt16Type: | |
case kCFNumberSInt32Type: | |
case kCFNumberSInt64Type: | |
case kCFNumberCharType: | |
case kCFNumberShortType: | |
case kCFNumberIntType: | |
case kCFNumberLongType: | |
case kCFNumberLongLongType: | |
CFNumberGetValue(cfr, kCFNumberLongLongType, &n); | |
r = launch_data_alloc(LAUNCH_DATA_INTEGER); | |
launch_data_set_integer(r, n); | |
break; | |
case kCFNumberFloat32Type: | |
case kCFNumberFloat64Type: | |
case kCFNumberFloatType: | |
case kCFNumberDoubleType: | |
CFNumberGetValue(cfr, kCFNumberDoubleType, &d); | |
r = launch_data_alloc(LAUNCH_DATA_REAL); | |
launch_data_set_real(r, d); | |
break; | |
default: | |
r = NULL; | |
break; | |
} | |
} else { | |
r = NULL; | |
} | |
return r; | |
} | |
static void usage(FILE *where) | |
{ | |
if (where == stdout) | |
exit(EXIT_SUCCESS); | |
else | |
exit(EXIT_FAILURE); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment