diff options
Diffstat (limited to 'erts/etc/unix/dyn_erl.c')
-rw-r--r-- | erts/etc/unix/dyn_erl.c | 400 |
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; +} |