From 29ade362259ab5b1bcb692c1f5c74fb839b4e91c Mon Sep 17 00:00:00 2001 From: "Matthew N. Dodd" Date: Mon, 7 Apr 2003 16:21:26 +0000 Subject: [PATCH] Dynamic object dependency mapping: libmap. This is an optional feature, disabled by default. This will be useful to people testing the various POSIX threading libraries under -CURRENT but can easily serve other needs. --- include/paths.h | 1 + libexec/rtld-elf/Makefile | 9 ++ libexec/rtld-elf/libmap.c | 199 +++++++++++++++++++++++++++++++++++ libexec/rtld-elf/libmap.h | 7 ++ libexec/rtld-elf/rtld.1 | 2 + libexec/rtld-elf/rtld.c | 26 ++++- share/man/man5/Makefile | 2 +- share/man/man5/libmap.conf.5 | 111 +++++++++++++++++++ 8 files changed, 351 insertions(+), 6 deletions(-) create mode 100644 libexec/rtld-elf/libmap.c create mode 100644 libexec/rtld-elf/libmap.h create mode 100644 share/man/man5/libmap.conf.5 diff --git a/include/paths.h b/include/paths.h index 5376e7ea5370..48e3618f9c6f 100644 --- a/include/paths.h +++ b/include/paths.h @@ -60,6 +60,7 @@ #define _PATH_ETC "/etc" #define _PATH_FTPUSERS "/etc/ftpusers" #define _PATH_KMEM "/dev/kmem" +#define _PATH_LIBMAP_CONF "/etc/libmap.conf" #define _PATH_LOGIN "/usr/bin/login" #define _PATH_MAILDIR "/var/mail" #define _PATH_MAN "/usr/share/man" diff --git a/libexec/rtld-elf/Makefile b/libexec/rtld-elf/Makefile index cf406881a162..ff03080411cb 100644 --- a/libexec/rtld-elf/Makefile +++ b/libexec/rtld-elf/Makefile @@ -10,6 +10,15 @@ INSTALLFLAGS= -fschg -C -b MLINKS= rtld.1 ld-elf.so.1.1 \ rtld.1 ld.so.1 +# +# To enable the libmap.conf functionality please +# add 'WITH_LIBMAP=yes' to /etc/make.conf, recompile +# and reinstall rtld-elf. +.ifdef WITH_LIBMAP +CFLAGS+= -DWITH_LIBMAP +SRCS+= libmap.c +.endif + .if exists(${.CURDIR}/${MACHINE_ARCH}/Makefile.inc) .include "${.CURDIR}/${MACHINE_ARCH}/Makefile.inc" .endif diff --git a/libexec/rtld-elf/libmap.c b/libexec/rtld-elf/libmap.c new file mode 100644 index 000000000000..d4654b4de10f --- /dev/null +++ b/libexec/rtld-elf/libmap.c @@ -0,0 +1,199 @@ +/* + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include + +#ifndef _PATH_LIBMAP_CONF +#define _PATH_LIBMAP_CONF "/etc/libmap.conf" +#endif + +TAILQ_HEAD(lm_list, lm); +struct lm { + char *f; + char *t; + + TAILQ_ENTRY(lm) lm_link; +}; + +TAILQ_HEAD(lmp_list, lmp) lmp_head = TAILQ_HEAD_INITIALIZER(lmp_head); +struct lmp { + char *p; + struct lm_list lml; + TAILQ_ENTRY(lmp) lmp_link; +}; + +static void lm_add (char *, char *, char *); +static void lm_free (struct lm_list *); +static char * lml_find (struct lm_list *, const char *); +static struct lm_list * lmp_find (const char *); +static struct lm_list * lmp_init (char *); + +void +lm_init (void) +{ + FILE *fp; + char *cp; + char *f, *t, *p; + char prog[MAXPATHLEN]; + char line[MAXPATHLEN + 2]; + + TAILQ_INIT(&lmp_head); + + if ((fp = fopen(_PATH_LIBMAP_CONF, "r")) == NULL) + return; + + p = NULL; + while ((cp = fgets(line, MAXPATHLEN + 1, fp)) != NULL) { + t = f = NULL; + /* Skip over leading space */ + while (!isalpha(*cp) && + *cp != '#' && *cp != '\0' && *cp != '[') cp++; + /* Found a comment or EOL */ + if (*cp == '#' || *cp == '\0') + continue; + /* Found a costraint selector */ + if (*cp == '[') { + cp++; + /* Skip leading space */ + while (isspace(*cp) && + *cp != '#' && *cp != '\0' && *cp != ']') cp++; + /* Found comment, EOL or end of selector */ + if (*cp == '#' || *cp == '\0' || *cp == ']') + continue; + p = cp; + /* Skip to end of word */ + while (!isspace(*cp) && + *cp != '#' && *cp != '\0' && *cp != ']') cp++; + *cp++ = '\0'; + bzero(prog, MAXPATHLEN); + strncpy(prog, p, strlen(p)); + p = prog; + continue; + } + f = cp; + while (!isspace(*cp) && *cp != '#' && *cp != '\0') cp++; + *cp++ = '\0'; + while (isspace(*cp) && *cp != '#' && *cp != '\0') cp++; + t = cp; + while (!isspace(*cp) && *cp != '#' && *cp != '\0') cp++; + *cp++ = '\0'; + + lm_add(p, strdup(f), strdup(t)); + bzero(line, sizeof(line)); + } + (void)fclose(fp); + return; +} + +static void +lm_free (struct lm_list *lml) +{ + struct lm *lm; + + while (!TAILQ_EMPTY(lml)) { + lm = TAILQ_FIRST(lml); + TAILQ_REMOVE(lml, lm, lm_link); + free(lm->f); + free(lm->t); + free(lm); + } + return; +} + +void +lm_fini (void) +{ + struct lmp *lmp; + + while (!TAILQ_EMPTY(&lmp_head)) { + lmp = TAILQ_FIRST(&lmp_head); + TAILQ_REMOVE(&lmp_head, lmp, lmp_link); + free(lmp->p); + lm_free(&lmp->lml); + free(lmp); + } + return; +} + +static void +lm_add (char *p, char *f, char *t) +{ + struct lm_list *lml; + struct lm *lm; + + if (p == NULL) + p = "$DEFAULT$"; + +#if 0 + printf("%s(\"%s\", \"%s\", \"%s\")\n", __func__, p, f, t); +#endif + + if ((lml = lmp_find(p)) == NULL) + lml = lmp_init(strdup(p)); + + lm = malloc(sizeof(struct lm)); + lm->f = f; + lm->t = t; + TAILQ_INSERT_HEAD(lml, lm, lm_link); +} + +char * +lm_find (const char *p, const char *f) +{ + struct lm_list *lml; + char *t; + + if (p != NULL && (lml = lmp_find(p)) != NULL) { + t = lml_find(lml, f); + if (t != NULL) + return (t); + } + lml = lmp_find("$DEFAULT$"); + if (lml != NULL) + return (lml_find(lml, f)); + else + return (NULL); +} + +static char * +lml_find (struct lm_list *lmh, const char *f) +{ + struct lm *lm; + + TAILQ_FOREACH(lm, lmh, lm_link) + if ((strncmp(f, lm->f, strlen(lm->f)) == 0) && + (strlen(f) == strlen(lm->f))) + return (lm->t); + return NULL; +} + +static struct lm_list * +lmp_find (const char *n) +{ + struct lmp *lmp; + + TAILQ_FOREACH(lmp, &lmp_head, lmp_link) + if ((strncmp(n, lmp->p, strlen(lmp->p)) == 0) && + (strlen(n) == strlen(lmp->p))) + return (&lmp->lml); + return (NULL); +} + +static struct lm_list * +lmp_init (char *n) +{ + struct lmp *lmp; + + lmp = malloc(sizeof(struct lmp)); + lmp->p = n; + TAILQ_INIT(&lmp->lml); + TAILQ_INSERT_HEAD(&lmp_head, lmp, lmp_link); + + return (&lmp->lml); +} diff --git a/libexec/rtld-elf/libmap.h b/libexec/rtld-elf/libmap.h new file mode 100644 index 000000000000..8228ef8edcb1 --- /dev/null +++ b/libexec/rtld-elf/libmap.h @@ -0,0 +1,7 @@ +/* + * $FreeBSD$ + */ + +void lm_init (void); +void lm_fini (void); +char * lm_find (const char *, const char *); diff --git a/libexec/rtld-elf/rtld.1 b/libexec/rtld-elf/rtld.1 index 472c572b3bca..3916922fc132 100644 --- a/libexec/rtld-elf/rtld.1 +++ b/libexec/rtld-elf/rtld.1 @@ -157,6 +157,8 @@ are recognized and have their usual meaning. .Sh FILES .Bl -tag -width indent .It Pa /var/run/ld-elf.so.hints +.It Pa /etc/libmap.conf +The libmap configuration file. .El .Sh SEE ALSO .Xr ld 1 , diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 2016ce01e235..2bd6584c0fa9 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -52,6 +52,9 @@ #include "debug.h" #include "rtld.h" +#ifdef WITH_LIBMAP +#include "libmap.h" +#endif #define END_SYM "_end" #define PATH_RTLD "/usr/libexec/ld-elf.so.1" @@ -366,6 +369,10 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) sym_zero.st_info = ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE); sym_zero.st_shndx = SHN_UNDEF; +#ifdef WITH_LIBMAP + lm_init(); +#endif + dbg("loading LD_PRELOAD libraries"); if (load_preload_objects() == -1) die(); @@ -802,19 +809,25 @@ elf_hash(const char *name) * /usr/lib */ static char * -find_library(const char *name, const Obj_Entry *refobj) +find_library(const char *xname, const Obj_Entry *refobj) { char *pathname; + char *name; - if (strchr(name, '/') != NULL) { /* Hard coded pathname */ - if (name[0] != '/' && !trust) { + if (strchr(xname, '/') != NULL) { /* Hard coded pathname */ + if (xname[0] != '/' && !trust) { _rtld_error("Absolute pathname required for shared object \"%s\"", - name); + xname); return NULL; } - return xstrdup(name); + return xstrdup(xname); } +#ifdef WITH_LIBMAP + if ((name = lm_find(refobj->path, xname)) == NULL) +#endif + name = (char *)xname; + dbg(" Searching for \"%s\"", name); if ((pathname = search_library_path(name, ld_library_path)) != NULL || @@ -1468,6 +1481,9 @@ rtld_exit(void) obj->refcount = 0; objlist_call_fini(&list_fini); /* No need to remove the items from the list, since we are exiting. */ +#ifdef WITH_LIBMAP + lm_fini(); +#endif } static void * diff --git a/share/man/man5/Makefile b/share/man/man5/Makefile index dc3765da35e2..34a316bb774e 100644 --- a/share/man/man5/Makefile +++ b/share/man/man5/Makefile @@ -6,7 +6,7 @@ MAN= a.out.5 acct.5 core.5 devfs.5 device.hints.5 \ dir.5 disktab.5 drivers.conf.5 \ elf.5 ethers.5 fbtab.5 fdescfs.5 forward.5 fs.5 fstab.5 group.5 \ hesiod.conf.5 \ - hosts.5 hosts.equiv.5 hosts.lpd.5 intro.5 link.5 \ + hosts.5 hosts.equiv.5 hosts.lpd.5 intro.5 libmap.conf.5 link.5 \ linprocfs.5 mailer.conf.5 make.conf.5 moduli.5 motd.5 msdosfs.5 \ networks.5 \ nsswitch.conf.5 \ diff --git a/share/man/man5/libmap.conf.5 b/share/man/man5/libmap.conf.5 new file mode 100644 index 000000000000..5acde5dc83d8 --- /dev/null +++ b/share/man/man5/libmap.conf.5 @@ -0,0 +1,111 @@ +.\" Copyright (c) 2003 Matthew N. Dodd +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.\" Note: The date here should be updated whenever a non-trivial +.\" change is made to the manual page. +.Dd April 7, 2003 +.Dt LIBMAP.CONF 5 +.Os +.Sh NAME +.Nm libmap.conf +.Nd "configuration file for dynamic object dependency mapping" +.Sh DESCRIPTION +The +.Em libmap +functionality of +.Nm ld-elf.so.1 +allows dynamic object dependencies to be mapped to arbitrary +names. +.Pp +The configuration file consists of two whitespace separated columns; the +left hand side containing the mapping candidate and the right hand +side containing the mapping. Dependencies are matched against candidates +and replaced with the mappings. +.Pp +Constrained mappings may be specified by enclosing the name of the +executable or library in brackets. All mappings following a constraint +will only be evaluated for that constraint. Currently, constraints +are matched literally so that an executable with a fully qualified pathname +will only match the same constraint. This means that +.Em /usr/bin/foo +will not match a constraint for +.Em foo +and vise-versa. +.Pp +WARNING! Constrained mappings must never appear first in the configuration +file. While there is a way to specify the +.Dq default +constraint, its use is not recommended. +.Pp +The most common use at the date of writing is for allowing multiple +POSIX threading libraries to be used on a system without relinking or +changing symlinks. +.Pp +In order to enable this feature please see +.Pa src/libexec/rtld-elf/Makefile . +.Sh EXAMPLE +.Bd -literal + +# /etc/libmap.conf +# +# candidate mapping +# +libc_r.so.5 libthr.so.1 # Everything uses 'libthr' +libc_r.so libthr.so + +[/usr/local/bin/mplayer] # 'mplayer' uses libc_r. +libc_r.so.5 libc_r.so.5 +libc_r.so libc_r.so + +[mplayer] +libc_r.so.5 libc_r.so.5 +libc_r.so libc_r.so + +[/usr/local/sbin/httpd] # Apache uses libkse +libc_r.so.5 libkse.so.1 +libc_r.so libkse.so + +[httpd] +libc_r.so.5 libkse.so.1 +libc_r.so libkse.so +.Ed +.Sh FILES +.Bl -tag -width ".Pa /etc/libmap.conf" -compact +.It Pa /etc/libmap.conf +The libmap configuration file. +.El +.Sh SEE ALSO +.Xr rtld 1 +.Xr ldd 1 +.Sh HISTORY +The +.Nm +manual page and libmap.conf functionality first appeared in +.Fx 5.1 . +.Sh AUTHORS +This +manual page was written by +.An Matthew N. Dodd .