Index: eclipseGtk.c =================================================================== RCS file: /cvsroot/eclipse/platform-launcher/library/gtk/eclipseGtk.c,v retrieving revision 1.25 diff -u -r1.25 eclipseGtk.c --- platform-launcher/library/gtk/eclipseGtk.c 17 Sep 2005 03:39:24 -0000 1.25 +++ platform-launcher/library/gtk/eclipseGtk.c 13 Dec 2005 20:55:34 -0000 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -291,6 +292,194 @@ return result; } +/* represents a linked list of used memory blocks, used for the arguments + * swapping below, so that we don't leak memory */ +struct llist +{ + char * data; + struct llist * next; +}; + +/* We check to see if the launcher was run from a symlink, if it was + * we need to change some paths to point at the actual launcher path, + * not the symlink-relative path. + * + * This works as follows: + * + * The symlink is usually something in /usr/bin (i.e. /usr/bin/eclipse) and + * links to something in /usr/share/ + * (i.e. /usr/share/eclipse/eclipse). However since the share dir should not + * have a compiled code in it, we store the actual launcher in + * /usr/lib// (i.e. /usr/lib/eclipse/eclipse). + * + * But startup.jar is in /usr/share/ so we need to make + * the launcher resolve one link deep and get the startup.jar at that path. + */ +int changeArgPaths(char *args[], struct llist ** toFree) +{ + int ret, pathlen, jarlen; + struct stat st; + char * link, * linkpath; + char ** opt, *tmp_p, *jarPath; + int launcherPos = 0; + int foundLauncher = 0; /* is the next arg supposed to be -launcher */ + int prevWasJar = 0; /* is the next arg supposed to be -jar */ + struct llist * curMemblock; + + *toFree = (struct llist *) malloc(sizeof (struct llist)); + link = (char *) malloc(sizeof(char) * PATH_MAX); + (*toFree)->data = link; + + (*toFree)->next = (struct llist *) malloc(sizeof (struct llist)); + curMemblock = (*toFree)->next; + + linkpath = (char *) malloc(sizeof(char) * PATH_MAX); + curMemblock->data = linkpath; + + /* first find the path of the launcher, this is after the -launcher + * command line option */ + + for (opt = args; *opt != NULL; opt++) + { + /* we found the '-launcher' flag */ + if (!strncmp(*opt, "-launcher", PATH_MAX -1)) + { + foundLauncher = 1; + } + + /* the flag after '-launcher' was not another '-blah' */ + if (foundLauncher == 1 && **opt != '-') + { + foundLauncher = 2; + launcherPos = opt - args; + break; + } + } + + /* see if we found the launcher path argument, otherwise, we'll just + * fail later */ + if (launcherPos > 0) + { + /* fix the executable name if we are running through a link */ + ret = lstat(args[launcherPos], &st); + if ( ret < 0 ) + { + printf("Lstat returned(%d): %s\n:", errno, strerror(errno)); + return ret; + } + + if (S_ISLNK(st.st_mode)) + { + /* read one link deep */ + ret = readlink(args[launcherPos], link, PATH_MAX - 1); + if (ret < 0) + { + printf("Readlink returned(%d): %s\n:", errno, strerror(errno)); + return ret; + } + + /* null terminate, since readlink() doesn't do that */ + link[ret] = '\0'; + + /* replace the name of the program */ + args[launcherPos] = link; + strncpy(linkpath, link, PATH_MAX); + + + /* now we need to replace every occurence of + * -jar with + * -jar / + * but only if the jar was not specified with an absolute path. + * + * We search the args for -jar, and see if they are aboslute, if not + * we prepend the path. + */ + + /* first find the path of the given launcher (before the last '/') */ + tmp_p = strrchr(linkpath, '/'); + + /* if the linked launcher is not a relative path to a file in the + * current directory */ + if (tmp_p != NULL) + { + /* truncate the after the last directory, keeping the '/' */ + tmp_p++; + *tmp_p = '\0'; + + pathlen = strlen(linkpath); + + for (opt = args; *opt != NULL; opt++) + { + /* we found a '-jar' flag, set for next iteration */ + if (!strncmp(*opt, "-jar", PATH_MAX -1)) + { + prevWasJar = 1; + } + + /* if we're at the argument after a 'jar' and it's not another + * '-blah' */ + if (prevWasJar == 1 && **opt != '-') + { + /* if the jar is an absolute path we won't do anything to + * it, because we assume it's correct */ + if ( **opt == '/') + { + continue; + } + + jarlen = strlen(*opt); + + /* we know that the jar is a relative path, so we just + * prepend it with the path to the link's target */ + + jarPath = (char *) malloc (sizeof(char) * + (pathlen + jarlen + 1)); + if (jarPath == NULL) + { + printf("Could not allocate a jar path, die...\n"); + return ENOMEM; + } + + /* add this malloced memory to the list */ + curMemblock->next = (struct llist *) malloc + (sizeof (struct llist)); + curMemblock = curMemblock->next; + curMemblock->data = jarPath; + + strncpy(jarPath, linkpath, pathlen + 1); + strncat(jarPath, *opt, jarlen); + + /* replace the jar with a pathed jar */ + *opt = jarPath; + } + + /* if we're not in at the -jar argument anymore, reset the + * flag */ + if (strncmp(*opt, "-jar", PATH_MAX -1)) + { + prevWasJar = 0; + } + } + } + } + curMemblock->next = NULL; + + } +} + +/* frees a linked list and it's data */ +void freeMem(struct llist * toFree) +{ + struct llist * next; + while (toFree != NULL) + { + next = toFree->next; + if (toFree->data != NULL) + free(toFree->data); + free(toFree); + toFree = next; + } +} /* Start the Java VM * @@ -302,11 +491,17 @@ int jvmExitCode = 1; pid_t jvmProcess; int exitCode; - + struct llist * toFree; /* memory used for symlink path changing */ + #ifdef MOZILLA_FIX fixEnvForMozilla(); #endif /* MOZILLA_FIX */ + + /* Change the paths if we are running through a symlink */ + changeArgPaths(args, &toFree); + + jvmProcess = fork(); if (jvmProcess == 0) { @@ -325,6 +520,13 @@ jvmExitCode = WEXITSTATUS(exitCode); } + /* We currently don't free the memory we allocated because it might be + * reused if the workspace is restarted (i.e. after an Update Manager + * installation). So we leave the memory alone, it will be freed when + * this process completely exits, this is OK because it needs to stay + * around for the lifetime of the process in any case. */ + /* freeMem(toFree); */ + return jvmExitCode; }