#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include <debug.h>
#include <sys/sysmacros.h>
#include "msg.h"
#include "_libld.h"
static Aliste Lidx = 0;
static char *
compat_YL_YU(Ofl_desc *ofl, char *path, int index)
{
if (index == YLDIR) {
if (Llibdir) {
DBG_CALL(Dbg_libs_ylu(ofl->ofl_lml, Llibdir,
path, index));
return (Llibdir);
}
} else if (index == YUDIR) {
if (Ulibdir) {
DBG_CALL(Dbg_libs_ylu(ofl->ofl_lml, Ulibdir,
path, index));
return (Ulibdir);
}
}
return (path);
}
static char *
process_lib_path(Ofl_desc *ofl, APlist **apl, char *path, Boolean subsflag)
{
int i;
char *cp;
Boolean seenflg = FALSE;
char *dot = (char *)MSG_ORIG(MSG_STR_DOT);
for (i = YLDIR; i; i++) {
cp = strpbrk(path, MSG_ORIG(MSG_STR_PATHTOK));
if (cp == NULL) {
if (*path == '\0') {
if (seenflg)
if (aplist_append(apl, (subsflag ?
compat_YL_YU(ofl, dot, i) : dot),
AL_CNT_OFL_LIBDIRS) == NULL)
return ((char *)S_ERROR);
} else if (aplist_append(apl, (subsflag ?
compat_YL_YU(ofl, path, i) : path),
AL_CNT_OFL_LIBDIRS) == NULL) {
return ((char *)S_ERROR);
}
return (cp);
}
if (*cp == ':') {
*cp = '\0';
if (cp == path) {
if (aplist_append(apl, (subsflag ?
compat_YL_YU(ofl, dot, i) : dot),
AL_CNT_OFL_LIBDIRS) == NULL)
return ((char *)S_ERROR);
} else if (aplist_append(apl, (subsflag ?
compat_YL_YU(ofl, path, i) : path),
AL_CNT_OFL_LIBDIRS) == NULL) {
return ((char *)S_ERROR);
}
path = cp + 1;
seenflg = TRUE;
continue;
}
if (cp != path) {
if (aplist_append(apl, (subsflag ?
compat_YL_YU(ofl, path, i) : path),
AL_CNT_OFL_LIBDIRS) == NULL)
return ((char *)S_ERROR);
} else {
if (seenflg)
if (aplist_append(apl, (subsflag ?
compat_YL_YU(ofl, dot, i) : dot),
AL_CNT_OFL_LIBDIRS) == NULL)
return ((char *)S_ERROR);
}
return (cp);
}
return (NULL);
}
uintptr_t
ld_add_libdir(Ofl_desc *ofl, const char *path)
{
if (aplist_insert(&ofl->ofl_ulibdirs, path,
AL_CNT_OFL_LIBDIRS, Lidx++) == NULL)
return (S_ERROR);
DBG_CALL(Dbg_libs_update(ofl->ofl_lml, ofl->ofl_ulibdirs,
ofl->ofl_dlibdirs));
return (1);
}
static uintptr_t
find_lib_name(const char *dir, const char *file, Ofl_desc *ofl, Rej_desc *rej,
ofl_flag_t flags)
{
int fd;
size_t dlen;
char *_path, path[PATH_MAX + 2];
const char *_dir = dir;
uintptr_t open_ret;
if ((dlen = strlen(dir)) == 0) {
_dir = (char *)MSG_ORIG(MSG_STR_DOT);
dlen = 1;
}
dlen++;
if (ofl->ofl_flags & FLG_OF_DYNLIBS) {
(void) snprintf(path, (PATH_MAX + 2), MSG_ORIG(MSG_STR_LIB_SO),
_dir, file);
DBG_CALL(Dbg_libs_l(ofl->ofl_lml, file, path));
if ((fd = open(path, O_RDONLY)) != -1) {
if ((_path = libld_malloc(strlen(path) + 1)) == NULL)
return (S_ERROR);
(void) strcpy(_path, path);
open_ret = ld_process_open(_path, &_path[dlen], &fd,
ofl, FLG_IF_NEEDED, rej, NULL);
if (fd != -1)
(void) close(fd);
if (open_ret != 0 && (flags & FLG_OF_ADEFLIB))
ld_eprintf(ofl, ERR_WARNING,
MSG_INTL(MSG_ARG_ASSDEFLIB_FOUND), dir,
file);
return (open_ret);
} else if (errno != ENOENT) {
rej->rej_type = SGS_REJ_STR;
rej->rej_str = strerror(errno);
rej->rej_name = strdup(path);
}
}
(void) snprintf(path, (PATH_MAX + 2), MSG_ORIG(MSG_STR_LIB_A),
_dir, file);
DBG_CALL(Dbg_libs_l(ofl->ofl_lml, file, path));
if ((fd = open(path, O_RDONLY)) != -1) {
if ((_path = libld_malloc(strlen(path) + 1)) == NULL)
return (S_ERROR);
(void) strcpy(_path, path);
open_ret = ld_process_open(_path, &_path[dlen], &fd, ofl,
FLG_IF_NEEDED, rej, NULL);
if (fd != -1)
(void) close(fd);
return (open_ret);
} else if (errno != ENOENT) {
rej->rej_type = SGS_REJ_STR;
rej->rej_str = strerror(errno);
rej->rej_name = strdup(path);
}
return (0);
}
uintptr_t
ld_find_library(const char *name, Ofl_desc *ofl)
{
Aliste idx;
char *path;
uintptr_t open_ret;
Rej_desc rej = { 0 };
ofl_flag_t flags = 0;
for (APLIST_TRAVERSE(ofl->ofl_ulibdirs, idx, path)) {
Rej_desc _rej = { 0 };
if ((open_ret = find_lib_name(path, name, ofl, &_rej,
flags)) == 0) {
if (_rej.rej_type && (rej.rej_type == 0))
rej = _rej;
continue;
}
return (open_ret);
}
if (ofl->ofl_flags & FLG_OF_ADEFLIB) {
flags |= FLG_OF_ADEFLIB;
for (APLIST_TRAVERSE(ofl->ofl_assdeflib, idx, path)) {
if (strncmp(name, path + MSG_STR_LIB_SIZE,
MAX(strlen(path + MSG_STR_LIB_SIZE) -
MSG_STR_SOEXT_SIZE, strlen(name))) == 0) {
flags &= ~FLG_OF_ADEFLIB;
break;
}
}
}
for (APLIST_TRAVERSE(ofl->ofl_dlibdirs, idx, path)) {
Rej_desc _rej = { 0 };
if ((open_ret = find_lib_name(path, name, ofl, &_rej,
flags)) == 0) {
if (_rej.rej_type && (rej.rej_type == 0))
rej = _rej;
continue;
}
return (open_ret);
}
if (rej.rej_type) {
Conv_reject_desc_buf_t rej_buf;
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(reject[rej.rej_type]),
rej.rej_name ? rej.rej_name : MSG_INTL(MSG_STR_UNKNOWN),
conv_reject_desc(&rej, &rej_buf, ld_targ.t_m.m_mach));
} else {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_LIB_NOTFOUND), name);
}
return (0);
}
uintptr_t
ld_lib_setup(Ofl_desc *ofl)
{
char *path, *cp = NULL;
if (!(ofl->ofl_flags & FLG_OF_IGNENV)) {
#if defined(_ELF64)
if ((cp = getenv(MSG_ORIG(MSG_LD_LIBPATH_64))) == NULL)
#else
if ((cp = getenv(MSG_ORIG(MSG_LD_LIBPATH_32))) == NULL)
#endif
cp = getenv(MSG_ORIG(MSG_LD_LIBPATH));
}
if (cp && cp[0]) {
if ((path = libld_malloc(strlen(cp) + 1)) == NULL)
return (S_ERROR);
(void) strcpy(path, cp);
DBG_CALL(Dbg_libs_path(ofl->ofl_lml, path, LA_SER_DEFAULT, 0));
path = process_lib_path(ofl, &ofl->ofl_ulibdirs, path, FALSE);
if (path) {
Lidx = aplist_nitems(ofl->ofl_ulibdirs);
*path = '\0';
++path;
cp = process_lib_path(ofl, &ofl->ofl_ulibdirs, path,
FALSE);
if (cp == (char *)S_ERROR)
return (S_ERROR);
else if (cp)
ld_eprintf(ofl, ERR_WARNING,
MSG_INTL(MSG_LIB_MALFORM));
}
}
DBG_CALL(Dbg_libs_yp(ofl->ofl_lml, Plibpath));
cp = process_lib_path(ofl, &ofl->ofl_dlibdirs, Plibpath, TRUE);
if (cp == (char *)S_ERROR)
return (S_ERROR);
else if (cp) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_LIB_BADYP));
return (S_ERROR);
}
DBG_CALL(Dbg_libs_init(ofl->ofl_lml, ofl->ofl_ulibdirs,
ofl->ofl_dlibdirs));
return (1);
}