Created
November 8, 2014 14:11
-
-
Save maxlapshin/910e860665ad40144729 to your computer and use it in GitHub Desktop.
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 <stdint.h> | |
#include "erl_nif.h" | |
#include <string.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#ifdef __APPLE__ | |
#include <CoreFoundation/CoreFoundation.h> | |
#include <Carbon/Carbon.h> // Oh noes! See discussion blow at GetCurrentProcess | |
#include <crt_externs.h> | |
#endif | |
#ifdef __linux__ | |
#include <sys/prctl.h> | |
#endif | |
static int | |
load(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info) | |
{ | |
return 0; | |
} | |
static int | |
reload(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info) | |
{ | |
return 0; | |
} | |
static int | |
upgrade(ErlNifEnv* env, void** priv, void** old_priv, | |
ERL_NIF_TERM load_info) | |
{ | |
return 0; | |
} | |
static void | |
unload(ErlNifEnv* env, void* priv) | |
{ | |
return; | |
} | |
static ERL_NIF_TERM | |
os3_nif_loaded(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) | |
{ | |
return enif_make_atom(env, "true"); | |
} | |
static ERL_NIF_TERM | |
os3_setprogname(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) | |
{ | |
ErlNifBinary set_name; | |
if(!enif_inspect_binary(env, argv[0], &set_name)) return enif_make_badarg(env); | |
char title[set_name.size+1]; | |
title[set_name.size] = 0; | |
strncpy(title, (const char *)set_name.data, set_name.size); | |
#ifdef __APPLE__ | |
static int symbol_lookup_status = 0; // 1=ok, 2=unavailable | |
if (symbol_lookup_status == 2) { | |
// feature is unavailable | |
return enif_make_atom(env, "undefined"); | |
} | |
// Warning: here be dragons! This is SPI reverse-engineered from WebKit's | |
// plugin host, and could break at any time (although realistically it's only | |
// likely to break in a new major release). | |
// When 10.7 is available, check that this still works, and update this | |
// comment for 10.8. | |
// Private CFType used in these LaunchServices calls. | |
typedef CFTypeRef PrivateLSASN; | |
typedef PrivateLSASN (*LSGetCurrentApplicationASNType)(); | |
typedef OSStatus (*LSSetApplicationInformationItemType)(int, PrivateLSASN, | |
CFStringRef, | |
CFStringRef, | |
CFDictionaryRef*); | |
static LSGetCurrentApplicationASNType ls_get_current_application_asn_func = | |
NULL; | |
static LSSetApplicationInformationItemType | |
ls_set_application_information_item_func = NULL; | |
static CFStringRef ls_display_name_key = NULL; | |
if (!symbol_lookup_status) { | |
CFBundleRef launch_services_bundle = | |
CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices")); | |
if (!launch_services_bundle) { | |
symbol_lookup_status = 2; | |
return enif_make_atom(env, "undefined"); | |
} | |
ls_get_current_application_asn_func = | |
reinterpret_cast<LSGetCurrentApplicationASNType>( | |
CFBundleGetFunctionPointerForName( | |
launch_services_bundle, CFSTR("_LSGetCurrentApplicationASN"))); | |
if (!ls_get_current_application_asn_func) { | |
symbol_lookup_status = 2; | |
return enif_make_atom(env, "undefined"); | |
} | |
ls_set_application_information_item_func = | |
reinterpret_cast<LSSetApplicationInformationItemType>( | |
CFBundleGetFunctionPointerForName( | |
launch_services_bundle, | |
CFSTR("_LSSetApplicationInformationItem"))); | |
if (!ls_set_application_information_item_func) { | |
symbol_lookup_status = 2; | |
return enif_make_atom(env, "undefined"); | |
} | |
const CFStringRef* key_pointer = reinterpret_cast<const CFStringRef*>( | |
CFBundleGetDataPointerForName(launch_services_bundle, | |
CFSTR("_kLSDisplayNameKey"))); | |
ls_display_name_key = key_pointer ? *key_pointer : NULL; | |
if (!ls_display_name_key) { | |
symbol_lookup_status = 2; | |
return enif_make_atom(env, "undefined"); | |
} | |
// Internally, this call relies on the Mach ports that are started up by the | |
// Carbon Process Manager. In debug builds this usually happens due to how | |
// the logging layers are started up; but in release, it isn't started in as | |
// much of a defined order. So if the symbols had to be loaded, go ahead | |
// and force a call to make sure the manager has been initialized and hence | |
// the ports are opened. | |
ProcessSerialNumber psn; | |
GetCurrentProcess(&psn); | |
symbol_lookup_status = 1; // 1=ok | |
} | |
PrivateLSASN asn = ls_get_current_application_asn_func(); | |
// Constant used by WebKit; what exactly it means is unknown. | |
const int magic_session_constant = -2; | |
CFStringRef process_name = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8); | |
ls_set_application_information_item_func(magic_session_constant, asn, | |
ls_display_name_key, | |
process_name, | |
NULL /* optional out param */); | |
setprogname(title); | |
// #if defined(__darwin__) | |
// char **new_argv = (char**)malloc(8*4 + strlen(title) + 10); | |
// new_argv[0] = ((void*)new_argv+16); | |
// strcpy(new_argv[0], title); | |
// new_argv[1] = 0; | |
// *_NSGetArgv() = new_argv; | |
char **new_argv = *_NSGetArgv(); | |
int len = strlen(new_argv[0]); | |
len = set_name.size > len ? len : set_name.size; | |
memset(new_argv[0], 0, len); | |
strncpy(new_argv[0], title, len); | |
*_NSGetArgc() = 1; | |
const char *out_name = getprogname(); | |
len = strlen(out_name); | |
ErlNifBinary out_bin; | |
enif_alloc_binary(len, &out_bin); | |
memcpy((char *)out_bin.data, out_name, out_bin.size); | |
return enif_make_binary(env, &out_bin); | |
#endif | |
#ifdef __linux__ | |
prctl(PR_SET_NAME, title); | |
return enif_make_binary(env, &set_name); | |
#endif | |
return enif_make_atom(env, "undefined"); | |
} | |
static ErlNifFunc os3_funcs[] = | |
{ | |
{"nif_loaded", 0, os3_nif_loaded}, | |
{"setprogname0", 1, os3_setprogname} | |
}; | |
ERL_NIF_INIT(os3, os3_funcs, load, reload, upgrade, unload) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment