| 1 | /* Copyright (C) 2009 Peter Speck |
|---|
| 2 | * |
|---|
| 3 | * This program is free software: you can redistribute it and/or modify |
|---|
| 4 | * it under the terms of the GNU General Public License as published by |
|---|
| 5 | * the Free Software Foundation, either version 3 of the License, or |
|---|
| 6 | * (at your option) any later version. |
|---|
| 7 | * |
|---|
| 8 | * This program is distributed in the hope that it will be useful, |
|---|
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 11 | * GNU General Public License for more details. |
|---|
| 12 | * |
|---|
| 13 | * You should have received a copy of the GNU General Public License |
|---|
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
|---|
| 15 | */ |
|---|
| 16 | |
|---|
| 17 | #include <CoreFoundation/CoreFoundation.h> |
|---|
| 18 | #include <JavaVM/jni.h> |
|---|
| 19 | #include <mach-o/arch.h> |
|---|
| 20 | #include <spawn.h> |
|---|
| 21 | #include <sys/resource.h> |
|---|
| 22 | #include <sys/stat.h> |
|---|
| 23 | #include <sys/sysctl.h> |
|---|
| 24 | #include <unistd.h> |
|---|
| 25 | |
|---|
| 26 | static int debugFlag = 0; |
|---|
| 27 | static int hasUsrLibexecJavaHome = 0; |
|---|
| 28 | |
|---|
| 29 | static int hasVM(const char *jvmVersion) |
|---|
| 30 | { |
|---|
| 31 | if (debugFlag) |
|---|
| 32 | fprintf(stderr, "hasVM(%s) runs.\n", jvmVersion); |
|---|
| 33 | // Look for the JavaVM bundle using its identifier |
|---|
| 34 | CFBundleRef vmBundleR = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.JavaVM")); |
|---|
| 35 | if (!vmBundleR) { |
|---|
| 36 | if (debugFlag) |
|---|
| 37 | fprintf(stderr, "hasVM(%s): Missing com.apple.JavaVM bundle.\n", jvmVersion); |
|---|
| 38 | return 0; |
|---|
| 39 | } |
|---|
| 40 | CFURLRef frameworkUrl = CFBundleCopyBundleURL(vmBundleR); |
|---|
| 41 | // -> /System/Library/Frameworks/JavaVM.framework |
|---|
| 42 | if (!frameworkUrl) { |
|---|
| 43 | if (debugFlag) |
|---|
| 44 | fprintf(stderr, "hasVM(%s): Can't create frameworkUrl.\n", jvmVersion); |
|---|
| 45 | return 0; |
|---|
| 46 | } |
|---|
| 47 | CFURLRef versionDirUrl = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, frameworkUrl, CFSTR("Versions"), true); |
|---|
| 48 | // -> /System/Library/Frameworks/JavaVM.framework/Versions |
|---|
| 49 | CFRelease(frameworkUrl); |
|---|
| 50 | if (!versionDirUrl) { |
|---|
| 51 | if (debugFlag) |
|---|
| 52 | fprintf(stderr, "hasVM(%s): Can't create versionDirUrl.\n", jvmVersion); |
|---|
| 53 | return 0; |
|---|
| 54 | } |
|---|
| 55 | CFStringRef vers = CFStringCreateWithCString(kCFAllocatorDefault, jvmVersion, kCFStringEncodingUTF8); |
|---|
| 56 | CFURLRef targetUrl = vers ? CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, versionDirUrl, vers, true) : NULL; |
|---|
| 57 | // -> /System/Library/Frameworks/JavaVM.framework/Versions/1.6 |
|---|
| 58 | if (vers) |
|---|
| 59 | CFRelease(vers); |
|---|
| 60 | CFRelease(versionDirUrl); |
|---|
| 61 | if (!targetUrl) { |
|---|
| 62 | if (debugFlag) |
|---|
| 63 | fprintf(stderr, "hasVM(%s): Can't create targetUrl.\n", jvmVersion); |
|---|
| 64 | return 0; |
|---|
| 65 | } |
|---|
| 66 | char path[PATH_MAX] = "\0"; |
|---|
| 67 | if (!CFURLGetFileSystemRepresentation(targetUrl, true, (UInt8*)path, sizeof(path))) { |
|---|
| 68 | if (debugFlag) |
|---|
| 69 | fprintf(stderr, "hasVM(%s): Can't convert targetUrl to file system representation.\n", jvmVersion); |
|---|
| 70 | CFRelease(targetUrl); |
|---|
| 71 | return 0; |
|---|
| 72 | } |
|---|
| 73 | CFRelease(targetUrl); |
|---|
| 74 | struct stat statbuf; |
|---|
| 75 | if (stat(path, &statbuf)) { |
|---|
| 76 | if (debugFlag) |
|---|
| 77 | fprintf(stderr, "hasVM(%s): Missing JavaVM directory: '%s'\n", jvmVersion, path); |
|---|
| 78 | return 0; |
|---|
| 79 | } |
|---|
| 80 | if (debugFlag) |
|---|
| 81 | fprintf(stderr, "hasVM(%s): Success.\n", jvmVersion); |
|---|
| 82 | return 1; |
|---|
| 83 | } |
|---|
| 84 | |
|---|
| 85 | #define JARDIR "/Library/PreferencePanes/GlimmerBlocker.prefPane/Contents/GlimmerBlockerProxy.app/Contents/Resources/Java" |
|---|
| 86 | #define CLASSPATH JARDIR "/glimmerblocker-server.jar" \ |
|---|
| 87 | /**/ ":" JARDIR "/annotations.jar" \ |
|---|
| 88 | /**/ ":" JARDIR "/dnsjava.jar" \ |
|---|
| 89 | /**/ ":" JARDIR "/smalljs.jar" |
|---|
| 90 | |
|---|
| 91 | static JavaVMOption javaOptions[25]; |
|---|
| 92 | |
|---|
| 93 | static void addJavaOption(const char* s) |
|---|
| 94 | { |
|---|
| 95 | JavaVMOption* jvo = javaOptions; |
|---|
| 96 | while (jvo->optionString) |
|---|
| 97 | jvo++; |
|---|
| 98 | jvo->optionString = (char*)s; |
|---|
| 99 | jvo->extraInfo = NULL; |
|---|
| 100 | jvo++; |
|---|
| 101 | jvo->optionString = NULL; |
|---|
| 102 | jvo->extraInfo = NULL; |
|---|
| 103 | } |
|---|
| 104 | |
|---|
| 105 | static int startVM(const char *jvmVersion, int tryLibExecTool) |
|---|
| 106 | { |
|---|
| 107 | if (!hasUsrLibexecJavaHome && strcmp(jvmVersion, "*") && !hasVM(jvmVersion)) |
|---|
| 108 | return 0; |
|---|
| 109 | if (debugFlag) |
|---|
| 110 | fprintf(stderr, "Tries starting java version %s\n", jvmVersion); |
|---|
| 111 | javaOptions[0].optionString = NULL; |
|---|
| 112 | addJavaOption("-Xms25m"); |
|---|
| 113 | addJavaOption("-Xmx50m"); |
|---|
| 114 | if (strcmp(jvmVersion, "1.5")) |
|---|
| 115 | addJavaOption("-XX:+UseCompressedOops"); // seems to make java 1.5 to fail launch on PPC 10.5 |
|---|
| 116 | addJavaOption("-Djava.awt.headless=true"); |
|---|
| 117 | addJavaOption("-Dfile.encoding=UTF-8"); |
|---|
| 118 | struct stat statbuf; |
|---|
| 119 | if (getenv("GB_JAVA_DEBUGGER") || !stat("/Library/GlimmerBlocker/enable-java-debugging.txt", &statbuf)) { |
|---|
| 120 | fprintf(stderr, "Enables java debugging. Pid = %d\n", getpid()); |
|---|
| 121 | addJavaOption("-Xint"); |
|---|
| 122 | addJavaOption("-Xdebug"); |
|---|
| 123 | addJavaOption("-Xshare:off"); |
|---|
| 124 | addJavaOption("-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"); |
|---|
| 125 | } |
|---|
| 126 | if (!stat("/Library/GlimmerBlocker/enable-jmxremote.txt", &statbuf)) { |
|---|
| 127 | fprintf(stderr, "Enables jmxremote for e.g. jvisualvm. Pid = %d\n", getpid()); |
|---|
| 128 | fprintf(stderr, " use 'Add JMXConnection' to 127.0.0.1:9494\n"); |
|---|
| 129 | addJavaOption("-Dcom.sun.management.jmxremote.port=9494"); |
|---|
| 130 | addJavaOption("-Dcom.sun.management.jmxremote.ssl=false"); |
|---|
| 131 | addJavaOption("-Dcom.sun.management.jmxremote.authenticate=false"); |
|---|
| 132 | } |
|---|
| 133 | addJavaOption("-Djava.class.path=" CLASSPATH); |
|---|
| 134 | if (!stat("/Library/GlimmerBlocker/preferIPv4Stack.txt", &statbuf)) { |
|---|
| 135 | addJavaOption("-Djava.net.preferIPv4Stack=1"); |
|---|
| 136 | fprintf(stderr, "Launches GB using java.net.preferIPv4Stack\n"); |
|---|
| 137 | } |
|---|
| 138 | if (debugFlag) { |
|---|
| 139 | fprintf(stderr, "Java VM options:\n"); |
|---|
| 140 | JavaVMOption* jvo = javaOptions; |
|---|
| 141 | while (jvo->optionString) { |
|---|
| 142 | fprintf(stderr, " %s\n", jvo->optionString); |
|---|
| 143 | jvo++; |
|---|
| 144 | } |
|---|
| 145 | } |
|---|
| 146 | if (hasUsrLibexecJavaHome && tryLibExecTool) { |
|---|
| 147 | // The bad thing about using /usr/libexec/java_home -exec java |
|---|
| 148 | // is that the process is called "java" in Activity Monitor |
|---|
| 149 | // and by the firewall. |
|---|
| 150 | long len = 500; |
|---|
| 151 | for (JavaVMOption* jvo = javaOptions; jvo->optionString; jvo++) |
|---|
| 152 | len += strlen(jvo->optionString) + 1; |
|---|
| 153 | char* buf = malloc(len); |
|---|
| 154 | if (!buf) { |
|---|
| 155 | fprintf(stderr, "Couldn't malloc %ld bytes.\n", len); |
|---|
| 156 | return 0; |
|---|
| 157 | } |
|---|
| 158 | char* p = buf + sprintf(buf, "/usr/libexec/java_home"); |
|---|
| 159 | if (strcmp(jvmVersion, "*")) |
|---|
| 160 | p += sprintf(p, " -F -v'%s+'", jvmVersion); |
|---|
| 161 | p += sprintf(p, " -exec java"); |
|---|
| 162 | for (JavaVMOption* jvo = javaOptions; jvo->optionString; jvo++) |
|---|
| 163 | p += sprintf(p, " '%s'", jvo->optionString); |
|---|
| 164 | p += sprintf(p, " org.glimmerblocker.proxy.GlimmerBlocker"); |
|---|
| 165 | if (debugFlag) { |
|---|
| 166 | p += sprintf(p, " -stderr"); |
|---|
| 167 | fprintf(stderr, "cmdline (%ld/%ld): %s\n", (long)(p - buf) + 1, len, buf); |
|---|
| 168 | } |
|---|
| 169 | if (system(buf)) { |
|---|
| 170 | fprintf(stderr, "GB proxy java failed to launch.\n"); |
|---|
| 171 | return 0; |
|---|
| 172 | } else { |
|---|
| 173 | fprintf(stderr, "GB proxy java launched ok.\n"); |
|---|
| 174 | exit(0); |
|---|
| 175 | } |
|---|
| 176 | } |
|---|
| 177 | setenv("JAVA_JVM_VERSION", jvmVersion, true); |
|---|
| 178 | JavaVMInitArgs vm_args; |
|---|
| 179 | vm_args.version = JNI_VERSION_1_4; |
|---|
| 180 | vm_args.options = javaOptions; |
|---|
| 181 | vm_args.nOptions = 0; |
|---|
| 182 | for (JavaVMOption* opt = vm_args.options; opt->optionString; opt++, vm_args.nOptions++) |
|---|
| 183 | ; |
|---|
| 184 | vm_args.ignoreUnrecognized = JNI_TRUE; |
|---|
| 185 | // |
|---|
| 186 | #define CHECK_EXCEPTION(MSG) \ |
|---|
| 187 | if ((*env)->ExceptionOccurred(env)) { \ |
|---|
| 188 | fprintf(stderr, "Java %s: Got exception from " MSG ".\n", jvmVersion); \ |
|---|
| 189 | (*env)->ExceptionDescribe(env); \ |
|---|
| 190 | goto done; \ |
|---|
| 191 | } |
|---|
| 192 | JNIEnv *env; |
|---|
| 193 | JavaVM *vm; |
|---|
| 194 | int r = JNI_CreateJavaVM(&vm, (void**)&env, &vm_args); |
|---|
| 195 | if (r) { |
|---|
| 196 | if (debugFlag) |
|---|
| 197 | fprintf(stderr, "Java %s: JNI_CreateJavaVM failed with error code %d\n", jvmVersion, r); |
|---|
| 198 | return 0; |
|---|
| 199 | } |
|---|
| 200 | if (debugFlag) |
|---|
| 201 | fprintf(stderr, "Java %s: Did create JVM using JNI_CreateJavaVM\n", jvmVersion); |
|---|
| 202 | jclass mainClass = (*env)->FindClass(env, "org/glimmerblocker/proxy/GlimmerBlocker"); |
|---|
| 203 | if (!mainClass) { |
|---|
| 204 | fprintf(stderr, "Java %s: Can't load main class.\n", jvmVersion); |
|---|
| 205 | CHECK_EXCEPTION("Loading main class"); |
|---|
| 206 | goto done; |
|---|
| 207 | } |
|---|
| 208 | jmethodID mainID = (*env)->GetStaticMethodID(env, mainClass, "main", "([Ljava/lang/String;)V"); |
|---|
| 209 | if (!mainID) { |
|---|
| 210 | fprintf(stderr, "Java %s: Can't find 'public void main(...)' in main class.\n", jvmVersion); |
|---|
| 211 | CHECK_EXCEPTION("Finding main() method"); |
|---|
| 212 | goto done; |
|---|
| 213 | } |
|---|
| 214 | jobjectArray mainArgs = (*env)->NewObjectArray(env, debugFlag ? 1 : 0, (*env)->FindClass(env, "java/lang/String"), NULL); |
|---|
| 215 | if (mainArgs == nil) { |
|---|
| 216 | fprintf(stderr, "Java %s: Can't create String[] array.\n", jvmVersion); |
|---|
| 217 | CHECK_EXCEPTION("Creating String[] array"); |
|---|
| 218 | goto done; |
|---|
| 219 | } |
|---|
| 220 | if (debugFlag) { |
|---|
| 221 | jstring s = (*env)->NewStringUTF(env, "-stderr"); |
|---|
| 222 | if (!s) { |
|---|
| 223 | fprintf(stderr, "Java %s: Can't create String constant.\n", jvmVersion); |
|---|
| 224 | CHECK_EXCEPTION("Creating String constant"); |
|---|
| 225 | goto done; |
|---|
| 226 | } |
|---|
| 227 | (*env)->SetObjectArrayElement(env, mainArgs, 0, s); |
|---|
| 228 | CHECK_EXCEPTION("Setting -stderr argument"); |
|---|
| 229 | } |
|---|
| 230 | if (debugFlag) |
|---|
| 231 | fprintf(stderr, "Java %s: Calls main()\n", jvmVersion); |
|---|
| 232 | (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs); |
|---|
| 233 | CHECK_EXCEPTION("Executing main method"); |
|---|
| 234 | if (debugFlag) |
|---|
| 235 | fprintf(stderr, "Java %s: main() returned.\n", jvmVersion); |
|---|
| 236 | return 1; // don't destroy successful vm. |
|---|
| 237 | done: |
|---|
| 238 | if (debugFlag) |
|---|
| 239 | fprintf(stderr, "Java %s: DestroyJavaVM.\n", jvmVersion); |
|---|
| 240 | (*vm)->DestroyJavaVM(vm); |
|---|
| 241 | if (debugFlag) |
|---|
| 242 | fprintf(stderr, "Java %s: DestroyJavaVM done.\n", jvmVersion); |
|---|
| 243 | return 0; |
|---|
| 244 | } |
|---|
| 245 | |
|---|
| 246 | static void check(const char* cmd, int rc) |
|---|
| 247 | { |
|---|
| 248 | if (!rc) |
|---|
| 249 | return; |
|---|
| 250 | fprintf(stderr, "GlimmerBlocker PROXY LAUNCHER FAILED (%d = %s): %s\n", rc, strerror(rc), cmd); |
|---|
| 251 | exit(rc); |
|---|
| 252 | } |
|---|
| 253 | |
|---|
| 254 | static void spawn(cpu_type_t cpu) |
|---|
| 255 | { |
|---|
| 256 | posix_spawnattr_t attr; |
|---|
| 257 | check("posix_spawnattr_init", posix_spawnattr_init(&attr)); |
|---|
| 258 | /* do the equivalent of exec, rather than creating a separate process */ |
|---|
| 259 | check("posix_spawnattr_setflags", posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETEXEC)); |
|---|
| 260 | size_t copied; |
|---|
| 261 | check("posix_spawnattr_setbinpref_np", posix_spawnattr_setbinpref_np(&attr, 1, &cpu, &copied)); |
|---|
| 262 | if (copied != 1) |
|---|
| 263 | check("posix_spawnattr_setbinpref_np didn't set cpu type.", -1); |
|---|
| 264 | const char* cmd = "/Library/PreferencePanes/GlimmerBlocker.prefPane/Contents/GlimmerBlockerProxy.app/Contents/MacOS/GlimmerBlocker"; |
|---|
| 265 | const char* argv[] = { cmd, NULL }; |
|---|
| 266 | pid_t pid; |
|---|
| 267 | extern char **environ; |
|---|
| 268 | check("posix_spawn", posix_spawn(&pid, cmd, NULL, &attr, (char**)argv, environ)); |
|---|
| 269 | fprintf(stderr, "posix_spawn returned!!!\n"); |
|---|
| 270 | } |
|---|
| 271 | |
|---|
| 272 | static void* startBestVM() |
|---|
| 273 | { |
|---|
| 274 | if (startVM("1.6", 0)) |
|---|
| 275 | return NULL; |
|---|
| 276 | if (startVM("1.5", 0)) |
|---|
| 277 | return NULL; |
|---|
| 278 | if (startVM("1.6", 1)) |
|---|
| 279 | return NULL; |
|---|
| 280 | if (startVM("1.5", 1)) |
|---|
| 281 | return NULL; |
|---|
| 282 | if (startVM("*", 1)) |
|---|
| 283 | return NULL; |
|---|
| 284 | // |
|---|
| 285 | // Did not find any java which works on this architecture. |
|---|
| 286 | // This happends for PPC on 10.5 in 64-bit mode as it has no java 1.6 and java 1.5 is 32-bit only (on PPC). |
|---|
| 287 | // Only x64 can do 32 and 64 bit java 1.5 in 10.5 |
|---|
| 288 | int mib[CTL_MAXNAME]; |
|---|
| 289 | size_t len = CTL_MAXNAME; |
|---|
| 290 | check("sysctlnametomib", sysctlnametomib("sysctl.proc_cputype", mib, &len)); |
|---|
| 291 | mib[len++] = getpid(); |
|---|
| 292 | cpu_type_t cputype; |
|---|
| 293 | size_t cpusz = sizeof(cputype); |
|---|
| 294 | if (sysctl(mib, (u_int)len, &cputype, &cpusz, NULL, 0)) { |
|---|
| 295 | // prefer sysctlbyname_with_pid because NXGetLocalArchInfo is buggy: |
|---|
| 296 | // Mac OS X 10.5.6, Core 2 Duo, in 64-bit mode, arch->cputype returns 7 == CPU_TYPE_X86 and not CPU_TYPE_X86_64 as expected! |
|---|
| 297 | cputype = NXGetLocalArchInfo()->cputype; // failback if sysctl fails. |
|---|
| 298 | } |
|---|
| 299 | if (debugFlag) |
|---|
| 300 | fprintf(stderr, "startBestVM: 0x%lX, sz = %d\n", (long)cputype, (int)sizeof(void*)); |
|---|
| 301 | if (cputype == CPU_TYPE_POWERPC64) { |
|---|
| 302 | if (debugFlag) |
|---|
| 303 | fprintf(stderr, "Running on ppc64, has no java, tries to relaunch in 32-bit mode.\n"); |
|---|
| 304 | spawn(CPU_TYPE_POWERPC); |
|---|
| 305 | } |
|---|
| 306 | if (cputype == CPU_TYPE_X86_64) { |
|---|
| 307 | if (debugFlag) |
|---|
| 308 | fprintf(stderr, "Running on x86_64, has no java, tries to relaunch in 32-bit mode.\n"); |
|---|
| 309 | spawn(CPU_TYPE_I386); |
|---|
| 310 | } |
|---|
| 311 | fprintf(stderr, "Can't find any usable java version. Tries to exec java as cmd line.\n"); |
|---|
| 312 | //fprintf(stderr, "CLASSPATH: %s\n\n", CLASSPATH); |
|---|
| 313 | // argv[0] needs to be repeated in execlp |
|---|
| 314 | int rc = execlp("java", "java", "-cp", CLASSPATH, "-Xmx100m", "-Djava.awt.headless=true", "-Dfile.encoding=UTF-8", "org.glimmerblocker.proxy.GlimmerBlocker", NULL); |
|---|
| 315 | fprintf(stderr, "exec java returned with error = %d\n", rc); |
|---|
| 316 | exit(rc ? rc : -1); |
|---|
| 317 | } |
|---|
| 318 | |
|---|
| 319 | static void sourceCallBack(void *info) // dummy for CFRunLoop so it doesn't exit. |
|---|
| 320 | { |
|---|
| 321 | } |
|---|
| 322 | |
|---|
| 323 | static int sys(const char *x) |
|---|
| 324 | { |
|---|
| 325 | fprintf(stderr, "Executes: %s\n", x); |
|---|
| 326 | int r = system(x); |
|---|
| 327 | if (r) |
|---|
| 328 | fprintf(stderr, "Got returncode = %d from %s\n", r, x); |
|---|
| 329 | fprintf(stderr, "\n"); |
|---|
| 330 | return r; |
|---|
| 331 | } |
|---|
| 332 | |
|---|
| 333 | int checkCodesign(const char *x) |
|---|
| 334 | { |
|---|
| 335 | fprintf(stderr, "Executes: %s\n", x); |
|---|
| 336 | int r = system(x); |
|---|
| 337 | if (r) { |
|---|
| 338 | fprintf(stderr, "\n"); |
|---|
| 339 | fprintf(stderr, "\n"); |
|---|
| 340 | fprintf(stderr, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); |
|---|
| 341 | fprintf(stderr, "@@@@ Codesign verification failed with returncode = %3d @@@@\n", r); |
|---|
| 342 | fprintf(stderr, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); |
|---|
| 343 | fprintf(stderr, "\n"); |
|---|
| 344 | fprintf(stderr, "\n"); |
|---|
| 345 | } |
|---|
| 346 | fprintf(stderr, "\n"); |
|---|
| 347 | return r; |
|---|
| 348 | } |
|---|
| 349 | |
|---|
| 350 | int main(int argc, const char **argv) |
|---|
| 351 | { |
|---|
| 352 | unsetenv("IFS"); |
|---|
| 353 | setenv("SHELL", "/bin/sh", 1); |
|---|
| 354 | setenv("PATH", "/bin:/usr/bin:/usr/sbin", 1); |
|---|
| 355 | unsetenv("CDPATH"); |
|---|
| 356 | int r = chdir("/tmp"); |
|---|
| 357 | if (r) |
|---|
| 358 | fprintf(stderr, "GlimmerBlockerProxy: failed chdir('/tmp'): %d\n", r); |
|---|
| 359 | int displayedInTextEdit = 0; |
|---|
| 360 | int makeDebugReport = 0; |
|---|
| 361 | for (int i = 1; i < argc; i++) { |
|---|
| 362 | if (!strcmp(argv[i], "--make-report")) |
|---|
| 363 | makeDebugReport = debugFlag = 1; |
|---|
| 364 | else if (!strcmp(argv[i], "--textedit")) |
|---|
| 365 | displayedInTextEdit = 1; |
|---|
| 366 | else if (!strcmp(argv[i], "-d")) |
|---|
| 367 | debugFlag = 1; |
|---|
| 368 | } |
|---|
| 369 | struct rlimit rlp; |
|---|
| 370 | struct rlimit rlpOld; |
|---|
| 371 | getrlimit(RLIMIT_NOFILE, &rlpOld); |
|---|
| 372 | getrlimit(RLIMIT_NOFILE, &rlp); |
|---|
| 373 | if (rlp.rlim_cur < rlp.rlim_max) { |
|---|
| 374 | rlp.rlim_cur = MAX(rlp.rlim_max, 10240); |
|---|
| 375 | setrlimit(RLIMIT_NOFILE, &rlp); |
|---|
| 376 | } |
|---|
| 377 | struct stat statbuf; |
|---|
| 378 | // java_home in 10.6.0 doesn't support the -exec parameter. |
|---|
| 379 | hasUsrLibexecJavaHome = !stat("/usr/libexec/java_home", &statbuf) && (statbuf.st_mode & 0111) |
|---|
| 380 | && !stat("/System/Library/Java/JavaVirtualMachines", &statbuf); |
|---|
| 381 | if (makeDebugReport) { |
|---|
| 382 | if (displayedInTextEdit) { |
|---|
| 383 | fprintf(stderr, "#\n"); |
|---|
| 384 | fprintf(stderr, "#\n"); |
|---|
| 385 | fprintf(stderr, "# Please copy/paste the content of this window into a mail to\n"); |
|---|
| 386 | fprintf(stderr, "# feedback@glimmerblocker.org\n"); |
|---|
| 387 | fprintf(stderr, "#\n"); |
|---|
| 388 | fprintf(stderr, "#\n"); |
|---|
| 389 | } else { |
|---|
| 390 | fprintf(stderr, "GlimmerBlockerProxy: debug log enabled.\n"); |
|---|
| 391 | } |
|---|
| 392 | fprintf(stderr, "rlimit.files: %lld -> %lld, hard = %lld\n", |
|---|
| 393 | (long long)rlpOld.rlim_cur, (long long)rlp.rlim_cur, (long long)rlp.rlim_max); |
|---|
| 394 | fprintf(stderr, "hasUsrLibexecJavaHome = %s\n", hasUsrLibexecJavaHome ? "yes" : "no"); |
|---|
| 395 | sys("printenv"); |
|---|
| 396 | sys("id"); |
|---|
| 397 | sys("ls -l /Library/Logs/GlimmerBlocker"); |
|---|
| 398 | sys("ls -l /Library/GlimmerBlocker"); |
|---|
| 399 | sys("codesign --verify --verbose /Library/PreferencePanes/GlimmerBlocker.prefPane/Contents/GlimmerBlockerProxy.app"); |
|---|
| 400 | sys("dscl . -read /Users/_glimmerblocker"); |
|---|
| 401 | sys("java -version"); |
|---|
| 402 | if (hasUsrLibexecJavaHome) { |
|---|
| 403 | r = sys("/usr/libexec/java_home -v'1.6*' java -version"); |
|---|
| 404 | if (r) |
|---|
| 405 | sys("/usr/libexec/java_home -v'1.5*' java -version"); |
|---|
| 406 | } |
|---|
| 407 | sys("perl -MIO -e 'print \"perl is ok\\n\";'"); // http://www.theregister.co.uk/2009/02/16/apple_update_perl_breakage/ |
|---|
| 408 | sys("system_profiler SPSoftwareDataType | egrep -i 'version|kernel'"); |
|---|
| 409 | sys("system_profiler SPHardwareDataType | perl -ne 'print unless /Serial Number|Hardware UUID/i;' # omits serial + hardwareid."); |
|---|
| 410 | #define PPANE "/Library/PreferencePanes/GlimmerBlocker.prefPane" |
|---|
| 411 | #define UPDATER PPANE "/Contents/GlimmerBlockerUpdater.app" |
|---|
| 412 | #define SPARKLE PPANE "/Contents/GlimmerBlockerUpdater.app/Contents/Frameworks/Sparkle.framework/Versions/A" |
|---|
| 413 | #define SIGNATURE "c9d85c0c3b7a8d1cb8060aa34df69713cfff637c" |
|---|
| 414 | int a = checkCodesign("codesign -vv '-R=identifier org.glimmerblocker.prefsPane and certificate leaf = H\"" SIGNATURE "\"' " PPANE); |
|---|
| 415 | int b = checkCodesign("codesign -vv '-R=identifier org.glimmerblocker.upgradeApp and certificate leaf = H\"" SIGNATURE "\"' " UPDATER); |
|---|
| 416 | int c = checkCodesign("codesign -vv '-R=identifier org.andymatuschak.Sparkle and certificate leaf = H\"" SIGNATURE "\"' " SPARKLE); |
|---|
| 417 | if (a || b || c) { |
|---|
| 418 | sys("codesign -vddd -r- " PPANE); |
|---|
| 419 | sys("codesign -vddd -r- " UPDATER); |
|---|
| 420 | sys("codesign -vddd -r- " SPARKLE); |
|---|
| 421 | } |
|---|
| 422 | if (c) |
|---|
| 423 | sys("file " SPARKLE "/Resources/relaunch"); |
|---|
| 424 | sys("ulimit -a"); |
|---|
| 425 | } |
|---|
| 426 | // posix_spawn doesn't work on thread, so launch JVM in main thread before run loop. |
|---|
| 427 | // TN2147 says it's ok for non-AWT apps. |
|---|
| 428 | startBestVM(); |
|---|
| 429 | if (makeDebugReport) { |
|---|
| 430 | sleep(2); |
|---|
| 431 | fprintf(stderr, "#\n"); |
|---|
| 432 | fprintf(stderr, "# Debug-mode launch of GlimmerBlocker proxy now done.\n"); |
|---|
| 433 | fprintf(stderr, "#\n"); |
|---|
| 434 | fprintf(stderr, "# Please copy/paste the content of this window into a mail to\n"); |
|---|
| 435 | fprintf(stderr, "# feedback@glimmerblocker.org\n"); |
|---|
| 436 | if (!displayedInTextEdit) |
|---|
| 437 | fprintf(stderr, "# and then close this window and quit Terminal.\n"); |
|---|
| 438 | fprintf(stderr, "#\n"); |
|---|
| 439 | exit(0); |
|---|
| 440 | } |
|---|
| 441 | // |
|---|
| 442 | // Create a a sourceContext to be used by our source that makes |
|---|
| 443 | // sure the CFRunLoop doesn't exit right away |
|---|
| 444 | CFRunLoopSourceContext sourceContext; |
|---|
| 445 | sourceContext.version = 0; |
|---|
| 446 | sourceContext.info = NULL; |
|---|
| 447 | sourceContext.retain = NULL; |
|---|
| 448 | sourceContext.release = NULL; |
|---|
| 449 | sourceContext.copyDescription = NULL; |
|---|
| 450 | sourceContext.equal = NULL; |
|---|
| 451 | sourceContext.hash = NULL; |
|---|
| 452 | sourceContext.schedule = NULL; |
|---|
| 453 | sourceContext.cancel = NULL; |
|---|
| 454 | sourceContext.perform = &sourceCallBack; |
|---|
| 455 | // |
|---|
| 456 | CFRunLoopSourceRef sourceRef = CFRunLoopSourceCreate(NULL, 0, &sourceContext); |
|---|
| 457 | CFRunLoopAddSource(CFRunLoopGetCurrent(), sourceRef, kCFRunLoopCommonModes); |
|---|
| 458 | CFRunLoopRun(); |
|---|
| 459 | CFRelease(sourceRef); |
|---|
| 460 | return 0; |
|---|
| 461 | } |
|---|