diff options
-rw-r--r-- | libexec/rtld-elf/libmap.c | 162 | ||||
-rw-r--r-- | share/man/man5/libmap.conf.5 | 23 |
2 files changed, 154 insertions, 31 deletions
diff --git a/libexec/rtld-elf/libmap.c b/libexec/rtld-elf/libmap.c index cf86703..239dd0c 100644 --- a/libexec/rtld-elf/libmap.c +++ b/libexec/rtld-elf/libmap.c @@ -2,11 +2,13 @@ * $FreeBSD$ */ +#include <sys/types.h> #include <sys/param.h> #include <sys/fcntl.h> #include <sys/mman.h> #include <sys/queue.h> #include <sys/stat.h> +#include <dirent.h> #include <errno.h> #include <stdlib.h> #include <string.h> @@ -39,9 +41,17 @@ struct lmp { TAILQ_ENTRY(lmp) lmp_link; }; +static TAILQ_HEAD(lmc_list, lmc) lmc_head = TAILQ_HEAD_INITIALIZER(lmc_head); +struct lmc { + char *path; + TAILQ_ENTRY(lmc) next; +}; + static int lm_count; static void lmc_parse(char *, size_t); +static void lmc_parse_file(char *); +static void lmc_parse_dir(char *); static void lm_add(const char *, const char *, const char *); static void lm_free(struct lm_list *); static char *lml_find(struct lm_list *, const char *); @@ -61,37 +71,13 @@ static const char *quickbasename(const char *); int lm_init(char *libmap_override) { - struct stat st; - char *lm_map, *p; - int fd; + char *p; dbg("lm_init(\"%s\")", libmap_override); TAILQ_INIT(&lmp_head); - fd = open(_PATH_LIBMAP_CONF, O_RDONLY); - if (fd == -1) { - dbg("lm_init: open(\"%s\") failed, %s", _PATH_LIBMAP_CONF, - rtld_strerror(errno)); - goto override; - } - if (fstat(fd, &st) == -1) { - close(fd); - dbg("lm_init: fstat(\"%s\") failed, %s", _PATH_LIBMAP_CONF, - rtld_strerror(errno)); - goto override; - } - lm_map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - if (lm_map == (const char *)MAP_FAILED) { - close(fd); - dbg("lm_init: mmap(\"%s\") failed, %s", _PATH_LIBMAP_CONF, - rtld_strerror(errno)); - goto override; - } - close(fd); - lmc_parse(lm_map, st.st_size); - munmap(lm_map, st.st_size); + lmc_parse_file(_PATH_LIBMAP_CONF); -override: if (libmap_override) { /* * Do some character replacement to make $LIBMAP look @@ -116,14 +102,116 @@ override: } static void +lmc_parse_file(char *path) +{ + struct lmc *p; + struct stat st; + int fd; + char *rpath; + char *lm_map; + + rpath = realpath(path, NULL); + if (rpath == NULL) + return; + + TAILQ_FOREACH(p, &lmc_head, next) { + if (strcmp(p->path, rpath) == 0) { + free(rpath); + return; + } + } + + fd = open(path, O_RDONLY); + if (fd == -1) { + dbg("lm_init: open(\"%s\") failed, %s", path, + rtld_strerror(errno)); + free(rpath); + return; + } + if (fstat(fd, &st) == -1) { + close(fd); + dbg("lm_init: fstat(\"%s\") failed, %s", path, + rtld_strerror(errno)); + free(rpath); + return; + } + lm_map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (lm_map == (const char *)MAP_FAILED) { + close(fd); + dbg("lm_init: mmap(\"%s\") failed, %s", path, + rtld_strerror(errno)); + free(rpath); + return; + } + close(fd); + p = xmalloc(sizeof(struct lmc)); + p->path = rpath; + TAILQ_INSERT_HEAD(&lmc_head, p, next); + lmc_parse(lm_map, st.st_size); + munmap(lm_map, st.st_size); +} + +static void +lmc_parse_dir(char *idir) +{ + DIR *d; + struct dirent *dp; + struct lmc *p; + char conffile[MAXPATHLEN]; + char *ext; + char *rpath; + + rpath = realpath(idir, NULL); + if (rpath == NULL) + return; + + TAILQ_FOREACH(p, &lmc_head, next) { + if (strcmp(p->path, rpath) == 0) { + free(rpath); + return; + } + } + d = opendir(idir); + if (d == NULL) { + free(rpath); + return; + } + + p = xmalloc(sizeof(struct lmc)); + p->path = rpath; + TAILQ_INSERT_HEAD(&lmc_head, p, next); + + while ((dp = readdir(d)) != NULL) { + if (dp->d_ino == 0) + continue; + if (dp->d_type != DT_REG) + continue; + ext = strrchr(dp->d_name, '.'); + if (ext == NULL) + continue; + if (strcmp(ext, ".conf") != 0) + continue; + if (strlcpy(conffile, idir, MAXPATHLEN) >= MAXPATHLEN) + continue; /* too long */ + if (strlcat(conffile, "/", MAXPATHLEN) >= MAXPATHLEN) + continue; /* too long */ + if (strlcat(conffile, dp->d_name, MAXPATHLEN) >= MAXPATHLEN) + continue; /* too long */ + lmc_parse_file(conffile); + } + closedir(d); +} + +static void lmc_parse(char *lm_p, size_t lm_len) { char *cp, *f, *t, *c, *p; char prog[MAXPATHLEN]; - char line[MAXPATHLEN + 2]; + /* allow includedir + full length path */ + char line[MAXPATHLEN + 13]; size_t cnt; int i; - + cnt = 0; p = NULL; while (cnt < lm_len) { @@ -181,7 +269,8 @@ lmc_parse(char *lm_p, size_t lm_len) while(rtld_isspace(*cp)) cp++; if (!iseol(*cp)) continue; - strcpy(prog, c); + if (strlcpy(prog, c, sizeof prog) >= sizeof prog) + continue; p = prog; continue; } @@ -207,7 +296,12 @@ lmc_parse(char *lm_p, size_t lm_len) if (!iseol(*cp)) continue; *cp = '\0'; - lm_add(p, f, t); + if (strcmp(f, "includedir") == 0) + lmc_parse_dir(t); + else if (strcmp(f, "include") == 0) + lmc_parse_file(t); + else + lm_add(p, f, t); } } @@ -232,9 +326,17 @@ void lm_fini (void) { struct lmp *lmp; + struct lmc *p; dbg("%s()", __func__); + while (!TAILQ_EMPTY(&lmc_head)) { + p = TAILQ_FIRST(&lmc_head); + TAILQ_REMOVE(&lmc_head, p, next); + free(p->path); + free(p); + } + while (!TAILQ_EMPTY(&lmp_head)) { lmp = TAILQ_FIRST(&lmp_head); TAILQ_REMOVE(&lmp_head, lmp, lmp_link); diff --git a/share/man/man5/libmap.conf.5 b/share/man/man5/libmap.conf.5 index 6959ce2..784d5d0 100644 --- a/share/man/man5/libmap.conf.5 +++ b/share/man/man5/libmap.conf.5 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 31, 2004 +.Dd April 28, 2012 .Dt LIBMAP.CONF 5 .Os .Sh NAME @@ -43,6 +43,27 @@ 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 +Two special directives are available: +.Bl -tag -width indent +.It Cm include Ar file +Parse the contents of +.Ar file +before continuing with the current file. +.It Cm includedir Ar dir +Parse the contents of every file in +.Ar dir +that ends in +.Pa .conf +before continuing with the current file. +.El +.Pp +Any file or directory encountered while processing +.Cm include +or +.Cm includedir +directives will be parsed exactly once, even if it is encountered +multiple times. +.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. |