* THE SOFTWARE.
*/
-#include "config.h"
-
-#define _GNU_SOURCE
-#include <dlfcn.h>
-
-#include "glaze.h"
-
-#include <talloc.h>
-
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <errno.h>
-
-/* For PATH_MAX */
-#include <linux/limits.h>
-
-void *
-glaze_lookup (char *function)
-{
- static void *libgl_handle = NULL;
- void *ret;
-
- if (libgl_handle == NULL) {
- const char *path;
-
- path = getenv ("GLAZE_LIBGL");
- if (path == NULL) {
- fprintf (stderr, "GLAZE_LIBGL unset. "
- "Please set to path of libGL.so under glaze.\n"
- );
- exit (1);
- }
-
- libgl_handle = dlopen (path, RTLD_LAZY | RTLD_GLOBAL);
- if (libgl_handle == NULL) {
- fprintf (stderr, "glaze_lookup: Error: Failed to dlopen %s\n", path);
- exit (1);
- }
- }
-
- ret = dlsym (libgl_handle, function);
-
- if (ret == NULL) {
- fprintf (stderr, "Error: glaze_lookup failed to dlsym %s\n",
- function);
- exit (1);
- }
+#include <getopt.h>
+#include <limits.h>
- return ret;
-}
+#include <glaze.h>
-/* Terminate a string representing a filename at the final '/' to
- * eliminate the final filename component, (leaving only the directory
- * portions of the original path).
- *
- * Notes: A path containing no '/' character will not be modified.
- * A path consisting only of "/" will not be modified.
- */
static void
-chop_trailing_path_component (char *path)
-{
- char *slash;
-
- slash = strrchr (path, '/');
-
- if (slash == NULL)
- return;
-
- if (slash == path)
- return;
-
- *slash = '\0';
-}
-
-/* Find the absolute path of the currently executing binary.
- *
- * Returns: a string talloc'ed to 'ctx'
- */
-static char *
-get_bin_name (void *ctx)
-{
- const char *link = "/proc/self/exe";
- char *name;
-
- /* Yes, PATH_MAX is cheesy. I would have preferred to have
- * used lstat and read the resulting st_size, but everytime I
- * did that with /proc/self/exe I got a value of 0, (whereas
- * with a "real" symbolic link I make myself I get the length
- * of the filename being linked to). Go figure. */
- int name_len = PATH_MAX + 1;
-
- name = talloc_size (ctx, name_len);
- if (name == NULL) {
- fprintf (stderr, "Out of memory.\n");
- exit (1);
- }
-
- name_len = readlink (link, name, name_len - 1);
- if (name_len < 0) {
- fprintf (stderr, "Failed to readlink %s: %s\n", link,
- strerror (errno));
- exit (1);
- }
-
- name[name_len] = '\0';
-
- return name;
-}
-
-/* Does path exist? */
-static int
-exists (const char *path)
-{
- struct stat st;
- int err;
-
- err = stat (path, &st);
-
- /* Failed to stat. It either doesn't exist, or might as well not. */
- if (err == -1)
- return 0;
-
- return 1;
-}
-
-/* Execute "program" in a pipe, reads its first line of output on
- * stdout, and returns that as a string (discarding any further
- * output).
- *
- * Returns NULL if the program failed to execute for any reason.
- *
- * NOTE: The caller should free() the returned string when done with
- * it.
- */
-static char *
-read_process_output_one_line (const char *program)
-{
- FILE *process;
- int status;
- char *line = NULL;
- size_t len = 0;
- ssize_t bytes_read;
-
- process = popen (program, "r");
- if (process == NULL)
- return NULL;
-
- bytes_read = getline (&line, &len, process);
-
- status = pclose (process);
- if (! WIFEXITED (status))
- return NULL;
-
- if (WEXITSTATUS (status))
- return NULL;
-
- if (bytes_read == -1)
- return NULL;
-
- if (bytes_read) {
- if (line[strlen(line)-1] == '\n')
- line[strlen(line)-1] = '\0';
- return line;
- } else {
- return NULL;
- }
-}
-
-
-/* Look for "wrapper" library next to currently executing binary.
- *
- * If "wrapper" is an absolute path, return it directly.
- *
- * Otherwise, ("wrapper" is relative), look for an existing file named
- * "wrapper" in the same directory as the currently executing binary,
- * (as determined by /proc/self/exe). If that file exists, return its
- * path.
- *
- * Otherwise, return the original, relative "wrapper".
- */
-static const char *
-resolve_wrapper_path (void *ctx, const char *wrapper)
+usage (void)
{
- char *bin_path, *lib_path;
-
- if (*wrapper == '/')
- return wrapper;
-
- bin_path = get_bin_name (ctx);
-
- chop_trailing_path_component (bin_path);
-
- lib_path = talloc_asprintf (ctx, "%s/%s", bin_path, wrapper);
-
- talloc_free (bin_path);
-
- if (exists (lib_path))
- return lib_path;
-
- talloc_free (lib_path);
-
- return wrapper;
+ printf ("Usage: glaze --wrapper=<wrapper> <program> [program args...]\n"
+ "\n"
+ "Execute <program> with <wrapper> providing alternate OpenGL functions.\n");
}
-/* Return path to directory containing Glaze wrapper's libGL.so.1
- * suitable for use in LD_PRELOAD or LD_LIBRARY_PATH. Note that the
- * path returned may not be a full path to the directory but may end
- * with "$LIB" which will be expanded by the Linux dynamic linker to
- * an architecture specific string (such as "lib/i386-linux-gnu" or
- * "lib/x86_64-linux-gnu"). */
-static const char *
-find_glaze_libgl_dir (void)
-{
- return CONFIG_LIBDIR "/glaze/$LIB";
-}
+enum {
+ WRAPPER_OPT = CHAR_MAX + 1
+};
-void
-glaze_execute (int argc, char *argv[], const char *wrapper)
+int
+main (int argc, char *argv[])
{
- void *ctx = talloc_new (NULL);
- int i;
+ const char *wrapper = NULL;
+ int opt;
- /* Set GLAZE_WRAPPER to absolute path of wrapper library */
- if (wrapper == NULL || *wrapper == '\0') {
- fprintf (stderr, "Error: glaze_execute called with empty wrapper library.\n");
- return;
- }
-
- wrapper = resolve_wrapper_path (ctx, wrapper);
-
- setenv ("GLAZE_WRAPPER", wrapper, 1);
-
- /* Ensure GLAZE_LIBGL is set. If not, set GLAZE_LIBGL_32_AUTO
- * and GLAZE_LIBGL_64_AUTO
+ /* The initial '+' means that getopt will stop looking for
+ * options after the first non-option argument. This means
+ * that a command such as:
*
- * Note that we must do this before setting LD_LIBRARY_PATH,
- * since after that, of course we would find Glaze's wrapper
- * libGL.so.1. */
- if (getenv ("GLAZE_LIBGL") == NULL) {
- char *libgl_path;
-
- libgl_path = read_process_output_one_line ("glaze-find-libgl-32");
- if (libgl_path) {
- setenv ("GLAZE_LIBGL_32_AUTO", libgl_path, 1);
- free (libgl_path);
- }
-
- libgl_path = read_process_output_one_line ("glaze-find-libgl-64");
- if (libgl_path) {
- setenv ("GLAZE_LIBGL_64_AUTO", libgl_path, 1);
- free (libgl_path);
+ * glaze glenv --renderer=Foo glxgears
+ *
+ * Will do what is intended, (namely, have glaze invoke "glenv
+ * --renderer=Foo glxgears" rather than trying to interpret
+ * --renderer=Foo as an option to glaze itself.
+ */
+ const char *short_options="+h";
+ const struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"wrapper", required_argument, 0, WRAPPER_OPT},
+ {0, 0, 0, 0}
+ };
+
+ while (1)
+ {
+ opt = getopt_long (argc, argv, short_options, long_options, NULL);
+ if (opt == -1)
+ break;
+
+ switch (opt) {
+ case 'h':
+ usage ();
+ return 0;
+ case WRAPPER_OPT:
+ wrapper = optarg;
+ break;
+ default:
+ fprintf (stderr, "Internal error: "
+ "unexpected getopt value: %d\n", opt);
+ exit (1);
}
}
- /* Set LD_LIBRARY_PATH to include glaze's own libGL.so */
- const char *glaze_libgl_dir, *ld_library_path;
-
- glaze_libgl_dir = find_glaze_libgl_dir ();
-
- ld_library_path = getenv ("LD_LIBRARY_PATH");
-
- if (ld_library_path == NULL)
- ld_library_path = glaze_libgl_dir;
- else
- ld_library_path = talloc_asprintf (ctx, "%s:%s",
- glaze_libgl_dir,
- ld_library_path);
-
- setenv ("LD_LIBRARY_PATH", ld_library_path, 1);
-
- talloc_free (ctx);
-
- /* Execute program */
- execvp (argv[0], argv);
+ if (optind >= argc) {
+ fprintf (stderr, "Error: No program name provided, "
+ "see (glaze --help)\n");
+ exit (1);
+ }
- /* If execvp returns, something went wrong. */
- fprintf (stderr, "Error: Failed to exec:");
- for (i = 0; i < argc; i++)
- fprintf (stderr, " %s", argv[i]);
- fprintf (stderr, "\n");
+ glaze_execute (argc - optind, &argv[optind], wrapper);
- return;
+ /* If glaze_execute returns then something went wrong. */
+ return 1;
}