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