1 /*        $NetBSD: expand.c,v 1.8 2025/05/02 23:04:56 riastradh Exp $ */
2 
3 /*-
4  * Copyright (c) 2007 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Christos Zoulas.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 #include <sys/cdefs.h>
32 #ifndef lint
33 __RCSID("$NetBSD: expand.c,v 1.8 2025/05/02 23:04:56 riastradh Exp $");
34 #endif /* not lint */
35 
36 #include <ctype.h>
37 #include <string.h>
38 #include <sys/sysctl.h>
39 
40 #ifdef DEBUG_EXPAND
41 #include <stdio.h>
42 #include <err.h>
43 #define xwarn warn
44 #define xerr err
45 size_t _rtld_expand_path(char *, size_t, const char *, const char *,
46     const char *);
47 #else
48 #include <sys/stat.h>
49 #include "rtld.h"
50 #endif
51 
52 #include "../../lib/libc/include/__sysctl.h" /* __sysctl syscall stub */
53 
54 static const struct {
55           const char *name;
56           size_t namelen;
57 } bltn[] = {
58 #define ADD(a)      { #a, sizeof(#a) - 1 },
59           ADD(HWCAP)          /* SSE, MMX, etc */
60           ADD(ISALIST)        /* XXX */
61           ADD(ORIGIN)         /* dirname argv[0] */
62           ADD(OSNAME)         /* uname -s */
63           ADD(OSREL)          /* uname -r */
64           ADD(PLATFORM)       /* uname -p */
65 };
66 
67 static int mib[3][2] = {
68           { CTL_KERN, KERN_OSTYPE },
69           { CTL_KERN, KERN_OSRELEASE },
70           { CTL_HW, HW_MACHINE_ARCH },
71 };
72 
73 static size_t
expand(char * buf,const char * execname,size_t what,size_t bl)74 expand(char *buf, const char *execname, size_t what, size_t bl)
75 {
76           const char *p, *ep;
77           char *bp = buf;
78           size_t len;
79           char name[32];
80 
81           switch (what) {
82           case 0:   /* HWCAP XXX: Not yet */
83           case 1:   /* ISALIST XXX: Not yet */
84                     return 0;
85 
86           case 2:   /* ORIGIN */
87                     if (execname == NULL)
88                               xerr(1, "execname not specified in AUX vector");
89                     if ((ep = strrchr(p = execname, '/')) == NULL)
90                               xerr(1, "bad execname `%s' in AUX vector", execname);
91                     break;
92 
93           case 3:   /* OSNAME */
94           case 4:   /* OSREL */
95           case 5:   /* PLATFORM */
96                     len = sizeof(name);
97                     if (__sysctl(mib[what - 3], 2, name, &len, NULL, 0) == -1) {
98                               xwarn("sysctl");
99                               return 0;
100                     }
101                     ep = (p = name) + len - 1;
102                     break;
103           default:
104                     return 0;
105           }
106 
107           while (p != ep && bl)
108                     *bp++ = *p++, bl--;
109 
110           return bp - buf;
111 }
112 
113 
114 size_t
_rtld_expand_path(char * buf,size_t bufsize,const char * execname,const char * bp,const char * ep)115 _rtld_expand_path(char *buf, size_t bufsize, const char *execname,
116     const char *bp, const char *ep)
117 {
118           size_t i, ds = bufsize;
119           char *dp = buf;
120           const char *p;
121           int br;
122 
123           for (p = bp; p < ep;) {
124                     if (*p == '$') {
125                               br = *++p == '{';
126 
127                               if (br)
128                                         p++;
129 
130                               for (i = 0; i < sizeof(bltn) / sizeof(bltn[0]); i++) {
131                                         size_t s = bltn[i].namelen;
132                                         const char *es = p + s;
133 
134                                         if ((br && *es != '}') ||
135                                             (!br && (es != ep &&
136                                                   isalpha((unsigned char)*es))))
137                                                   continue;
138 
139                                         if (strncmp(bltn[i].name, p, s) == 0) {
140                                                   size_t ls = expand(dp, execname, i, ds);
141                                                   if (ls >= ds)
142                                                             return bufsize;
143                                                   ds -= ls;
144                                                   dp += ls;
145                                                   p = es + br;
146                                                   goto done;
147                                         }
148                               }
149                               p -= br + 1;
150 
151                     }
152                     *dp++ = *p++;
153                     ds--;
154 done:;
155           }
156           *dp = '\0';
157           return dp - buf;
158 }
159 
160 #ifdef DEBUG_EXPAND
161 int
main(int argc,char * argv[])162 main(int argc, char *argv[])
163 {
164           char buf[1024];
165           size_t i;
166 
167           for (i = 1; i < argc; i++) {
168                     char *p = argv[i], *ep = argv[i] + strlen(p);
169                     size_t n = _rtld_expand_path(buf, sizeof(buf), argv[0], p, ep);
170                     printf("%s\n", buf);
171           }
172           return 0;
173 }
174 #endif
175