Blame src/core/lt_path.c

47891e
/*******************************************************************/
47891e
/*  sltdl: a surrogate ltdl implementation                         */
47891e
/*  Copyright (C) 2019 Z. Gilboa                                   */
47891e
/*  Released under the Standard MIT License; see COPYING.SLTDL.    */
47891e
/*******************************************************************/
47891e
47891e
#include <limits.h>
bb0941
#include <fcntl.h>
47891e
#include <stdio.h>
47891e
#include <stdlib.h>
47891e
#include <string.h>
bb0941
#include <unistd.h>
47891e
#include <pthread.h>
47891e
#include <sltdl/sltdl.h>
47891e
#include "sltdl_core.h"
47891e
47891e
static off_t   lt_plen;
47891e
static off_t   lt_plocs;
47891e
static char *  lt_upath;
47891e
static char *  lt_vpath;
47891e
static char ** lt_vmark;
47891e
static char ** lt_pathv;
47891e
47891e
const char * lt_dlgetsearchpath(void)
47891e
{
47891e
	return lt_upath;
47891e
}
47891e
47891e
static int lt_dlsetsearchpath_locked(const char * path)
47891e
{
47891e
	const char *    ch;
47891e
	char *          uch;
47891e
	char *          vch;
47891e
	char **         pathv;
47891e
	off_t           elements;
47891e
47891e
	if (path[0] != '/')
47891e
		return 1;
47891e
47891e
	elements = 1;
47891e
47891e
	for (ch=&path[1]; *ch; ch++) {
47891e
		if (*ch == ':') {
47891e
			if (ch[1] != '/')
47891e
				return 1;
47891e
47891e
			elements++;
47891e
		}
47891e
	}
47891e
47891e
	if (++elements > lt_plocs) {
47891e
		if (lt_pathv) {
47891e
			free(lt_pathv);
47891e
			lt_pathv = 0;
47891e
		}
47891e
47891e
		lt_plocs  = elements;
47891e
		lt_plocs += 0x3f;
47891e
		lt_plocs |= 0x3f;
47891e
		lt_plocs ^= 0x3f;
47891e
47891e
		if (!(lt_pathv = calloc(lt_plocs,sizeof(char *))))
47891e
			return 1;
47891e
	}
47891e
47891e
	if ((ch - path) > lt_plen) {
47891e
		if (lt_upath) {
47891e
			free(lt_upath);
47891e
			lt_upath = 0;
47891e
		}
47891e
47891e
		lt_plen = ((ch - path + 1) <= 0x800)
47891e
			? 0x800 : ch - path + 1;
47891e
47891e
		lt_plen += 0x7ff;
47891e
		lt_plen |= 0x7ff;
47891e
		lt_plen ^= 0x7ff;
47891e
47891e
		if (!(lt_upath = calloc(2*lt_plen,1)))
47891e
			return 1;
47891e
47891e
		lt_vpath = &lt_upath[lt_plen];
47891e
	}
47891e
47891e
	pathv    = lt_pathv;
47891e
	*pathv++ = lt_vpath;
47891e
47891e
	for (ch=path, uch=lt_upath, vch=lt_vpath; *ch; ch++) {
47891e
		if (*ch == ':') {
47891e
			*uch++ = ch[0];
47891e
			*uch++ = ch[1];
47891e
47891e
			*vch++ = 0;
47891e
			*pathv = vch;
47891e
			*vch++ = ch[1];
47891e
47891e
			ch++;
47891e
			pathv++;
47891e
		} else {
47891e
			*uch++ = *ch;
47891e
			*vch++ = *ch;
47891e
		}
47891e
	}
47891e
47891e
	lt_vmark = pathv;
47891e
47891e
	return 0;
47891e
}
47891e
47891e
int lt_dlsetsearchpath(const char * path)
47891e
{
47891e
	lt_slock();
47891e
	return lt_sunlock(lt_dlsetsearchpath_locked(path));
47891e
}
47891e
47891e
int lt_dladdsearchdir(const char * path)
47891e
{
47891e
	int          ret;
47891e
	const char * ch;
47891e
	char *       buf;
47891e
	off_t        alen;
47891e
	off_t        plen;
47891e
47891e
	if (path[0] != '/')
47891e
		return 1;
47891e
47891e
	for (ch=path; *ch; ch++)
47891e
		if (*ch == ':')
47891e
			return 1;
47891e
47891e
	lt_slock();
47891e
47891e
	alen = strlen(path);
47891e
	plen = strlen(lt_upath);
47891e
47891e
	/* no allocation needed? */
47891e
	if (!lt_pathv[lt_plocs - 2] && ((plen + 1 + alen + 1) <= lt_plen)) {
47891e
		lt_upath[plen] = ':';
47891e
		lt_vpath[plen] = 0;
47891e
47891e
		plen++;
47891e
47891e
		strcpy(&lt_upath[plen],path);
47891e
		strcpy(&lt_vpath[plen],path);
47891e
47891e
		*lt_vmark++ = &lt_vpath[plen];
47891e
47891e
		return lt_sunlock(0);
47891e
	}
47891e
47891e
	/* (allocation needed) */
47891e
	if (!(buf = malloc(plen + 1 + alen + 1)))
47891e
		return lt_sunlock(1);
47891e
47891e
	sprintf(buf,"%s:%s",lt_upath,path);
47891e
47891e
	ret = lt_dlsetsearchpath_locked(buf);
47891e
47891e
	free(buf);
47891e
47891e
	return lt_sunlock(ret);
47891e
}
47891e
47891e
int lt_dlinsertsearchdir(const char * mark, const char * path)
47891e
{
47891e
	int          ret;
47891e
	const char * ch;
47891e
	char *       buf;
47891e
	char *       dst;
47891e
	off_t        alen;
47891e
	off_t        plen;
47891e
	off_t        slen;
47891e
	off_t        offset;
47891e
	char **      pathv;
47891e
47891e
	if (path[0] != '/')
47891e
		return 1;
47891e
47891e
	if (!mark)
47891e
		return lt_dladdsearchdir(path);
47891e
47891e
	for (ch=path; *ch; ch++)
47891e
		if (*ch == ':')
47891e
			return 1;
47891e
47891e
	lt_slock();
47891e
47891e
	alen = strlen(path);
47891e
	plen = strlen(lt_upath);
47891e
47891e
	if ((mark < lt_upath) || (mark >= &lt_upath[plen]))
47891e
		return lt_sunlock(1);
47891e
47891e
	if ((mark > lt_upath) && (mark[-1] != ':'))
47891e
		return lt_sunlock(1);
47891e
47891e
	mark = &lt_vpath[mark - lt_upath];
47891e
47891e
	/* no allocation needed? */
47891e
	if (!lt_pathv[lt_plocs - 2] && ((plen + 1 + alen + 1) <= lt_plen)) {
47891e
		for (pathv=lt_vmark; pathv>=lt_pathv; pathv--) {
47891e
			slen    = strlen(pathv[-1]);
47891e
			offset  = pathv[-1] - lt_vpath;
47891e
			offset += alen + 1;
47891e
47891e
			memcpy(&lt_upath[offset],pathv[-1],slen);
47891e
			memcpy(&lt_vpath[offset],&lt_upath[offset],slen);
47891e
47891e
			if (pathv < lt_vmark)
47891e
				lt_upath[offset + slen] = ':';
47891e
76a627
			pathv[0] = pathv[-1] + alen + 1;
47891e
47891e
			if (pathv[-1] == mark) {
47891e
				offset = mark - lt_vpath;
47891e
				strcpy(&lt_vpath[offset],path);
47891e
				memcpy(&lt_upath[offset],path,alen);
47891e
				lt_upath[offset+alen] = ':';
47891e
				lt_vmark++;
47891e
				return lt_sunlock(0);
47891e
			}
47891e
		}
47891e
	}
47891e
47891e
	/* (allocation needed) */
47891e
	if (!(buf = malloc(plen + 1 + alen + 1)))
47891e
		return lt_sunlock(1);
47891e
47891e
	for (dst=buf, pathv=lt_pathv; *pathv; pathv++) {
47891e
		if (*pathv == mark)
47891e
			dst += sprintf(dst,"%s:",path);
47891e
47891e
		if (pathv[1])
47891e
			dst += sprintf(dst,"%s:",*pathv);
47891e
		else
47891e
			dst += sprintf(dst,"%s",*pathv);
47891e
	}
47891e
47891e
	ret = lt_dlsetsearchpath_locked(buf);
47891e
47891e
	free(buf);
47891e
47891e
	return lt_sunlock(ret);
47891e
}
bb0941
bb0941
int lt_dlpathopen(const char * module, const char ** extv)
bb0941
{
bb0941
	int           fdat;
bb0941
	int           fdmod;
bb0941
	char **       ppath;
bb0941
	const char ** pext;
bb0941
	size_t        mlen;
bb0941
	size_t        elen;
bb0941
	char          path[1024];
bb0941
bb0941
	if ((mlen = strlen(module)) >= sizeof(path))
bb0941
		return -1;
bb0941
bb0941
	memcpy(path,module,mlen);
bb0941
bb0941
	lt_slock();
bb0941
bb0941
	for (ppath=lt_pathv; *ppath; ppath++) {
bb0941
		fdat = open(*ppath,O_RDONLY|O_DIRECTORY|O_CLOEXEC,0);
bb0941
bb0941
		if (fdat >= 0) {
bb0941
			for (pext=extv; *pext; pext++) {
bb0941
				if (mlen + (elen = strlen(*pext)) >= (sizeof(path))) {
bb0941
					close(fdat);
bb0941
					return (-1);
bb0941
				}
bb0941
bb0941
				memcpy(&path[mlen],*pext,elen);
bb0941
				path[mlen+elen] = 0;
bb0941
bb0941
				fdmod = openat(fdat,path,O_EXEC|O_CLOEXEC,0);
bb0941
bb0941
				if (fdmod >= 0) {
bb0941
					close(fdat);
bb0941
					return lt_sunlock(fdmod);
bb0941
				}
bb0941
			}
bb0941
bb0941
			close(fdat);
bb0941
		}
bb0941
	}
bb0941
bb0941
	return lt_sunlock(-1);
bb0941
}