[Simh] [RFC, PATCH] Linux Installer for VAX emulator (resend as part 1/2)

Peter Lund firefly at vax64.dk
Fri Sep 14 12:06:47 EDT 2007


(There's apparently a 40K size limit and this message was 49K so I've
split the patch up)

This patch is mainly a request for comments.

This patch packages the VAX emulator and its firmware into a single-
click, single-file distribution-neutral installer for Linux.

Applies on top of 3.7.3.

The main problem it solves is the problem of finding its firmware
(ka655x.bin) once it is running.  The traditional Unix/Linux way was to
hardcode such a path into the application during build.  What SimH
currently does is simply to look in the current directory.  Neither is
acceptable for installed software (although looking in the current
directory might be nice during development).

A better solution is to calculate the firmware path from the
executable's path.  So how do we find that?  On a new kernel it is easy,
just follow the symlink /proc/self/exe.  On older kernels it is not
quite so easy.  It involves reading /proc/self/maps and parse it to find
the file name that matches the current program.

The autopackage/binreloc.[ch] code does just that.  It tries
/proc/self/exe first and then falls back to /proc/self/maps.  If that
doesn't work either it basically gives up (by letting the caller decide
on a default).

I have made the ROM load code first try the current directory.  Failing
that, it will try the shared data directory that binreloc suggests
(using /usr/share as default) after appending vaxemu/ka655x.bin to it.

All that work makes it basically work out of the box, which is nice if
somebody wants to use the emulator to play with rather than to hack on.

The other big problem that I had to tackle was the build script
(the makefile).

It presumes that the compiler can 1) compile many files in one go and
2) also link the resulting maching code to an executable file, all in
one invocation.  Gcc can do that but the apgcc wrapper that Autopackage
uses can't.  We also lose the ability to get any advantage from ccache
that way.  And Microsoft's C compiler (CL.EXE) and linker (LINK.EXE)
can't do the same trick -- or else I just don't know how.  Doing one
compile at a time and then a link should make it easier to work with
other build tools and other compilers.

Another advantage of the new makefile is that it becomes practical to
override CC and CFLAGS from the command line (if one for example wants
to enable an extra warning or two or experiment with optimization
flags).

And there's help now!  And a 'distclean' target!  And it creates the BIN
directory itself when/if necessary!

The emulator package has a homepage:
 http://vax64.dk/vaxemu/

Questions:
 1) what do other packagers do?
 2) how do you like the makefile?
 3) should packaging scripts live in the main distribution or be
    maintained outside of it?  I've hard good arguments either way by
    reasonable people.
 4) can anybody with artistic skills draw up a SimH icon suitable for
    desktops?  Perhaps even one that can be "themed" as a VAX, PDP-11,
    PDP-10, etc icon?

Comments?

-Peter

PS: You can also use hg clone http://vax64.dyndns.org/vaxemu


Affected files:
 VAX/vax_sysdev.c             |   31 +
 b/autopackage/binreloc.c     |  766 +++++++++++++++++++++++++++++++++++++++++++
 b/autopackage/binreloc.h     |   80 ++++
 b/autopackage/default.apspec |   90 +++++
 b/man/man1/vaxemu.1          |   21 +
 makefile                     |  510 +++++++---------------------
 scp.c                        |    8 
 7 files changed, 1136 insertions(+), 370 deletions(-)



# HG changeset patch
# User Peter Lund <firefly at vax64.dk>
# Date 1189657630 -7200
# Node ID b0a8c6ad88667dd524023b2b60a058c4a8ae9711
# Parent  76cb8a5e0cbd5b9c3aeafa8ac160aa3a0973fb54
Simple Linux installer.  Only supports the VAX emulator.

 o built on top of SimH v3.7.3.
 o the makefile is better (but only supports the VAX target)
 o you don't have to create the BIN directory manually
 o contains a dummy man page
 o knows how to find the ka655x.bin firmware file (using binreloc from the
   autopackage project -- probably also useful without autopackage)
 o distro neutral single-click single-file installer
   (run 'makepackage' tool from the autopackage developer toolkit to build)

diff -r 76cb8a5e0cbd -r b0a8c6ad8866 VAX/vax_sysdev.c
--- a/VAX/vax_sysdev.c	Tue Sep 11 12:25:43 2007 +0200
+++ b/VAX/vax_sysdev.c	Thu Sep 13 06:27:10 2007 +0200
@@ -52,6 +52,9 @@
 */
 
 #include "vax_defs.h"
+#ifdef __linux__
+# include "autopackage/binreloc.h"
+#endif
 
 #define UNIT_V_NODELAY  (UNIT_V_UF + 0)                 /* ROM access equal to RAM access */
 #define UNIT_NODELAY    (1u << UNIT_V_NODELAY)
@@ -1521,8 +1524,32 @@ if (*rom == 0) {                        
 if (*rom == 0) {                                        /* no boot? */
     printf ("Loading boot code from ka655x.bin\n");
     if (sim_log) fprintf (sim_log, 
-        "Loading boot code from ka655x.bin\n");
-    r = load_cmd (0, "-R ka655x.bin");
+        "Loading boot code from ka655x.bin\n");
+    r = load_cmd (0, "-R ka655x.bin");
+#ifdef __linux__
+    /* If we didn't find the firmware in the current directory we are probably
+     * installed somewhere.  Find our data directory relative to our
+     * executable's position.
+     */
+    if (r == SCPE_OPENERR) {
+    	char	*dir, *fname, *cmd;
+
+	/* br_find_data_dir() is a function that's provided by Autopackage's
+	 * binreloc package.  It only really works on platforms with either
+	 * a /proc/self/exe pseudo symlink or a /proc/self/maps pseudo file
+	 * (i.e. it will work on most Linux distros and possibly also some
+	 * *BSDs).  If that file doesn't exist -- or anything else goes wrong
+	 * -- it just returns its argument.
+	 */
+    	dir   = br_find_data_dir("/usr/share");
+	fname = br_build_path(dir, "vaxemu/ka655x.bin");
+	cmd   = br_strcat("-R ", fname);
+	free(dir);
+	free(fname);
+    	r = load_cmd (0, cmd);
+    	free(cmd);
+    }
+#endif
     if (r != SCPE_OK) return r;
     }
 return SCPE_OK;
diff -r 76cb8a5e0cbd -r b0a8c6ad8866 autopackage/binreloc.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/autopackage/binreloc.c	Thu Sep 13 06:27:10 2007 +0200
@@ -0,0 +1,766 @@
+/*
+ * BinReloc - a library for creating relocatable executables
+ * Written by: Hongli Lai <h.lai at chello.nl>
+ * http://autopackage.org/
+ *
+ * This source code is public domain. You can relicense this code
+ * under whatever license you want.
+ *
+ * See http://autopackage.org/docs/binreloc/ for
+ * more information and how to use this.
+ */
+
+#ifndef __BINRELOC_C__
+#define __BINRELOC_C__
+
+#ifdef ENABLE_BINRELOC
+	#include <sys/types.h>
+	#include <sys/stat.h>
+	#include <unistd.h>
+#endif /* ENABLE_BINRELOC */
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include "binreloc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+
+/** @internal
+ * Find the canonical filename of the executable. Returns the filename
+ * (which must be freed) or NULL on error. If the parameter 'error' is
+ * not NULL, the error code will be stored there, if an error occured.
+ */
+static char *
+_br_find_exe (BrInitError *error)
+{
+#ifndef ENABLE_BINRELOC
+	if (error)
+		*error = BR_INIT_ERROR_DISABLED;
+	return NULL;
+#else
+	char *path, *path2, *line, *result;
+	size_t buf_size;
+	ssize_t size;
+	struct stat stat_buf;
+	FILE *f;
+
+	/* Read from /proc/self/exe (symlink) */
+	if (sizeof (path) > SSIZE_MAX)
+		buf_size = SSIZE_MAX - 1;
+	else
+		buf_size = PATH_MAX - 1;
+	path = (char *) malloc (buf_size);
+	if (path == NULL) {
+		/* Cannot allocate memory. */
+		if (error)
+			*error = BR_INIT_ERROR_NOMEM;
+		return NULL;
+	}
+	path2 = (char *) malloc (buf_size);
+	if (path2 == NULL) {
+		/* Cannot allocate memory. */
+		if (error)
+			*error = BR_INIT_ERROR_NOMEM;
+		free (path);
+		return NULL;
+	}
+
+	strncpy (path2, "/proc/self/exe", buf_size - 1);
+
+	while (1) {
+		int i;
+
+		size = readlink (path2, path, buf_size - 1);
+		if (size == -1) {
+			/* Error. */
+			free (path2);
+			break;
+		}
+
+		/* readlink() success. */
+		path[size] = '\0';
+
+		/* Check whether the symlink's target is also a symlink.
+		 * We want to get the final target. */
+		i = stat (path, &stat_buf);
+		if (i == -1) {
+			/* Error. */
+			free (path2);
+			break;
+		}
+
+		/* stat() success. */
+		if (!S_ISLNK (stat_buf.st_mode)) {
+			/* path is not a symlink. Done. */
+			free (path2);
+			return path;
+		}
+
+		/* path is a symlink. Continue loop and resolve this. */
+		strncpy (path, path2, buf_size - 1);
+	}
+
+
+	/* readlink() or stat() failed; this can happen when the program is
+	 * running in Valgrind 2.2. Read from /proc/self/maps as fallback. */
+
+	buf_size = PATH_MAX + 128;
+	line = (char *) realloc (path, buf_size);
+	if (line == NULL) {
+		/* Cannot allocate memory. */
+		free (path);
+		if (error)
+			*error = BR_INIT_ERROR_NOMEM;
+		return NULL;
+	}
+
+	f = fopen ("/proc/self/maps", "r");
+	if (f == NULL) {
+		free (line);
+		if (error)
+			*error = BR_INIT_ERROR_OPEN_MAPS;
+		return NULL;
+	}
+
+	/* The first entry should be the executable name. */
+	result = fgets (line, (int) buf_size, f);
+	if (result == NULL) {
+		fclose (f);
+		free (line);
+		if (error)
+			*error = BR_INIT_ERROR_READ_MAPS;
+		return NULL;
+	}
+
+	/* Get rid of newline character. */
+	buf_size = strlen (line);
+	if (buf_size <= 0) {
+		/* Huh? An empty string? */
+		fclose (f);
+		free (line);
+		if (error)
+			*error = BR_INIT_ERROR_INVALID_MAPS;
+		return NULL;
+	}
+	if (line[buf_size - 1] == 10)
+		line[buf_size - 1] = 0;
+
+	/* Extract the filename; it is always an absolute path. */
+	path = strchr (line, '/');
+
+	/* Sanity check. */
+	if (strstr (line, " r-xp ") == NULL || path == NULL) {
+		fclose (f);
+		free (line);
+		if (error)
+			*error = BR_INIT_ERROR_INVALID_MAPS;
+		return NULL;
+	}
+
+	path = strdup (path);
+	free (line);
+	fclose (f);
+	return path;
+#endif /* ENABLE_BINRELOC */
+}
+
+
+/** @internal
+ * Find the canonical filename of the executable which owns symbol.
+ * Returns a filename which must be freed, or NULL on error.
+ */
+static char *
+_br_find_exe_for_symbol (const void *symbol, BrInitError *error)
+{
+#ifndef ENABLE_BINRELOC
+	if (error)
+		*error = BR_INIT_ERROR_DISABLED;
+	return (char *) NULL;
+#else
+	#define SIZE PATH_MAX + 100
+	FILE *f;
+	size_t address_string_len;
+	char *address_string, line[SIZE], *found;
+
+	if (symbol == NULL)
+		return (char *) NULL;
+
+	f = fopen ("/proc/self/maps", "r");
+	if (f == NULL)
+		return (char *) NULL;
+
+	address_string_len = 4;
+	address_string = (char *) malloc (address_string_len);
+	found = (char *) NULL;
+
+	while (!feof (f)) {
+		char *start_addr, *end_addr, *end_addr_end, *file;
+		void *start_addr_p, *end_addr_p;
+		size_t len;
+
+		if (fgets (line, SIZE, f) == NULL)
+			break;
+
+		/* Sanity check. */
+		if (strstr (line, " r-xp ") == NULL || strchr (line, '/') == NULL)
+			continue;
+
+		/* Parse line. */
+		start_addr = line;
+		end_addr = strchr (line, '-');
+		file = strchr (line, '/');
+
+		/* More sanity check. */
+		if (!(file > end_addr && end_addr != NULL && end_addr[0] == '-'))
+			continue;
+
+		end_addr[0] = '\0';
+		end_addr++;
+		end_addr_end = strchr (end_addr, ' ');
+		if (end_addr_end == NULL)
+			continue;
+
+		end_addr_end[0] = '\0';
+		len = strlen (file);
+		if (len == 0)
+			continue;
+		if (file[len - 1] == '\n')
+			file[len - 1] = '\0';
+
+		/* Get rid of "(deleted)" from the filename. */
+		len = strlen (file);
+		if (len > 10 && strcmp (file + len - 10, " (deleted)") == 0)
+			file[len - 10] = '\0';
+
+		/* I don't know whether this can happen but better safe than sorry. */
+		len = strlen (start_addr);
+		if (len != strlen (end_addr))
+			continue;
+
+
+		/* Transform the addresses into a string in the form of 0xdeadbeef,
+		 * then transform that into a pointer. */
+		if (address_string_len < len + 3) {
+			address_string_len = len + 3;
+			address_string = (char *) realloc (address_string, address_string_len);
+		}
+
+		memcpy (address_string, "0x", 2);
+		memcpy (address_string + 2, start_addr, len);
+		address_string[2 + len] = '\0';
+		sscanf (address_string, "%p", &start_addr_p);
+
+		memcpy (address_string, "0x", 2);
+		memcpy (address_string + 2, end_addr, len);
+		address_string[2 + len] = '\0';
+		sscanf (address_string, "%p", &end_addr_p);
+
+
+		if (symbol >= start_addr_p && symbol < end_addr_p) {
+			found = file;
+			break;
+		}
+	}
+
+	free (address_string);
+	fclose (f);
+
+	if (found == NULL)
+		return (char *) NULL;
+	else
+		return strdup (found);
+#endif /* ENABLE_BINRELOC */
+}
+
+
+#ifndef BINRELOC_RUNNING_DOXYGEN
+	#undef NULL
+	#define NULL ((void *) 0) /* typecasted as char* for C++ type safeness */
+#endif
+
+static char *exe = (char *) NULL;
+
+
+/** Initialize the BinReloc library (for applications).
+ *
+ * This function must be called before using any other BinReloc functions.
+ * It attempts to locate the application's canonical filename.
+ *
+ * @note If you want to use BinReloc for a library, then you should call
+ *       br_init_lib() instead.
+ *
+ * @param error  If BinReloc failed to initialize, then the error code will
+ *               be stored in this variable. Set to NULL if you want to
+ *               ignore this. See #BrInitError for a list of error codes.
+ *
+ * @returns 1 on success, 0 if BinReloc failed to initialize.
+ */
+int
+br_init (BrInitError *error)
+{
+	exe = _br_find_exe (error);
+	return exe != NULL;
+}
+
+
+/** Initialize the BinReloc library (for libraries).
+ *
+ * This function must be called before using any other BinReloc functions.
+ * It attempts to locate the calling library's canonical filename.
+ *
+ * @note The BinReloc source code MUST be included in your library, or this
+ *       function won't work correctly.
+ *
+ * @param error  If BinReloc failed to initialize, then the error code will
+ *               be stored in this variable. Set to NULL if you want to
+ *               ignore this. See #BrInitError for a list of error codes.
+ *
+ * @returns 1 on success, 0 if a filename cannot be found.
+ */
+int
+br_init_lib (BrInitError *error)
+{
+	exe = _br_find_exe_for_symbol ((const void *) "", error);
+	return exe != NULL;
+}
+
+
+/** Find the canonical filename of the current application.
+ *
+ * @param default_exe  A default filename which will be used as fallback.
+ * @returns A string containing the application's canonical filename,
+ *          which must be freed when no longer necessary. If BinReloc is
+ *          not initialized, or if br_init() failed, then a copy of
+ *          default_exe will be returned. If default_exe is NULL, then
+ *          NULL will be returned.
+ */
+char *
+br_find_exe (const char *default_exe)
+{
+	if (exe == (char *) NULL) {
+		/* BinReloc is not initialized. */
+		if (default_exe != (const char *) NULL)
+			return strdup (default_exe);
+		else
+			return (char *) NULL;
+	}
+	return strdup (exe);
+}
+
+
+/** Locate the directory in which the current application is installed.
+ *
+ * The prefix is generated by the following pseudo-code evaluation:
+ * \code
+ * dirname(exename)
+ * \endcode
+ *
+ * @param default_dir  A default directory which will used as fallback.
+ * @return A string containing the directory, which must be freed when no
+ *         longer necessary. If BinReloc is not initialized, or if the
+ *         initialization function failed, then a copy of default_dir
+ *         will be returned. If default_dir is NULL, then NULL will be
+ *         returned.
+ */
+char *
+br_find_exe_dir (const char *default_dir)
+{
+	if (exe == NULL) {
+		/* BinReloc not initialized. */
+		if (default_dir != NULL)
+			return strdup (default_dir);
+		else
+			return NULL;
+	}
+
+	return br_dirname (exe);
+}
+
+
+/** Locate the prefix in which the current application is installed.
+ *
+ * The prefix is generated by the following pseudo-code evaluation:
+ * \code
+ * dirname(dirname(exename))
+ * \endcode
+ *
+ * @param default_prefix  A default prefix which will used as fallback.
+ * @return A string containing the prefix, which must be freed when no
+ *         longer necessary. If BinReloc is not initialized, or if
+ *         the initialization function failed, then a copy of default_prefix
+ *         will be returned. If default_prefix is NULL, then NULL will be returned.
+ */
+char *
+br_find_prefix (const char *default_prefix)
+{
+	char *dir1, *dir2;
+
+	if (exe == (char *) NULL) {
+		/* BinReloc not initialized. */
+		if (default_prefix != (const char *) NULL)
+			return strdup (default_prefix);
+		else
+			return (char *) NULL;
+	}
+
+	dir1 = br_dirname (exe);
+	dir2 = br_dirname (dir1);
+	free (dir1);
+	return dir2;
+}
+
+
+/** Locate the application's binary folder.
+ *
+ * The path is generated by the following pseudo-code evaluation:
+ * \code
+ * prefix + "/bin"
+ * \endcode
+ *
+ * @param default_bin_dir  A default path which will used as fallback.
+ * @return A string containing the bin folder's path, which must be freed when
+ *         no longer necessary. If BinReloc is not initialized, or if
+ *         the initialization function failed, then a copy of default_bin_dir will
+ *         be returned. If default_bin_dir is NULL, then NULL will be returned.
+ */
+char *
+br_find_bin_dir (const char *default_bin_dir)
+{
+	char *prefix, *dir;
+
+	prefix = br_find_prefix ((const char *) NULL);
+	if (prefix == (char *) NULL) {
+		/* BinReloc not initialized. */
+		if (default_bin_dir != (const char *) NULL)
+			return strdup (default_bin_dir);
+		else
+			return (char *) NULL;
+	}
+
+	dir = br_build_path (prefix, "bin");
+	free (prefix);
+	return dir;
+}
+
+
+/** Locate the application's superuser binary folder.
+ *
+ * The path is generated by the following pseudo-code evaluation:
+ * \code
+ * prefix + "/sbin"
+ * \endcode
+ *
+ * @param default_sbin_dir  A default path which will used as fallback.
+ * @return A string containing the sbin folder's path, which must be freed when
+ *         no longer necessary. If BinReloc is not initialized, or if the
+ *         initialization function failed, then a copy of default_sbin_dir will
+ *         be returned. If default_bin_dir is NULL, then NULL will be returned.
+ */
+char *
+br_find_sbin_dir (const char *default_sbin_dir)
+{
+	char *prefix, *dir;
+
+	prefix = br_find_prefix ((const char *) NULL);
+	if (prefix == (char *) NULL) {
+		/* BinReloc not initialized. */
+		if (default_sbin_dir != (const char *) NULL)
+			return strdup (default_sbin_dir);
+		else
+			return (char *) NULL;
+	}
+
+	dir = br_build_path (prefix, "sbin");
+	free (prefix);
+	return dir;
+}
+
+
+/** Locate the application's data folder.
+ *
+ * The path is generated by the following pseudo-code evaluation:
+ * \code
+ * prefix + "/share"
+ * \endcode
+ *
+ * @param default_data_dir  A default path which will used as fallback.
+ * @return A string containing the data folder's path, which must be freed when
+ *         no longer necessary. If BinReloc is not initialized, or if the
+ *         initialization function failed, then a copy of default_data_dir
+ *         will be returned. If default_data_dir is NULL, then NULL will be
+ *         returned.
+ */
+char *
+br_find_data_dir (const char *default_data_dir)
+{
+	char *prefix, *dir;
+
+	prefix = br_find_prefix ((const char *) NULL);
+	if (prefix == (char *) NULL) {
+		/* BinReloc not initialized. */
+		if (default_data_dir != (const char *) NULL)
+			return strdup (default_data_dir);
+		else
+			return (char *) NULL;
+	}
+
+	dir = br_build_path (prefix, "share");
+	free (prefix);
+	return dir;
+}
+
+
+/** Locate the application's localization folder.
+ *
+ * The path is generated by the following pseudo-code evaluation:
+ * \code
+ * prefix + "/share/locale"
+ * \endcode
+ *
+ * @param default_locale_dir  A default path which will used as fallback.
+ * @return A string containing the localization folder's path, which must be freed when
+ *         no longer necessary. If BinReloc is not initialized, or if the
+ *         initialization function failed, then a copy of default_locale_dir will be returned.
+ *         If default_locale_dir is NULL, then NULL will be returned.
+ */
+char *
+br_find_locale_dir (const char *default_locale_dir)
+{
+	char *data_dir, *dir;
+
+	data_dir = br_find_data_dir ((const char *) NULL);
+	if (data_dir == (char *) NULL) {
+		/* BinReloc not initialized. */
+		if (default_locale_dir != (const char *) NULL)
+			return strdup (default_locale_dir);
+		else
+			return (char *) NULL;
+	}
+
+	dir = br_build_path (data_dir, "locale");
+	free (data_dir);
+	return dir;
+}
+
+
+/** Locate the application's library folder.
+ *
+ * The path is generated by the following pseudo-code evaluation:
+ * \code
+ * prefix + "/lib"
+ * \endcode
+ *
+ * @param default_lib_dir  A default path which will used as fallback.
+ * @return A string containing the library folder's path, which must be freed when
+ *         no longer necessary. If BinReloc is not initialized, or if the initialization
+ *         function failed, then a copy of default_lib_dir will be returned.
+ *         If default_lib_dir is NULL, then NULL will be returned.
+ */
+char *
+br_find_lib_dir (const char *default_lib_dir)
+{
+	char *prefix, *dir;
+
+	prefix = br_find_prefix ((const char *) NULL);
+	if (prefix == (char *) NULL) {
+		/* BinReloc not initialized. */
+		if (default_lib_dir != (const char *) NULL)
+			return strdup (default_lib_dir);
+		else
+			return (char *) NULL;
+	}
+
+	dir = br_build_path (prefix, "lib");
+	free (prefix);
+	return dir;
+}
+
+
+/** Locate the application's libexec folder.
+ *
+ * The path is generated by the following pseudo-code evaluation:
+ * \code
+ * prefix + "/libexec"
+ * \endcode
+ *
+ * @param default_libexec_dir  A default path which will used as fallback.
+ * @return A string containing the libexec folder's path, which must be freed when
+ *         no longer necessary. If BinReloc is not initialized, or if the initialization
+ *         function failed, then a copy of default_libexec_dir will be returned.
+ *         If default_libexec_dir is NULL, then NULL will be returned.
+ */
+char *
+br_find_libexec_dir (const char *default_libexec_dir)
+{
+	char *prefix, *dir;
+
+	prefix = br_find_prefix ((const char *) NULL);
+	if (prefix == (char *) NULL) {
+		/* BinReloc not initialized. */
+		if (default_libexec_dir != (const char *) NULL)
+			return strdup (default_libexec_dir);
+		else
+			return (char *) NULL;
+	}
+
+	dir = br_build_path (prefix, "libexec");
+	free (prefix);
+	return dir;
+}
+
+
+/** Locate the application's configuration files folder.
+ *
+ * The path is generated by the following pseudo-code evaluation:
+ * \code
+ * prefix + "/etc"
+ * \endcode
+ *
+ * @param default_etc_dir  A default path which will used as fallback.
+ * @return A string containing the etc folder's path, which must be freed when
+ *         no longer necessary. If BinReloc is not initialized, or if the initialization
+ *         function failed, then a copy of default_etc_dir will be returned.
+ *         If default_etc_dir is NULL, then NULL will be returned.
+ */
+char *
+br_find_etc_dir (const char *default_etc_dir)
+{
+	char *prefix, *dir;
+
+	prefix = br_find_prefix ((const char *) NULL);
+	if (prefix == (char *) NULL) {
+		/* BinReloc not initialized. */
+		if (default_etc_dir != (const char *) NULL)
+			return strdup (default_etc_dir);
+		else
+			return (char *) NULL;
+	}
+
+	dir = br_build_path (prefix, "etc");
+	free (prefix);
+	return dir;
+}
+
+
+/***********************
+ * Utility functions
+ ***********************/
+
+/** Concatenate str1 and str2 to a newly allocated string.
+ *
+ * @param str1 A string.
+ * @param str2 Another string.
+ * @returns A newly-allocated string. This string should be freed when no longer needed.
+ */
+char *
+br_strcat (const char *str1, const char *str2)
+{
+	char *result;
+	size_t len1, len2;
+
+	if (str1 == NULL)
+		str1 = "";
+	if (str2 == NULL)
+		str2 = "";
+
+	len1 = strlen (str1);
+	len2 = strlen (str2);
+
+	result = (char *) malloc (len1 + len2 + 1);
+	memcpy (result, str1, len1);
+	memcpy (result + len1, str2, len2);
+	result[len1 + len2] = '\0';
+
+	return result;
+}
+
+
+char *
+br_build_path (const char *dir, const char *file)
+{
+	char *dir2, *result;
+	size_t len;
+	int must_free = 0;
+
+	len = strlen (dir);
+	if (len > 0 && dir[len - 1] != '/') {
+		dir2 = br_strcat (dir, "/");
+		must_free = 1;
+	} else
+		dir2 = (char *) dir;
+
+	result = br_strcat (dir2, file);
+	if (must_free)
+		free (dir2);
+	return result;
+}
+
+
+/* Emulates glibc's strndup() */
+static char *
+br_strndup (const char *str, size_t size)
+{
+	char *result = (char *) NULL;
+	size_t len;
+
+	if (str == (const char *) NULL)
+		return (char *) NULL;
+
+	len = strlen (str);
+	if (len == 0)
+		return strdup ("");
+	if (size > len)
+		size = len;
+
+	result = (char *) malloc (len + 1);
+	memcpy (result, str, size);
+	result[size] = '\0';
+	return result;
+}
+
+
+/** Extracts the directory component of a path.
+ *
+ * Similar to g_dirname() or the dirname commandline application.
+ *
+ * Example:
+ * \code
+ * br_dirname ("/usr/local/foobar");  --> Returns: "/usr/local"
+ * \endcode
+ *
+ * @param path  A path.
+ * @returns     A directory name. This string should be freed when no longer needed.
+ */
+char *
+br_dirname (const char *path)
+{
+	char *end, *result;
+
+	if (path == (const char *) NULL)
+		return (char *) NULL;
+
+	end = strrchr (path, '/');
+	if (end == (const char *) NULL)
+		return strdup (".");
+
+	while (end > path && *end == '/')
+		end--;
+	result = br_strndup (path, end - path + 1);
+	if (result[0] == 0) {
+		free (result);
+		return strdup ("/");
+	} else
+		return result;
+}
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __BINRELOC_C__ */
diff -r 76cb8a5e0cbd -r b0a8c6ad8866 autopackage/binreloc.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/autopackage/binreloc.h	Thu Sep 13 06:27:10 2007 +0200
@@ -0,0 +1,80 @@
+/*
+ * BinReloc - a library for creating relocatable executables
+ * Written by: Hongli Lai <h.lai at chello.nl>
+ * http://autopackage.org/
+ *
+ * This source code is public domain. You can relicense this code
+ * under whatever license you want.
+ *
+ * See http://autopackage.org/docs/binreloc/ for
+ * more information and how to use this.
+ */
+
+#ifndef __BINRELOC_H__
+#define __BINRELOC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/** These error codes can be returned by br_init(), br_init_lib(), gbr_init() or gbr_init_lib(). */
+typedef enum {
+	/** Cannot allocate memory. */
+	BR_INIT_ERROR_NOMEM,
+	/** Unable to open /proc/self/maps; see errno for details. */
+	BR_INIT_ERROR_OPEN_MAPS,
+	/** Unable to read from /proc/self/maps; see errno for details. */
+	BR_INIT_ERROR_READ_MAPS,
+	/** The file format of /proc/self/maps is invalid; kernel bug? */
+	BR_INIT_ERROR_INVALID_MAPS,
+	/** BinReloc is disabled (the ENABLE_BINRELOC macro is not defined). */
+	BR_INIT_ERROR_DISABLED
+} BrInitError;
+
+
+#ifndef BINRELOC_RUNNING_DOXYGEN
+/* Mangle symbol names to avoid symbol collisions with other ELF objects. */
+	#define br_init             RoGd92526924064174_br_init
+	#define br_init_lib         RoGd92526924064174_br_init_lib
+	#define br_find_exe         RoGd92526924064174_br_find_exe
+	#define br_find_exe_dir     RoGd92526924064174_br_find_exe_dir
+	#define br_find_prefix      RoGd92526924064174_br_find_prefix
+	#define br_find_bin_dir     RoGd92526924064174_br_find_bin_dir
+	#define br_find_sbin_dir    RoGd92526924064174_br_find_sbin_dir
+	#define br_find_data_dir    RoGd92526924064174_br_find_data_dir
+	#define br_find_locale_dir  RoGd92526924064174_br_find_locale_dir
+	#define br_find_lib_dir     RoGd92526924064174_br_find_lib_dir
+	#define br_find_libexec_dir RoGd92526924064174_br_find_libexec_dir
+	#define br_find_etc_dir     RoGd92526924064174_br_find_etc_dir
+	#define br_strcat           RoGd92526924064174_br_strcat
+	#define br_build_path       RoGd92526924064174_br_build_path
+	#define br_dirname          RoGd92526924064174_br_dirname
+
+
+#endif
+int   br_init             (BrInitError *error);
+int   br_init_lib         (BrInitError *error);
+
+char *br_find_exe         (const char *default_exe);
+char *br_find_exe_dir     (const char *default_dir);
+char *br_find_prefix      (const char *default_prefix);
+char *br_find_bin_dir     (const char *default_bin_dir);
+char *br_find_sbin_dir    (const char *default_sbin_dir);
+char *br_find_data_dir    (const char *default_data_dir);
+char *br_find_locale_dir  (const char *default_locale_dir);
+char *br_find_lib_dir     (const char *default_lib_dir);
+char *br_find_libexec_dir (const char *default_libexec_dir);
+char *br_find_etc_dir     (const char *default_etc_dir);
+
+/* Utility functions */
+char *br_strcat  (const char *str1, const char *str2);
+char *br_build_path (const char *dir, const char *file);
+char *br_dirname (const char *path);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __BINRELOC_H__ */





More information about the Simh mailing list