update_prebinding.cxx [plain text]
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <vector>
#ifndef KERN_OTHERARCHHANDLER
#define KERN_OTHERARCHHANDLER 45
#endif
static void parsePathsFile(const char* preboundDylibsPathsFile, std::vector<const char*>& paths)
{
int fd = open(preboundDylibsPathsFile, O_RDONLY, 0);
if ( fd == -1 ) {
fprintf(stderr, "update_prebinding:can't open file: %s", preboundDylibsPathsFile);
exit(1);
}
struct stat stat_buf;
fstat(fd, &stat_buf);
char* p = (char*)malloc(stat_buf.st_size);
if ( p == NULL ) {
fprintf(stderr, "update_prebinding:malloc failure");
exit(1);
}
if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size ) {
fprintf(stderr, "update_prebinding: can't read file: %s", preboundDylibsPathsFile);
exit(1);
}
::close(fd);
char * const end = &p[stat_buf.st_size];
enum { lineStart, inSymbol, inComment } state = lineStart;
char* symbolStart = NULL;
for (char* s = p; s < end; ++s ) {
switch ( state ) {
case lineStart:
if ( *s =='#' ) {
state = inComment;
}
else if ( !isspace(*s) ) {
state = inSymbol;
symbolStart = s;
}
break;
case inSymbol:
if ( *s == '\n' ) {
*s = '\0';
char* last = s-1;
while ( isspace(*last) ) {
*last = '\0';
--last;
}
paths.push_back(symbolStart);
symbolStart = NULL;
state = lineStart;
}
break;
case inComment:
if ( *s == '\n' )
state = lineStart;
break;
}
}
}
static void parseCommandLineOptions(int argc, const char* argv[], char flags[])
{
int flagsLen = strlen(flags);
for(int i=1; i < argc; ++i) {
const char* arg = argv[i];
if ( arg[0] == '-' ) {
if ( (strcmp(arg, "-root") == 0) || (strcmp(&arg[1], "-root") == 0) ) {
const char* rootPath = argv[++i];
if ( (rootPath == NULL) || (rootPath[0] != '/') ) {
fprintf(stderr, "update_prebinding: -root requires an absolute path to follow\n");
exit(1);
}
setenv("DYLD_ROOT_PATH", rootPath, 1);
}
else if ( (strcmp(arg, "-force") == 0) || (strcmp(&arg[1], "-force") == 0) ) {
setenv("DYLD_IGNORE_PREBINDING", "all", 1);
}
else if ( (strcmp(arg, "-debug") == 0) || (strcmp(&arg[1], "-debug") == 0) ) {
setenv("DYLD_PREBIND_DEBUG", "1", 1);
}
else if ( (strcmp(arg, "-progress") == 0) || (strcmp(&arg[1], "-progress") == 0) ) {
flags[flagsLen-2] = '1'; }
else if ( (strcmp(arg, "-dry-run") == 0) || (strcmp(&arg[1], "-dry-run") == 0) ) {
flags[flagsLen-1] = '1'; }
else {
fprintf(stderr, "update_prebinding: warning: unknown option %s\n", arg);
}
}
else {
fprintf(stderr, "update_prebinding: warning: unknown argument %s\n", arg);
}
}
}
static int run(const char* path, const std::vector<const char*>& args, bool affinity=false)
{
const char* argv[args.size()+2];
argv[0] = path;
int i=1;
for(std::vector<const char*>::const_iterator it=args.begin(); it != args.end(); ++it) {
argv[i++] = *it;
}
argv[i] = NULL;
pid_t pid = fork();
switch(pid) {
case -1: return -1;
case 0: if ( affinity ) {
#if __i386__
int mib[] = { CTL_KERN, KERN_AFFINITY, 1, 1 };
int namelen = 4;
sysctl(mib, namelen, NULL, NULL, NULL, 0);
#endif
}
execv(path, (char**)argv);
_exit(127);
default: int childStatus;
if (waitpid (pid, &childStatus, 0) != pid)
return -1;
return childStatus;
}
}
#if __i386__
static bool getRosettaPath(char* path)
{
int mib[2] = {CTL_KERN, KERN_OTHERARCHHANDLER};
size_t len = PATH_MAX;
return ( sysctl(mib, 2, (void*)path, &len, 0, 0) == 0 );
}
#endif
int main(int argc, const char* argv[])
{
char flags[] = "00000000000000000000000000000000";
parseCommandLineOptions(argc, argv, flags);
std::vector<const char*> coreArgs;
coreArgs.reserve(1000);
parsePathsFile("/var/db/dyld/update-prebinding-paths.txt", coreArgs);
coreArgs.push_back(flags);
int result = run("/usr/bin/update_prebinding_core", coreArgs);
if ( result != 0 )
fprintf(stderr, "update_prebinding: error %d running update_prebinding_core\n", result);
#if __i386__
std::vector<const char*> rosettaArgs;
rosettaArgs.push_back("-prebindOAH");
char rosettaPath[PATH_MAX];
if ( getRosettaPath(rosettaPath) ) {
result = run(rosettaPath, rosettaArgs, false);
if ( result != 0 )
fprintf(stderr, "update_prebinding: error %d running %s -prebindOAH\n", result, rosettaPath);
}
else {
fprintf(stderr, "update_prebinding: error could not locate Rosetta\n");
}
result = run("/usr/bin/update_prebinding_core", coreArgs, true);
if ( result != 0 )
fprintf(stderr, "update_prebinding: error %d running update_prebinding_core\n", result);
#endif
unsetenv("DYLD_ROOT_PATH");
unsetenv("DYLD_PREBIND_DEBUG");
std::vector<const char*> rmArgs;
rmArgs.push_back("-c");
rmArgs.push_back("/bin/rm -f /var/vm/app_profile/*{_names,_data}");
run("/bin/sh", rmArgs);
return result;
}