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