aout2elf.c revision 1.2 1 1.2 martin /* $NetBSD: aout2elf.c,v 1.2 2019/06/12 06:20:17 martin Exp $
2 1.1 dholland *
3 1.1 dholland * Copyright 1997 Piermont Information Systems Inc.
4 1.1 dholland * All rights reserved.
5 1.1 dholland *
6 1.1 dholland * Written by Philip A. Nelson for Piermont Information Systems Inc.
7 1.1 dholland *
8 1.1 dholland * Redistribution and use in source and binary forms, with or without
9 1.1 dholland * modification, are permitted provided that the following conditions
10 1.1 dholland * are met:
11 1.1 dholland * 1. Redistributions of source code must retain the above copyright
12 1.1 dholland * notice, this list of conditions and the following disclaimer.
13 1.1 dholland * 2. Redistributions in binary form must reproduce the above copyright
14 1.1 dholland * notice, this list of conditions and the following disclaimer in the
15 1.1 dholland * documentation and/or other materials provided with the distribution.
16 1.1 dholland * 3. The name of Piermont Information Systems Inc. may not be used to endorse
17 1.1 dholland * or promote products derived from this software without specific prior
18 1.1 dholland * written permission.
19 1.1 dholland *
20 1.1 dholland * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
21 1.1 dholland * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 1.1 dholland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 1.1 dholland * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
24 1.1 dholland * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 1.1 dholland * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 1.1 dholland * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 1.1 dholland * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 1.1 dholland * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 1.1 dholland * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 1.1 dholland * THE POSSIBILITY OF SUCH DAMAGE.
31 1.1 dholland *
32 1.1 dholland */
33 1.1 dholland
34 1.1 dholland /* aout2elf.c -- routines for upgrading an a.out system to ELF */
35 1.1 dholland
36 1.1 dholland #include <sys/param.h>
37 1.1 dholland #include <sys/exec.h>
38 1.1 dholland #include <sys/exec_aout.h>
39 1.1 dholland #include <sys/stat.h>
40 1.1 dholland #include <fcntl.h>
41 1.1 dholland #include <unistd.h>
42 1.1 dholland #include <dirent.h>
43 1.1 dholland #include <errno.h>
44 1.1 dholland #include <stdio.h>
45 1.1 dholland #include <stdlib.h>
46 1.1 dholland #include <string.h>
47 1.1 dholland #include <err.h>
48 1.1 dholland
49 1.1 dholland #include "defs.h"
50 1.1 dholland #include "md.h"
51 1.1 dholland #include "msg_defs.h"
52 1.1 dholland #include "menu_defs.h"
53 1.1 dholland
54 1.1 dholland /* Local prototypes */
55 1.1 dholland static int is_aout_shared_lib(const char *name);
56 1.1 dholland static void handle_aout_x_libs(const char *srcdir, const char *tgtdir);
57 1.1 dholland static int handle_aout_libs(const char *dir, int op, const void *arg);
58 1.1 dholland static char *target_realpath(const char *, char *);
59 1.1 dholland
60 1.1 dholland #define LIB_COUNT 0
61 1.1 dholland #define LIB_MOVE 1
62 1.1 dholland
63 1.1 dholland /* XXX NAH. This probably needs moving to arch/<foo>/md.h
64 1.1 dholland *
65 1.1 dholland * a.out X libraries to move. These have not changed since 1.3.x
66 1.1 dholland */
67 1.1 dholland const char *x_libs[] = {
68 1.1 dholland "libICE.so.6.3",
69 1.1 dholland "libPEX5.so.6.0",
70 1.1 dholland "libSM.so.6.0",
71 1.1 dholland "libX11.so.6.1",
72 1.1 dholland "libXIE.so.6.0",
73 1.1 dholland "libXaw.so.6.1",
74 1.1 dholland "libXext.so.6.3",
75 1.1 dholland "libXi.so.6.0",
76 1.1 dholland "libXmu.so.6.0",
77 1.1 dholland "libXp.so.6.2",
78 1.1 dholland "libXt.so.6.0",
79 1.1 dholland "libXtst.so.6.1",
80 1.1 dholland "liboldX.so.6.0",
81 1.1 dholland };
82 1.1 dholland
83 1.1 dholland static int
84 1.1 dholland is_aout_shared_lib(const char *name)
85 1.1 dholland {
86 1.1 dholland struct exec ex;
87 1.1 dholland struct stat st;
88 1.1 dholland int fd;
89 1.1 dholland
90 1.1 dholland if (stat(name, &st) < 0)
91 1.1 dholland return 0;
92 1.1 dholland if ((st.st_mode & (S_IFREG|S_IFLNK)) == 0)
93 1.1 dholland return 0;
94 1.1 dholland
95 1.1 dholland fd = open(name, O_RDONLY);
96 1.1 dholland if (fd < 0) {
97 1.1 dholland return 0;
98 1.1 dholland }
99 1.1 dholland if (read(fd, &ex, sizeof ex) - sizeof ex != 0) {
100 1.1 dholland close(fd);
101 1.1 dholland return 0;
102 1.1 dholland }
103 1.1 dholland close(fd);
104 1.1 dholland if (N_GETMAGIC(ex) != ZMAGIC ||
105 1.1 dholland (N_GETFLAG(ex) & EX_DYNAMIC) == 0)
106 1.1 dholland return 0;
107 1.1 dholland
108 1.1 dholland return 1;
109 1.1 dholland }
110 1.1 dholland
111 1.1 dholland static void
112 1.1 dholland handle_aout_x_libs(const char *srcdir, const char *tgtdir)
113 1.1 dholland {
114 1.1 dholland char src[MAXPATHLEN];
115 1.1 dholland unsigned int i;
116 1.1 dholland
117 1.1 dholland for (i = 0; i < (sizeof x_libs / sizeof (const char *)); i++) {
118 1.1 dholland snprintf(src, MAXPATHLEN, "%s/%s", srcdir, x_libs[i]);
119 1.1 dholland if (!is_aout_shared_lib(src))
120 1.1 dholland continue;
121 1.1 dholland run_program(0, "mv -f %s %s", src, tgtdir);
122 1.1 dholland }
123 1.1 dholland
124 1.1 dholland /*
125 1.1 dholland * Don't care if it fails; X may not have been installed.
126 1.1 dholland */
127 1.1 dholland }
128 1.1 dholland
129 1.1 dholland /*
130 1.1 dholland * Function to count or move a.out shared libraries.
131 1.1 dholland */
132 1.1 dholland static int
133 1.1 dholland handle_aout_libs(const char *dir, int op, const void *arg)
134 1.1 dholland {
135 1.1 dholland DIR *dd;
136 1.1 dholland struct dirent *dp;
137 1.1 dholland char *full_name;
138 1.1 dholland const char *destdir = NULL; /* XXX -Wuninitialized [many] */
139 1.1 dholland int n;
140 1.1 dholland
141 1.1 dholland destdir = NULL; /* XXX gcc */
142 1.1 dholland
143 1.1 dholland dd = opendir(dir);
144 1.1 dholland if (dd == NULL)
145 1.1 dholland return -1;
146 1.1 dholland
147 1.1 dholland n = 0;
148 1.1 dholland
149 1.1 dholland switch (op) {
150 1.1 dholland case LIB_COUNT:
151 1.1 dholland break;
152 1.1 dholland case LIB_MOVE:
153 1.1 dholland destdir = (const char *)arg;
154 1.1 dholland break;
155 1.1 dholland default:
156 1.1 dholland return -1;
157 1.1 dholland }
158 1.1 dholland
159 1.1 dholland while ((dp = readdir(dd)) != NULL) {
160 1.1 dholland /*
161 1.1 dholland * strlen("libX.so")
162 1.1 dholland */
163 1.1 dholland if (dp->d_namlen < 7)
164 1.1 dholland continue;
165 1.1 dholland if (strncmp(dp->d_name, "lib", 3) != 0)
166 1.1 dholland continue;
167 1.1 dholland
168 1.1 dholland if (asprintf(&full_name, "%s/%s", dir, dp->d_name) == -1) {
169 1.1 dholland warn("Out of memory");
170 1.1 dholland continue;
171 1.1 dholland }
172 1.1 dholland
173 1.1 dholland if (!is_aout_shared_lib(full_name))
174 1.1 dholland goto endloop;
175 1.1 dholland
176 1.1 dholland switch (op) {
177 1.1 dholland case LIB_COUNT:
178 1.1 dholland n++;
179 1.1 dholland break;
180 1.1 dholland case LIB_MOVE:
181 1.1 dholland run_program(0, "mv -f %s %s/%s",
182 1.1 dholland full_name, destdir, dp->d_name);
183 1.1 dholland break;
184 1.1 dholland }
185 1.1 dholland
186 1.1 dholland endloop:
187 1.1 dholland free(full_name);
188 1.1 dholland }
189 1.1 dholland
190 1.1 dholland closedir(dd);
191 1.1 dholland
192 1.1 dholland return n;
193 1.1 dholland }
194 1.1 dholland
195 1.1 dholland __dead static void
196 1.1 dholland abort_libupdate(void)
197 1.1 dholland {
198 1.2 martin hit_enter_to_continue(MSG_aoutfail, NULL);
199 1.1 dholland exit(1);
200 1.1 dholland }
201 1.1 dholland
202 1.1 dholland int
203 1.1 dholland move_aout_libs(void)
204 1.1 dholland {
205 1.1 dholland int n, backedup = 0;
206 1.1 dholland char prefix[MAXPATHLEN], src[MAXPATHLEN];
207 1.1 dholland struct stat st;
208 1.1 dholland
209 1.1 dholland n = handle_aout_libs(target_expand("/usr/lib"), LIB_COUNT, NULL);
210 1.1 dholland if (n <= 0)
211 1.1 dholland return n;
212 1.1 dholland
213 1.1 dholland /*
214 1.1 dholland * See if /emul/aout already exists, taking symlinks into
215 1.1 dholland * account. If so, no need to create it, just use it.
216 1.1 dholland */
217 1.1 dholland if (target_realpath("/emul/aout", prefix) != NULL && stat(prefix, &st) == 0)
218 1.1 dholland goto domove;
219 1.1 dholland
220 1.1 dholland /*
221 1.1 dholland * See if /emul exists. If not, create it.
222 1.1 dholland */
223 1.1 dholland if (target_realpath("/emul", prefix) == NULL || stat(prefix, &st) < 0) {
224 1.1 dholland strlcpy(prefix, target_expand("/emul"), sizeof(prefix));
225 1.1 dholland if (lstat(prefix, &st) == 0) {
226 1.1 dholland run_program(0, "mv -f %s %s", prefix,
227 1.1 dholland target_expand("/emul.old"));
228 1.1 dholland backedup = 1;
229 1.1 dholland }
230 1.1 dholland scripting_fprintf(NULL, "mkdir %s\n", prefix);
231 1.1 dholland mkdir(prefix, 0755);
232 1.1 dholland }
233 1.1 dholland
234 1.1 dholland /*
235 1.1 dholland * Can use strcpy, target_expand has made sure it fits into
236 1.1 dholland * MAXPATHLEN. XXX all this copying is because concat_paths
237 1.1 dholland * returns a pointer to a static buffer.
238 1.1 dholland *
239 1.1 dholland * If an old aout link exists (apparently pointing to nowhere),
240 1.1 dholland * move it out of the way.
241 1.1 dholland */
242 1.1 dholland strlcpy(src, concat_paths(prefix, "aout"), sizeof(src));
243 1.1 dholland if (lstat(src, &st) == 0) {
244 1.1 dholland run_program(0, "mv -f %s %s", src,
245 1.1 dholland concat_paths(prefix, "aout.old"));
246 1.1 dholland backedup = 1;
247 1.1 dholland }
248 1.1 dholland
249 1.1 dholland /*
250 1.1 dholland * We have created /emul if needed. Since no previous /emul/aout
251 1.1 dholland * existed, we'll use a symbolic link in /emul to /usr/aout, to
252 1.1 dholland * avoid overflowing the root partition.
253 1.1 dholland */
254 1.1 dholland strlcpy(prefix, target_expand("/usr/aout"), sizeof(prefix));
255 1.1 dholland if (run_program(0, "mkdir -p %s", prefix))
256 1.1 dholland abort_libupdate();
257 1.1 dholland if (run_program(0, "ln -s %s %s", "/usr/aout", src))
258 1.1 dholland abort_libupdate();
259 1.1 dholland
260 1.1 dholland domove:
261 1.1 dholland /*
262 1.1 dholland * Rename etc and usr/lib if they already existed, so that we
263 1.1 dholland * do not overwrite old files.
264 1.1 dholland *
265 1.1 dholland * Then, move /etc/ld.so.conf to /emul/aout/etc/ld.so.conf,
266 1.1 dholland * and all a.out dynamic libraries from /usr/lib to
267 1.1 dholland * /emul/aout/usr/lib. This is where the a.out code in ldconfig
268 1.1 dholland * and ld.so respectively will find them.
269 1.1 dholland */
270 1.1 dholland strlcpy(src, concat_paths(prefix, "usr/lib"), sizeof(src));
271 1.1 dholland run_program(0, "mv -f %s %s", src, concat_paths(prefix, "usr/lib.old"));
272 1.1 dholland strlcpy(src, concat_paths(prefix, "etc/ld.so.conf"), sizeof(src));
273 1.1 dholland run_program(0, "mv -f %s %s",
274 1.1 dholland src, concat_paths(prefix, "etc/ld.so.conf.old"));
275 1.1 dholland if (run_program(0, "mkdir -p %s ", concat_paths(prefix, "usr/lib")))
276 1.1 dholland abort_libupdate();
277 1.1 dholland if (run_program(0, "mkdir -p %s ", concat_paths(prefix, "etc")))
278 1.1 dholland abort_libupdate();
279 1.1 dholland
280 1.1 dholland strlcpy(src, target_expand("/etc/ld.so.conf"), sizeof(src));
281 1.1 dholland if (run_program(0, "mv -f %s %s",
282 1.1 dholland src, concat_paths(prefix, "etc/ld.so.conf")))
283 1.1 dholland abort_libupdate();
284 1.1 dholland
285 1.1 dholland strlcpy(src, target_expand("/usr/lib"), sizeof(src));
286 1.1 dholland n = handle_aout_libs(src, LIB_MOVE, concat_paths(prefix, "usr/lib"));
287 1.1 dholland
288 1.1 dholland if (run_program(0, "mkdir -p %s ",
289 1.1 dholland concat_paths(prefix, "usr/X11R6/lib")))
290 1.1 dholland abort_libupdate();
291 1.1 dholland
292 1.1 dholland strlcpy(src, target_expand("/usr/X11R6/lib"), sizeof(src));
293 1.1 dholland handle_aout_x_libs(src, concat_paths(prefix, "usr/X11R6/lib"));
294 1.1 dholland
295 1.1 dholland if (backedup) {
296 1.2 martin hit_enter_to_continue(MSG_emulbackup, NULL);
297 1.1 dholland }
298 1.1 dholland
299 1.1 dholland return n;
300 1.1 dholland }
301 1.1 dholland
302 1.1 dholland /*
303 1.1 dholland * XXXX had to include this to deal with symlinks in some places.
304 1.1 dholland * When the target * disk is mounted under /targetroot, absolute symlinks
305 1.1 dholland * on it don't work right.
306 1.1 dholland * This function will resolve them using the mountpoint as prefix.
307 1.1 dholland * Copied verbatim from libc, with added prefix handling.
308 1.1 dholland *
309 1.1 dholland * char *realpath(const char *path, char resolved_path[MAXPATHLEN]);
310 1.1 dholland *
311 1.1 dholland * Find the real name of path, by removing all ".", ".." and symlink
312 1.1 dholland * components. Returns (resolved) on success, or (NULL) on failure,
313 1.1 dholland * in which case the path which caused trouble is left in (resolved).
314 1.1 dholland */
315 1.1 dholland static char *
316 1.1 dholland target_realpath(const char *path, char *resolved)
317 1.1 dholland {
318 1.1 dholland struct stat sb;
319 1.1 dholland int fd, n, rootd, serrno, nlnk = 0;
320 1.1 dholland char *p, *q, wbuf[MAXPATHLEN];
321 1.1 dholland char solidus[2], empty[1];
322 1.1 dholland solidus[0] = '/';
323 1.1 dholland solidus[1] = '\0';
324 1.1 dholland empty[0] = '\0';
325 1.1 dholland
326 1.1 dholland /* Save the starting point. */
327 1.1 dholland if ((fd = open(".", O_RDONLY)) < 0) {
328 1.1 dholland (void)strlcpy(resolved, ".", MAXPATHLEN);
329 1.1 dholland return (NULL);
330 1.1 dholland }
331 1.1 dholland
332 1.1 dholland /*
333 1.1 dholland * Find the dirname and basename from the path to be resolved.
334 1.1 dholland * Change directory to the dirname component.
335 1.1 dholland * lstat the basename part.
336 1.1 dholland * if it is a symlink, read in the value and loop.
337 1.1 dholland * if it is a directory, then change to that directory.
338 1.1 dholland * get the current directory name and append the basename.
339 1.1 dholland */
340 1.1 dholland if (target_prefix() != NULL && strcmp(target_prefix(), "") != 0)
341 1.1 dholland snprintf(resolved, MAXPATHLEN, "%s/%s", target_prefix(), path);
342 1.1 dholland else
343 1.1 dholland if (strlcpy(resolved, path, MAXPATHLEN) >= MAXPATHLEN) {
344 1.1 dholland errno = ENAMETOOLONG;
345 1.1 dholland goto err1;
346 1.1 dholland }
347 1.1 dholland loop:
348 1.1 dholland q = strrchr(resolved, '/');
349 1.1 dholland if (q != NULL) {
350 1.1 dholland p = q + 1;
351 1.1 dholland if (q == resolved)
352 1.1 dholland q = solidus;
353 1.1 dholland else {
354 1.1 dholland do {
355 1.1 dholland --q;
356 1.1 dholland } while (q > resolved && *q == '/');
357 1.1 dholland q[1] = '\0';
358 1.1 dholland q = resolved;
359 1.1 dholland }
360 1.1 dholland if (chdir(q) < 0)
361 1.1 dholland goto err1;
362 1.1 dholland } else
363 1.1 dholland p = resolved;
364 1.1 dholland
365 1.1 dholland /* Deal with the last component. */
366 1.1 dholland if (lstat(p, &sb) == 0) {
367 1.1 dholland if (S_ISLNK(sb.st_mode)) {
368 1.1 dholland if (nlnk++ >= MAXSYMLINKS) {
369 1.1 dholland errno = ELOOP;
370 1.1 dholland goto err1;
371 1.1 dholland }
372 1.1 dholland n = readlink(p, wbuf, MAXPATHLEN - 1);
373 1.1 dholland if (n < 0)
374 1.1 dholland goto err1;
375 1.1 dholland wbuf[n] = '\0';
376 1.1 dholland if (wbuf[0] == '/')
377 1.1 dholland snprintf(resolved, MAXPATHLEN, "%s%s",
378 1.1 dholland target_prefix(), wbuf);
379 1.1 dholland else
380 1.1 dholland strlcpy(resolved, wbuf, MAXPATHLEN);
381 1.1 dholland goto loop;
382 1.1 dholland }
383 1.1 dholland if (S_ISDIR(sb.st_mode)) {
384 1.1 dholland if (chdir(p) < 0)
385 1.1 dholland goto err1;
386 1.1 dholland p = empty;
387 1.1 dholland }
388 1.1 dholland }
389 1.1 dholland
390 1.1 dholland /*
391 1.1 dholland * Save the last component name and get the full pathname of
392 1.1 dholland * the current directory.
393 1.1 dholland */
394 1.1 dholland if (strlcpy(wbuf, p, sizeof(wbuf)) >= sizeof(wbuf)) {
395 1.1 dholland errno = ENAMETOOLONG;
396 1.1 dholland goto err1;
397 1.1 dholland }
398 1.1 dholland
399 1.1 dholland /*
400 1.1 dholland * Call the internal internal version of getcwd which
401 1.1 dholland * does a physical search rather than using the $PWD short-cut
402 1.1 dholland */
403 1.1 dholland if (getcwd(resolved, MAXPATHLEN) == 0)
404 1.1 dholland goto err1;
405 1.1 dholland
406 1.1 dholland /*
407 1.1 dholland * Join the two strings together, ensuring that the right thing
408 1.1 dholland * happens if the last component is empty, or the dirname is root.
409 1.1 dholland */
410 1.1 dholland if (resolved[0] == '/' && resolved[1] == '\0')
411 1.1 dholland rootd = 1;
412 1.1 dholland else
413 1.1 dholland rootd = 0;
414 1.1 dholland
415 1.1 dholland if (*wbuf) {
416 1.1 dholland if (strlen(resolved) + strlen(wbuf) + (rootd ? 0 : 1) + 1 >
417 1.1 dholland MAXPATHLEN) {
418 1.1 dholland errno = ENAMETOOLONG;
419 1.1 dholland goto err1;
420 1.1 dholland }
421 1.1 dholland if (rootd == 0)
422 1.1 dholland if (strlcat(resolved, "/", MAXPATHLEN) >= MAXPATHLEN) {
423 1.1 dholland errno = ENAMETOOLONG;
424 1.1 dholland goto err1;
425 1.1 dholland }
426 1.1 dholland if (strlcat(resolved, wbuf, MAXPATHLEN) >= MAXPATHLEN) {
427 1.1 dholland errno = ENAMETOOLONG;
428 1.1 dholland goto err1;
429 1.1 dholland }
430 1.1 dholland }
431 1.1 dholland
432 1.1 dholland /* Go back to where we came from. */
433 1.1 dholland if (fchdir(fd) < 0) {
434 1.1 dholland serrno = errno;
435 1.1 dholland goto err2;
436 1.1 dholland }
437 1.1 dholland
438 1.1 dholland /* It's okay if the close fails, what's an fd more or less? */
439 1.1 dholland (void)close(fd);
440 1.1 dholland return (resolved);
441 1.1 dholland
442 1.1 dholland err1: serrno = errno;
443 1.1 dholland (void)fchdir(fd);
444 1.1 dholland err2: (void)close(fd);
445 1.1 dholland errno = serrno;
446 1.1 dholland return (NULL);
447 1.1 dholland }
448