Skip to content

Instantly share code, notes, and snippets.

@maxlapshin
Created November 8, 2014 14:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maxlapshin/910e860665ad40144729 to your computer and use it in GitHub Desktop.
Save maxlapshin/910e860665ad40144729 to your computer and use it in GitHub Desktop.
#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