1 /* $NetBSD: aout2elf.c,v 1.14 2009/08/16 17:12:48 pgoyette Exp $
3 * Copyright 1997 Piermont Information Systems Inc.
6 * Written by Philip A. Nelson for Piermont Information Systems Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed for the NetBSD Project by
19 * Piermont Information Systems Inc.
20 * 4. The name of Piermont Information Systems Inc. may not be used to endorse
21 * or promote products derived from this software without specific prior
24 * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
34 * THE POSSIBILITY OF SUCH DAMAGE.
38 /* aout2elf.c -- routines for upgrading an a.out system to ELF */
40 #include <sys/param.h>
42 #include <sys/exec_aout.h>
56 #include "menu_defs.h"
58 /* Local prototypes */
59 static int is_aout_shared_lib(const char *name
);
60 static void handle_aout_x_libs(const char *srcdir
, const char *tgtdir
);
61 static int handle_aout_libs(const char *dir
, int op
, const void *arg
);
62 static char *target_realpath(const char *, char *);
67 /* XXX NAH. This probably needs moving to arch/<foo>/md.h
69 * a.out X libraries to move. These have not changed since 1.3.x
71 const char *x_libs
[] = {
88 is_aout_shared_lib(const char *name
)
94 if (stat(name
, &st
) < 0)
96 if ((st
.st_mode
& (S_IFREG
|S_IFLNK
)) == 0)
99 fd
= open(name
, O_RDONLY
);
103 if (read(fd
, &ex
, sizeof ex
) - sizeof ex
!= 0) {
108 if (N_GETMAGIC(ex
) != ZMAGIC
||
109 (N_GETFLAG(ex
) & EX_DYNAMIC
) == 0)
116 handle_aout_x_libs(const char *srcdir
, const char *tgtdir
)
118 char src
[MAXPATHLEN
];
121 for (i
= 0; i
< (sizeof x_libs
/ sizeof (const char *)); i
++) {
122 snprintf(src
, MAXPATHLEN
, "%s/%s", srcdir
, x_libs
[i
]);
123 if (!is_aout_shared_lib(src
))
125 run_program(0, "mv -f %s %s", src
, tgtdir
);
129 * Don't care if it fails; X may not have been installed.
134 * Function to count or move a.out shared libraries.
137 handle_aout_libs(const char *dir
, int op
, const void *arg
)
142 const char *destdir
= NULL
; /* XXX -Wuninitialized [many] */
145 destdir
= NULL
; /* XXX gcc */
157 destdir
= (const char *)arg
;
163 while ((dp
= readdir(dd
)) != NULL
) {
167 if (dp
->d_namlen
< 7)
169 if (strncmp(dp
->d_name
, "lib", 3) != 0)
172 if (asprintf(&full_name
, "%s/%s", dir
, dp
->d_name
) == -1) {
173 warn("Out of memory");
177 if (!is_aout_shared_lib(full_name
))
185 run_program(0, "mv -f %s %s/%s",
186 full_name
, destdir
, dp
->d_name
);
200 abort_libupdate(void)
202 msg_display(MSG_aoutfail
);
203 process_menu(MENU_ok
, NULL
);
211 char prefix
[MAXPATHLEN
], src
[MAXPATHLEN
];
214 n
= handle_aout_libs(target_expand("/usr/lib"), LIB_COUNT
, NULL
);
219 * See if /emul/aout already exists, taking symlinks into
220 * account. If so, no need to create it, just use it.
222 if (target_realpath("/emul/aout", prefix
) != NULL
&& stat(prefix
, &st
) == 0)
226 * See if /emul exists. If not, create it.
228 if (target_realpath("/emul", prefix
) == NULL
|| stat(prefix
, &st
) < 0) {
229 strlcpy(prefix
, target_expand("/emul"), sizeof(prefix
));
230 if (lstat(prefix
, &st
) == 0) {
231 run_program(0, "mv -f %s %s", prefix
,
232 target_expand("/emul.old"));
235 scripting_fprintf(NULL
, "mkdir %s\n", prefix
);
240 * Can use strcpy, target_expand has made sure it fits into
241 * MAXPATHLEN. XXX all this copying is because concat_paths
242 * returns a pointer to a static buffer.
244 * If an old aout link exists (apparently pointing to nowhere),
245 * move it out of the way.
247 strlcpy(src
, concat_paths(prefix
, "aout"), sizeof(src
));
248 if (lstat(src
, &st
) == 0) {
249 run_program(0, "mv -f %s %s", src
,
250 concat_paths(prefix
, "aout.old"));
255 * We have created /emul if needed. Since no previous /emul/aout
256 * existed, we'll use a symbolic link in /emul to /usr/aout, to
257 * avoid overflowing the root partition.
259 strlcpy(prefix
, target_expand("/usr/aout"), sizeof(prefix
));
260 if (run_program(0, "mkdir -p %s", prefix
))
262 if (run_program(0, "ln -s %s %s", "/usr/aout", src
))
267 * Rename etc and usr/lib if they already existed, so that we
268 * do not overwrite old files.
270 * Then, move /etc/ld.so.conf to /emul/aout/etc/ld.so.conf,
271 * and all a.out dynamic libraries from /usr/lib to
272 * /emul/aout/usr/lib. This is where the a.out code in ldconfig
273 * and ld.so respectively will find them.
275 strlcpy(src
, concat_paths(prefix
, "usr/lib"), sizeof(src
));
276 run_program(0, "mv -f %s %s", src
, concat_paths(prefix
, "usr/lib.old"));
277 strlcpy(src
, concat_paths(prefix
, "etc/ld.so.conf"), sizeof(src
));
278 run_program(0, "mv -f %s %s",
279 src
, concat_paths(prefix
, "etc/ld.so.conf.old"));
280 if (run_program(0, "mkdir -p %s ", concat_paths(prefix
, "usr/lib")))
282 if (run_program(0, "mkdir -p %s ", concat_paths(prefix
, "etc")))
285 strlcpy(src
, target_expand("/etc/ld.so.conf"), sizeof(src
));
286 if (run_program(0, "mv -f %s %s",
287 src
, concat_paths(prefix
, "etc/ld.so.conf")))
290 strlcpy(src
, target_expand("/usr/lib"), sizeof(src
));
291 n
= handle_aout_libs(src
, LIB_MOVE
, concat_paths(prefix
, "usr/lib"));
293 if (run_program(0, "mkdir -p %s ",
294 concat_paths(prefix
, "usr/X11R6/lib")))
297 strlcpy(src
, target_expand("/usr/X11R6/lib"), sizeof(src
));
298 handle_aout_x_libs(src
, concat_paths(prefix
, "usr/X11R6/lib"));
301 msg_display(MSG_emulbackup
);
302 process_menu(MENU_ok
, NULL
);
309 * XXXX had to include this to deal with symlinks in some places.
310 * When the target * disk is mounted under /targetroot, absolute symlinks
311 * on it don't work right.
312 * This function will resolve them using the mountpoint as prefix.
313 * Copied verbatim from libc, with added prefix handling.
315 * char *realpath(const char *path, char resolved_path[MAXPATHLEN]);
317 * Find the real name of path, by removing all ".", ".." and symlink
318 * components. Returns (resolved) on success, or (NULL) on failure,
319 * in which case the path which caused trouble is left in (resolved).
322 target_realpath(const char *path
, char *resolved
)
325 int fd
, n
, rootd
, serrno
, nlnk
= 0;
326 char *p
, *q
, wbuf
[MAXPATHLEN
];
327 char solidus
[2], empty
[1];
332 /* Save the starting point. */
333 if ((fd
= open(".", O_RDONLY
)) < 0) {
334 (void)strlcpy(resolved
, ".", MAXPATHLEN
);
339 * Find the dirname and basename from the path to be resolved.
340 * Change directory to the dirname component.
341 * lstat the basename part.
342 * if it is a symlink, read in the value and loop.
343 * if it is a directory, then change to that directory.
344 * get the current directory name and append the basename.
346 if (target_prefix() != NULL
&& strcmp(target_prefix(), "") != 0)
347 snprintf(resolved
, MAXPATHLEN
, "%s/%s", target_prefix(), path
);
349 if (strlcpy(resolved
, path
, MAXPATHLEN
) >= MAXPATHLEN
) {
350 errno
= ENAMETOOLONG
;
354 q
= strrchr(resolved
, '/');
362 } while (q
> resolved
&& *q
== '/');
371 /* Deal with the last component. */
372 if (lstat(p
, &sb
) == 0) {
373 if (S_ISLNK(sb
.st_mode
)) {
374 if (nlnk
++ >= MAXSYMLINKS
) {
378 n
= readlink(p
, wbuf
, MAXPATHLEN
- 1);
383 snprintf(resolved
, MAXPATHLEN
, "%s%s",
384 target_prefix(), wbuf
);
386 strlcpy(resolved
, wbuf
, MAXPATHLEN
);
389 if (S_ISDIR(sb
.st_mode
)) {
397 * Save the last component name and get the full pathname of
398 * the current directory.
400 if (strlcpy(wbuf
, p
, sizeof(wbuf
)) >= sizeof(wbuf
)) {
401 errno
= ENAMETOOLONG
;
406 * Call the internal internal version of getcwd which
407 * does a physical search rather than using the $PWD short-cut
409 if (getcwd(resolved
, MAXPATHLEN
) == 0)
413 * Join the two strings together, ensuring that the right thing
414 * happens if the last component is empty, or the dirname is root.
416 if (resolved
[0] == '/' && resolved
[1] == '\0')
422 if (strlen(resolved
) + strlen(wbuf
) + (rootd
? 0 : 1) + 1 >
424 errno
= ENAMETOOLONG
;
428 if (strlcat(resolved
, "/", MAXPATHLEN
) >= MAXPATHLEN
) {
429 errno
= ENAMETOOLONG
;
432 if (strlcat(resolved
, wbuf
, MAXPATHLEN
) >= MAXPATHLEN
) {
433 errno
= ENAMETOOLONG
;
438 /* Go back to where we came from. */
439 if (fchdir(fd
) < 0) {
444 /* It's okay if the close fails, what's an fd more or less? */
448 err1
: serrno
= errno
;
450 err2
: (void)close(fd
);