aboutsummaryrefslogtreecommitdiffstats
path: root/erts/etc/unix/dyn_erl.c
diff options
context:
space:
mode:
Diffstat (limited to 'erts/etc/unix/dyn_erl.c')
-rw-r--r--erts/etc/unix/dyn_erl.c400
1 files changed, 400 insertions, 0 deletions
diff --git a/erts/etc/unix/dyn_erl.c b/erts/etc/unix/dyn_erl.c
new file mode 100644
index 0000000000..984935417e
--- /dev/null
+++ b/erts/etc/unix/dyn_erl.c
@@ -0,0 +1,400 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * This is a C version of the erl Bourne shell script
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "sys.h"
+#include <stdlib.h>
+#include <stdarg.h>
+
+#define BOOL int
+#define TRUE 1
+#define FALSE 0
+#define PATHSEP ":"
+#define DIRSEP "/"
+#define DIRSEPCHAR '/'
+
+static void
+error(char* format, ...)
+{
+ char sbuf[1024];
+ va_list ap;
+
+ va_start(ap, format);
+ vsprintf(sbuf, format, ap);
+ va_end(ap);
+ fprintf(stderr, "erl: %s\n", sbuf);
+ exit(1);
+}
+
+/*
+ * Variables.
+ */
+
+/*
+ * Manage memory
+ */
+
+static void *
+emalloc(size_t size)
+{
+ void *p = malloc(size);
+ if (p == NULL)
+ error("Insufficient memory");
+ return p;
+}
+
+/*
+static void *
+erealloc(void *p, size_t size)
+{
+ void *res = realloc(p, size);
+ if (res == NULL)
+ error("Insufficient memory");
+ return res;
+}
+*/
+
+static void
+efree(void *p)
+{
+ free(p);
+}
+
+static char*
+strsave(char* string)
+{
+ char* p = emalloc(strlen(string)+1);
+ strcpy(p, string);
+ return p;
+}
+
+/*
+ * Manage environment variables
+ */
+
+static char *
+get_env(char *key)
+{
+ return getenv(key);
+}
+
+static void
+set_env(char *key, char *value)
+{
+ size_t size = strlen(key) + 1 + strlen(value) + 1;
+ char *str = emalloc(size);
+ sprintf(str, "%s=%s", key, value);
+ if (putenv(str) != 0)
+ error("putenv(\"%s\") failed!", str);
+#ifdef HAVE_COPYING_PUTENV
+ efree(str);
+#endif
+}
+
+// /* A realpath look alike */
+// static char *
+// follow_symlinks(const char *path, char *resolved_path)
+// {
+// char tmp[PATH_MAX];
+// int len;
+//
+// strcpy(resolved_path, path);
+//
+// for (;;) {
+// len = readlink(resolved_path, tmp, PATH_MAX);
+//
+// if (len == -1) {
+// if (errno == EINVAL) {
+// /* Not a symbolic link. use the original name */
+// break;
+// } else {
+// return NULL;
+// }
+// } else {
+// tmp[len] = '\0';
+// strcpy(resolved_path, tmp);
+// }
+// }
+//
+// return resolved_path;
+// }
+
+/*
+ * Find absolute path to this program
+ */
+
+static char *
+find_prog(char *origpath)
+{
+ char relpath[PATH_MAX];
+ char abspath[PATH_MAX];
+
+ strcpy(relpath, origpath);
+
+ if (strstr(relpath, DIRSEP) == NULL) {
+ /* Just a base name */
+ char *envpath;
+
+ envpath = get_env("PATH");
+ if (envpath) {
+ /* Try to find the executable in the path */
+ char dir[PATH_MAX];
+ char *beg = envpath;
+ char *end;
+ int sz;
+ DIR *dp; /* Pointer to directory structure. */
+ struct dirent* dirp; /* Pointer to directory entry. */
+ BOOL look_for_sep = TRUE;
+
+ while (look_for_sep) {
+ end = strstr(beg, PATHSEP);
+ if (end != NULL) {
+ sz = end - beg;
+ strncpy(dir, beg, sz);
+ dir[sz] = '\0';
+ } else {
+ sz = strlen(beg);
+ strcpy(dir, beg);
+ look_for_sep = FALSE;
+ }
+ beg = end + 1;
+
+ dp = opendir(dir);
+ if (dp != NULL) {
+ while (TRUE) {
+ dirp = readdir(dp);
+ if (dirp == NULL) {
+ closedir(dp);
+ /* Try next directory in path */
+ break;
+ }
+
+ if (strcmp(origpath, dirp->d_name) == 0) {
+ /* Wow. We found the executable. */
+ strcpy(relpath, dir);
+ strcat(relpath, DIRSEP);
+ strcat(relpath, dirp->d_name);
+ closedir(dp);
+ look_for_sep = FALSE;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!realpath(relpath, abspath)) {
+ error("Cannot determine real path to erl");
+ }
+
+ return strdup(abspath);
+}
+
+/*
+ * Find bindir
+ */
+
+static void
+copy_latest_vsn(char *latest_vsn, char *next_vsn)
+{
+ char *lp;
+ char *np;
+ BOOL greater;
+
+ /* Find vsn */
+ for (lp = latest_vsn+strlen(latest_vsn)-1 ;lp > latest_vsn && *lp != DIRSEPCHAR; --lp)
+ ;
+
+ /* lp =+ length("erts-"); */
+ for (np = next_vsn+strlen(next_vsn)-1 ;np > next_vsn && *np != DIRSEPCHAR; --np)
+ ;
+
+ /* np =+ length("erts-"); */
+ while (TRUE) {
+ if (*lp != *np) {
+ if (*np > *lp) {
+ greater = TRUE;
+ } else {
+ greater = FALSE;
+ }
+
+ /* Find next dot or eos */
+ while (*lp != '\0' && *np != '\0') {
+ lp++;
+ np++;
+ if (*np == '.' && *lp == '.') {
+ break;
+ }
+ if (*np == '\0' && *lp == '\0') {
+ break;
+ }
+ if (*lp == '.' || *lp == '\0') {
+ greater = TRUE;
+ }
+ if (*np == '.' || *np == '\0') {
+ greater = FALSE;
+ }
+ }
+ if (greater) {
+ strcpy(latest_vsn, next_vsn);
+ }
+ return;
+ }
+ ++lp;
+ ++np;
+ }
+}
+
+static char *
+find_erts_vsn(char *erl_top)
+{
+ /* List install dir and look for latest erts-vsn */
+ DIR *dp; /* Pointer to directory structure. */
+ struct dirent* dirp; /* Pointer to directory entry. */
+ char latest_vsn[PATH_MAX]; /* Latest erts-vsn directory name. */
+
+ dp = opendir(erl_top);
+ if (dp == NULL) {
+ return NULL;
+ }
+
+ latest_vsn[0] = '\0';
+ for (;;) {
+ dirp = readdir(dp);
+ if (dirp == NULL) {
+ closedir(dp);
+ break;
+ }
+ if (strncmp("erts-", dirp->d_name, 5) == 0) {
+ copy_latest_vsn(latest_vsn, dirp->d_name);
+ }
+ }
+
+ if (latest_vsn[0] == '\0') {
+ return NULL;
+ } else {
+ char *p = malloc((strlen(erl_top)+1+strlen(latest_vsn)+4+1)*sizeof(char));
+ strcpy(p,erl_top);
+ strcat(p,DIRSEP);
+ strcat(p,latest_vsn);
+ strcat(p,DIRSEP);
+ strcat(p,"bin");
+ return p;
+ }
+}
+
+static char *
+find_bindir(char *erlpath)
+{
+ /* Assume that the path to erl is absolute and
+ * that it is not a symbolic link*/
+
+ char *p;
+ char *p2;
+ char buffer[PATH_MAX];
+
+ strcpy(buffer, erlpath);
+
+ /* Chop of base name*/
+ for (p = buffer+strlen(buffer)-1 ;p >= buffer && *p != DIRSEPCHAR; --p)
+ ;
+ *p = '\0';
+ p--;
+
+ /* Check if dir path is like ...\buffer\erts-vsn\bin */
+ for (;p >= buffer && *p != DIRSEPCHAR; --p)
+ ;
+ p--;
+ for (p2 = p;p2 >= buffer && *p2 != DIRSEPCHAR; --p2)
+ ;
+ p2++;
+ if (strncmp(p2, "erts-", 5) == 0) {
+ p = strsave(buffer);
+ return p;
+ }
+
+ /* Assume that dir path is like ...\buffer\bin */
+ *++p ='\0'; /* chop off bin dir */
+
+ p = find_erts_vsn(buffer);
+ if (p == NULL) {
+ return strsave(buffer);
+ } else {
+ return p;
+ }
+}
+
+/*
+ * main
+ */
+
+int
+main(int argc, char **argv)
+{
+ char *p;
+ char *abspath;
+ char *bindir; /* Location of executables. */
+ char rootdir[PATH_MAX]; /* Root location of Erlang installation. */
+ char progname[PATH_MAX]; /* Name of this program. */
+ char erlexec[PATH_MAX]; /* Path to erlexec */
+
+ /* Determine progname */
+ abspath = find_prog(argv[0]);
+ strcpy(progname, abspath);
+ for (p = progname+strlen(progname)-1;p >= progname && *p != '/'; --p)
+ ;
+
+ /* Determine bindir */
+ bindir = find_bindir(abspath);
+
+ /* Determine rootdir */
+ strcpy(rootdir, bindir);
+ for (p = rootdir+strlen(rootdir)-1;p >= rootdir && *p != '/'; --p)
+ ;
+ p--;
+ for (;p >= rootdir && *p != '/'; --p)
+ ;
+ *p ='\0';
+
+ /* Update environment */
+ set_env("EMU", "beam");
+ set_env("PROGNAME", progname);
+ set_env("BINDIR", bindir);
+ set_env("ROOTDIR", rootdir);
+
+ /* Invoke erlexec */
+ strcpy(erlexec, bindir);
+ strcat(erlexec, DIRSEP);
+ strcat(erlexec, "erlexec");
+
+ efree(abspath);
+ efree(bindir);
+
+ execvp(erlexec, argv);
+ error("Error %d executing \'%s\'.", errno, erlexec);
+ return 2;
+}