xref: /netbsd-src/libexec/ld.elf_so/expand.c (revision 6f661f3b8ef0440f9df81d6aa401ab5a0685f003)
1*6f661f3bSchristos /*	$NetBSD: expand.c,v 1.7 2023/01/04 01:37:00 christos Exp $	*/
204ee85adSchristos 
304ee85adSchristos /*-
404ee85adSchristos  * Copyright (c) 2007 The NetBSD Foundation, Inc.
504ee85adSchristos  * All rights reserved.
604ee85adSchristos  *
704ee85adSchristos  * This code is derived from software contributed to The NetBSD Foundation
804ee85adSchristos  * by Christos Zoulas.
904ee85adSchristos  *
1004ee85adSchristos  * Redistribution and use in source and binary forms, with or without
1104ee85adSchristos  * modification, are permitted provided that the following conditions
1204ee85adSchristos  * are met:
1304ee85adSchristos  * 1. Redistributions of source code must retain the above copyright
1404ee85adSchristos  *    notice, this list of conditions and the following disclaimer.
1504ee85adSchristos  * 2. Redistributions in binary form must reproduce the above copyright
1604ee85adSchristos  *    notice, this list of conditions and the following disclaimer in the
1704ee85adSchristos  *    documentation and/or other materials provided with the distribution.
1804ee85adSchristos  *
1904ee85adSchristos  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2004ee85adSchristos  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2104ee85adSchristos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2204ee85adSchristos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2304ee85adSchristos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2404ee85adSchristos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2504ee85adSchristos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2604ee85adSchristos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2704ee85adSchristos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2804ee85adSchristos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2904ee85adSchristos  * POSSIBILITY OF SUCH DAMAGE.
3004ee85adSchristos  */
3104ee85adSchristos #include <sys/cdefs.h>
3204ee85adSchristos #ifndef lint
33*6f661f3bSchristos __RCSID("$NetBSD: expand.c,v 1.7 2023/01/04 01:37:00 christos Exp $");
3404ee85adSchristos #endif /* not lint */
3504ee85adSchristos 
3604ee85adSchristos #include <ctype.h>
3704ee85adSchristos #include <string.h>
3804ee85adSchristos #include <sys/sysctl.h>
3904ee85adSchristos 
4004ee85adSchristos #ifdef DEBUG_EXPAND
4104ee85adSchristos #include <stdio.h>
4204ee85adSchristos #include <err.h>
4304ee85adSchristos #define xwarn warn
446eac1155Schristos #define xerr err
4504ee85adSchristos size_t _rtld_expand_path(char *, size_t, const char *, const char *,
4604ee85adSchristos     const char *);
4704ee85adSchristos #else
4804ee85adSchristos #include <sys/stat.h>
4904ee85adSchristos #include "rtld.h"
5004ee85adSchristos #endif
5104ee85adSchristos 
5204ee85adSchristos static const struct {
5304ee85adSchristos 	const char *name;
5404ee85adSchristos 	size_t namelen;
5504ee85adSchristos } bltn[] = {
5604ee85adSchristos #define ADD(a)	{ #a, sizeof(#a) - 1 },
5704ee85adSchristos 	ADD(HWCAP)	/* SSE, MMX, etc */
583b320420Schristos 	ADD(ISALIST)	/* XXX */
5904ee85adSchristos 	ADD(ORIGIN) 	/* dirname argv[0] */
6004ee85adSchristos 	ADD(OSNAME)	/* uname -s */
6104ee85adSchristos 	ADD(OSREL)	/* uname -r */
623b320420Schristos 	ADD(PLATFORM)	/* uname -p */
6304ee85adSchristos };
6404ee85adSchristos 
6504ee85adSchristos static int mib[3][2] = {
6604ee85adSchristos 	{ CTL_KERN, KERN_OSTYPE },
6704ee85adSchristos 	{ CTL_KERN, KERN_OSRELEASE },
6804ee85adSchristos 	{ CTL_HW, HW_MACHINE_ARCH },
6904ee85adSchristos };
7004ee85adSchristos 
7104ee85adSchristos static size_t
expand(char * buf,const char * execname,size_t what,size_t bl)72*6f661f3bSchristos expand(char *buf, const char *execname, size_t what, size_t bl)
7304ee85adSchristos {
7404ee85adSchristos 	const char *p, *ep;
7504ee85adSchristos 	char *bp = buf;
7604ee85adSchristos 	size_t len;
7704ee85adSchristos 	char name[32];
7804ee85adSchristos 
7904ee85adSchristos 	switch (what) {
8004ee85adSchristos 	case 0:	/* HWCAP XXX: Not yet */
8104ee85adSchristos 	case 1:	/* ISALIST XXX: Not yet */
8204ee85adSchristos 		return 0;
8304ee85adSchristos 
8404ee85adSchristos 	case 2:	/* ORIGIN */
8540cfdb5eSchristos 		if (execname == NULL)
8640cfdb5eSchristos 			xerr(1, "execname not specified in AUX vector");
8740cfdb5eSchristos 		if ((ep = strrchr(p = execname, '/')) == NULL)
8840cfdb5eSchristos 			xerr(1, "bad execname `%s' in AUX vector", execname);
8904ee85adSchristos 		break;
9004ee85adSchristos 
9104ee85adSchristos 	case 3:	/* OSNAME */
9204ee85adSchristos 	case 4:	/* OSREL */
9304ee85adSchristos 	case 5:	/* PLATFORM */
9404ee85adSchristos 		len = sizeof(name);
9504ee85adSchristos 		if (sysctl(mib[what - 3], 2, name, &len, NULL, 0) == -1) {
9604ee85adSchristos 			xwarn("sysctl");
9704ee85adSchristos 			return 0;
9804ee85adSchristos 		}
9904ee85adSchristos 		ep = (p = name) + len - 1;
10004ee85adSchristos 		break;
10104ee85adSchristos 	default:
10204ee85adSchristos 		return 0;
10304ee85adSchristos 	}
10404ee85adSchristos 
10504ee85adSchristos 	while (p != ep && bl)
10604ee85adSchristos 		*bp++ = *p++, bl--;
10704ee85adSchristos 
10804ee85adSchristos 	return bp - buf;
10904ee85adSchristos }
11004ee85adSchristos 
11104ee85adSchristos 
11204ee85adSchristos size_t
_rtld_expand_path(char * buf,size_t bufsize,const char * execname,const char * bp,const char * ep)11340cfdb5eSchristos _rtld_expand_path(char *buf, size_t bufsize, const char *execname,
11440cfdb5eSchristos     const char *bp, const char *ep)
11504ee85adSchristos {
11604ee85adSchristos 	size_t i, ds = bufsize;
11704ee85adSchristos 	char *dp = buf;
11804ee85adSchristos 	const char *p;
11904ee85adSchristos 	int br;
12004ee85adSchristos 
12104ee85adSchristos 	for (p = bp; p < ep;) {
12204ee85adSchristos 		if (*p == '$') {
12304ee85adSchristos 			br = *++p == '{';
12404ee85adSchristos 
12504ee85adSchristos 			if (br)
12604ee85adSchristos 				p++;
12704ee85adSchristos 
12804ee85adSchristos 			for (i = 0; i < sizeof(bltn) / sizeof(bltn[0]); i++) {
12904ee85adSchristos 				size_t s = bltn[i].namelen;
13004ee85adSchristos 				const char *es = p + s;
13104ee85adSchristos 
13204ee85adSchristos 				if ((br && *es != '}') ||
13304ee85adSchristos 				    (!br && (es != ep &&
13404ee85adSchristos 					isalpha((unsigned char)*es))))
13504ee85adSchristos 					continue;
13604ee85adSchristos 
13704ee85adSchristos 				if (strncmp(bltn[i].name, p, s) == 0) {
13840cfdb5eSchristos 					size_t ls = expand(dp, execname, i, ds);
13904ee85adSchristos 					if (ls >= ds)
14004ee85adSchristos 						return bufsize;
14104ee85adSchristos 					ds -= ls;
14204ee85adSchristos 					dp += ls;
14304ee85adSchristos 					p = es + br;
14404ee85adSchristos 					goto done;
14504ee85adSchristos 				}
14604ee85adSchristos 			}
14704ee85adSchristos 			p -= br + 1;
14804ee85adSchristos 
14904ee85adSchristos 		}
15004ee85adSchristos 		*dp++ = *p++;
15104ee85adSchristos 		ds--;
15204ee85adSchristos done:;
15304ee85adSchristos 	}
15404ee85adSchristos 	*dp = '\0';
15504ee85adSchristos 	return dp - buf;
15604ee85adSchristos }
15704ee85adSchristos 
15804ee85adSchristos #ifdef DEBUG_EXPAND
15904ee85adSchristos int
main(int argc,char * argv[])16004ee85adSchristos main(int argc, char *argv[])
16104ee85adSchristos {
16204ee85adSchristos 	char buf[1024];
16304ee85adSchristos 	size_t i;
16404ee85adSchristos 
16504ee85adSchristos 	for (i = 1; i < argc; i++) {
16604ee85adSchristos 		char *p = argv[i], *ep = argv[i] + strlen(p);
16704ee85adSchristos 		size_t n = _rtld_expand_path(buf, sizeof(buf), argv[0], p, ep);
16804ee85adSchristos 		printf("%s\n", buf);
16904ee85adSchristos 	}
17004ee85adSchristos 	return 0;
17104ee85adSchristos }
17204ee85adSchristos #endif
173