Home | History | Annotate | Line # | Download | only in sysinst
      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