xref: /netbsd-src/usr.sbin/sysinst/target.c (revision d24f36fab5977a1f962347d6cf381acc85840434)
1*d24f36faSmartin /*	$NetBSD: target.c,v 1.18 2022/02/10 16:11:41 martin Exp $	*/
250dbef1aSdholland 
350dbef1aSdholland /*
450dbef1aSdholland  * Copyright 1997 Jonathan Stone
550dbef1aSdholland  * All rights reserved.
650dbef1aSdholland  *
750dbef1aSdholland  * Redistribution and use in source and binary forms, with or without
850dbef1aSdholland  * modification, are permitted provided that the following conditions
950dbef1aSdholland  * are met:
1050dbef1aSdholland  * 1. Redistributions of source code must retain the above copyright
1150dbef1aSdholland  *    notice, this list of conditions and the following disclaimer.
1250dbef1aSdholland  * 2. Redistributions in binary form must reproduce the above copyright
1350dbef1aSdholland  *    notice, this list of conditions and the following disclaimer in the
1450dbef1aSdholland  *    documentation and/or other materials provided with the distribution.
1550dbef1aSdholland  * 3. All advertising materials mentioning features or use of this software
1650dbef1aSdholland  *    must display the following acknowledgement:
1750dbef1aSdholland  *      This product includes software developed for the NetBSD Project by
1850dbef1aSdholland  *      Jonathan Stone.
1950dbef1aSdholland  * 4. The name of Jonathan Stone may not be used to endorse
2050dbef1aSdholland  *    or promote products derived from this software without specific prior
2150dbef1aSdholland  *    written permission.
2250dbef1aSdholland  *
2350dbef1aSdholland  * THIS SOFTWARE IS PROVIDED BY JONATHAN STONE ``AS IS''
2450dbef1aSdholland  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2550dbef1aSdholland  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2650dbef1aSdholland  * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
2750dbef1aSdholland  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2850dbef1aSdholland  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2950dbef1aSdholland  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3050dbef1aSdholland  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3150dbef1aSdholland  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3250dbef1aSdholland  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
3350dbef1aSdholland  * THE POSSIBILITY OF SUCH DAMAGE.
3450dbef1aSdholland  *
3550dbef1aSdholland  */
3650dbef1aSdholland 
3750dbef1aSdholland /* Copyright below applies to the realpath() code */
3850dbef1aSdholland 
3950dbef1aSdholland /*
4050dbef1aSdholland  * Copyright (c) 1989, 1991, 1993, 1995
4150dbef1aSdholland  *      The Regents of the University of California.  All rights reserved.
4250dbef1aSdholland  *
4350dbef1aSdholland  * This code is derived from software contributed to Berkeley by
4450dbef1aSdholland  * Jan-Simon Pendry.
4550dbef1aSdholland  *
4650dbef1aSdholland  * Redistribution and use in source and binary forms, with or without
4750dbef1aSdholland  * modification, are permitted provided that the following conditions
4850dbef1aSdholland  * are met:
4950dbef1aSdholland  * 1. Redistributions of source code must retain the above copyright
5050dbef1aSdholland  *    notice, this list of conditions and the following disclaimer.
5150dbef1aSdholland  * 2. Redistributions in binary form must reproduce the above copyright
5250dbef1aSdholland  *    notice, this list of conditions and the following disclaimer in the
5350dbef1aSdholland  *    documentation and/or other materials provided with the distribution.
5450dbef1aSdholland  * 3. Neither the name of the University nor the names of its contributors
5550dbef1aSdholland  *    may be used to endorse or promote products derived from this software
5650dbef1aSdholland  *    without specific prior written permission.
5750dbef1aSdholland  *
5850dbef1aSdholland  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5950dbef1aSdholland  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
6050dbef1aSdholland  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
6150dbef1aSdholland  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
6250dbef1aSdholland  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
6350dbef1aSdholland  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
6450dbef1aSdholland  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6550dbef1aSdholland  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6650dbef1aSdholland  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6750dbef1aSdholland  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6850dbef1aSdholland  * SUCH DAMAGE.
6950dbef1aSdholland  */
7050dbef1aSdholland 
7150dbef1aSdholland 
7250dbef1aSdholland #include <sys/cdefs.h>
7350dbef1aSdholland #if defined(LIBC_SCCS) && !defined(lint)
74*d24f36faSmartin __RCSID("$NetBSD: target.c,v 1.18 2022/02/10 16:11:41 martin Exp $");
7550dbef1aSdholland #endif
7650dbef1aSdholland 
7750dbef1aSdholland /*
7850dbef1aSdholland  * target.c -- path-prefixing routines to access the target installation
7950dbef1aSdholland  *  filesystems. Makes the install tools more independent of whether
8050dbef1aSdholland  *  we're installing into a separate filesystem hierarchy mounted under
8150dbef1aSdholland  * /targetroot, or into the currently active root mounted on /.
8250dbef1aSdholland  */
8350dbef1aSdholland 
8450dbef1aSdholland #include <sys/param.h>			/* XXX vm_param.h always defines TRUE*/
8550dbef1aSdholland #include <sys/types.h>
868bb96d39Smartin #include <sys/ioctl.h>
8750dbef1aSdholland #include <sys/sysctl.h>
8850dbef1aSdholland #include <sys/stat.h>			/* stat() */
8950dbef1aSdholland #include <sys/mount.h>			/* statfs() */
9050dbef1aSdholland 
9150dbef1aSdholland #include <fcntl.h>
9250dbef1aSdholland #include <stdio.h>
9350dbef1aSdholland #include <stdarg.h>
9450dbef1aSdholland #include <unistd.h>
9550dbef1aSdholland #include <curses.h>			/* defines TRUE, but checks  */
9650dbef1aSdholland #include <errno.h>
978bb96d39Smartin #include <util.h>
9850dbef1aSdholland 
9950dbef1aSdholland #include "defs.h"
10050dbef1aSdholland #include "md.h"
10150dbef1aSdholland #include "msg_defs.h"
10250dbef1aSdholland #include "menu_defs.h"
10350dbef1aSdholland 
10450dbef1aSdholland /*
10550dbef1aSdholland  * local  prototypes
10650dbef1aSdholland  */
10750dbef1aSdholland 
10850dbef1aSdholland static void make_prefixed_dir (const char *prefix, const char *path);
10950dbef1aSdholland static int do_target_chdir (const char *dir, int flag);
11050dbef1aSdholland int	target_test(unsigned int mode, const char *path);
11150dbef1aSdholland int	target_test_dir (const char *path);	/* deprecated */
11250dbef1aSdholland int	target_test_file (const char *path);	/* deprecated */
11350dbef1aSdholland int	target_test_symlink (const char *path);	/* deprecated */
11450dbef1aSdholland 
11550dbef1aSdholland void unwind_mounts(void);
11650dbef1aSdholland 
11750dbef1aSdholland /* Record a mount for later unwinding of target mounts. */
11850dbef1aSdholland struct unwind_mount {
11950dbef1aSdholland 	struct unwind_mount *um_prev;
12050dbef1aSdholland 	char um_mountpoint[4];		/* Allocated longer... */
12150dbef1aSdholland };
12250dbef1aSdholland 
1238bb96d39Smartin /* Record a wedge for later deletion after all file systems have been unmounted */
1248bb96d39Smartin struct umount_delwedge {
1258bb96d39Smartin 	struct umount_delwedge *next;
126fade124bSmartin 	char disk[DISKNAMESIZE], wedge[DISKNAMESIZE];
1278bb96d39Smartin };
1288bb96d39Smartin struct umount_delwedge *post_umount_dwlist = NULL;
1298bb96d39Smartin 
13050dbef1aSdholland /* Unwind-mount stack */
13150dbef1aSdholland struct unwind_mount *unwind_mountlist = NULL;
13250dbef1aSdholland 
13350dbef1aSdholland /*
13450dbef1aSdholland  * Debugging options
13550dbef1aSdholland  */
13650dbef1aSdholland /*#define DEBUG_ROOT*/		/* turn on what-is-root? debugging. */
13750dbef1aSdholland /*#define DEBUG_UNWIND*/	/* turn on unwind-target-mount debugging. */
13850dbef1aSdholland 
13950dbef1aSdholland /*
14050dbef1aSdholland  * debugging helper. curses...
14150dbef1aSdholland  */
14250dbef1aSdholland #if defined(DEBUG)  ||	defined(DEBUG_ROOT)
14350dbef1aSdholland void
backtowin(void)14450dbef1aSdholland backtowin(void)
14550dbef1aSdholland {
14650dbef1aSdholland 
14750dbef1aSdholland 	fflush(stdout);	/* curses does not leave stdout linebuffered. */
14850dbef1aSdholland 	getchar();	/* wait for user to press return */
14950dbef1aSdholland 	wrefresh(stdscr);
15050dbef1aSdholland }
15150dbef1aSdholland #endif
15250dbef1aSdholland 
15350dbef1aSdholland 
15450dbef1aSdholland /*
15550dbef1aSdholland  * Is the root partition we're running from the same as the root
15650dbef1aSdholland  * which the user has selected to install/upgrade?
1574b2364d9Smartin  * Uses global variable "pm->diskdev" to find the selected device for
15850dbef1aSdholland  * install/upgrade.
15950dbef1aSdholland  */
16050dbef1aSdholland int
target_already_root(void)16150dbef1aSdholland target_already_root(void)
16250dbef1aSdholland {
1634103857bSmartin 	char dev[PATH_MAX];
1644103857bSmartin 	int rootpart = -1;
1654103857bSmartin 	static struct pm_devs *last_pm;
1664103857bSmartin 	static int last_res;
1674103857bSmartin 	part_id ptn;
168bc25142eSmartin 	struct disk_partitions *parts, *inner;
1694103857bSmartin 	struct disk_part_info info;
17050dbef1aSdholland 
171dd0cd772Smartin 	if (pm == NULL)
172dd0cd772Smartin 		return 1;
173dd0cd772Smartin 
1744103857bSmartin 	if (pm == last_pm)
1754103857bSmartin 		return last_res;
176e0822524Smartin 
177b1fa9754Smartin 	if (pm->cur_system)
178b1fa9754Smartin 		return 1;
179b1fa9754Smartin 
1804103857bSmartin 	last_pm = pm;
181c2ed2005Smartin 	last_res = 0;
1824103857bSmartin 
1834103857bSmartin 	parts = pm->parts;
184c2ed2005Smartin 	if (parts == NULL) {
1854103857bSmartin 		last_res = 0;
1864103857bSmartin 		return 0;
1874103857bSmartin 	}
188c2ed2005Smartin 
189c2ed2005Smartin 	if (pm->no_part) {
190c2ed2005Smartin 		last_res = is_active_rootpart(pm->diskdev, -1);
191c2ed2005Smartin 		return last_res;
192c2ed2005Smartin 	}
193c2ed2005Smartin 
194bc25142eSmartin 	if (pm->parts->pscheme->secondary_partitions != NULL) {
195bc25142eSmartin 		inner = pm->parts->pscheme->secondary_partitions(parts,
19683478358Smartin 		    pm->ptstart, false);
197bc25142eSmartin 		if (inner != NULL)
198bc25142eSmartin 			parts = inner;
199bc25142eSmartin 	}
2004103857bSmartin 
2014103857bSmartin 	for (ptn = 0; ptn < parts->num_part; ptn++) {
2024103857bSmartin 		if (!parts->pscheme->get_part_info(parts, ptn, &info))
2034103857bSmartin 			continue;
2044103857bSmartin 		if (info.nat_type->generic_ptype != PT_root)
2054103857bSmartin 			continue;
206c2ed2005Smartin 		if (!is_root_part_mount(info.last_mounted))
2074103857bSmartin 			continue;
2084103857bSmartin 		if (!parts->pscheme->get_part_device(parts, ptn,
209abce8cb3Smartin 		    dev, sizeof dev, &rootpart, plain_name, false, true))
2104103857bSmartin 			continue;
2114103857bSmartin 
2124103857bSmartin 		last_res = is_active_rootpart(dev, rootpart);
213c2ed2005Smartin 		break;
214c2ed2005Smartin  	}
215c2ed2005Smartin 
2164103857bSmartin 	return last_res;
2174103857bSmartin }
2184103857bSmartin 
219c2ed2005Smartin /*
220c2ed2005Smartin  * Could something with this "last mounted on" information be a potential
221c2ed2005Smartin  * root partition?
222c2ed2005Smartin  */
223c2ed2005Smartin bool
is_root_part_mount(const char * last_mounted)224c2ed2005Smartin is_root_part_mount(const char *last_mounted)
225c2ed2005Smartin {
2266de47033Smartin 	if (last_mounted == NULL)
2276de47033Smartin 		return false;
2286de47033Smartin 
229c2ed2005Smartin 	return strcmp(last_mounted, "/") == 0 ||
230c2ed2005Smartin 	    strcmp(last_mounted, "/targetroot") == 0 ||
231c2ed2005Smartin 	    strcmp(last_mounted, "/altroot") == 0;
23250dbef1aSdholland }
23350dbef1aSdholland 
23450dbef1aSdholland /*
23550dbef1aSdholland  * Is this device partition (e.g., "sd0a") mounted as root?
23650dbef1aSdholland  */
23750dbef1aSdholland int
is_active_rootpart(const char * dev,int ptn)23850dbef1aSdholland is_active_rootpart(const char *dev, int ptn)
23950dbef1aSdholland {
24050dbef1aSdholland 	int mib[2];
24150dbef1aSdholland 	char rootdev[SSTRSIZE];
24250dbef1aSdholland 	int rootptn;
24350dbef1aSdholland 	size_t varlen;
24450dbef1aSdholland 
24550dbef1aSdholland 	mib[0] = CTL_KERN;
24650dbef1aSdholland 	mib[1] = KERN_ROOT_DEVICE;
24750dbef1aSdholland 	varlen = sizeof(rootdev);
24850dbef1aSdholland 	if (sysctl(mib, 2, rootdev, &varlen, NULL, 0) < 0)
24950dbef1aSdholland 		return 1;
25050dbef1aSdholland 
25150dbef1aSdholland 	if (strcmp(dev, rootdev) != 0)
25250dbef1aSdholland 		return 0;
25350dbef1aSdholland 
2545864e121Smartin 	if (ptn < 0)
2555864e121Smartin 		return 1;	/* device only check, or wedge */
2565864e121Smartin 
25750dbef1aSdholland 	mib[1] = KERN_ROOT_PARTITION;
25850dbef1aSdholland 	varlen = sizeof rootptn;
2595864e121Smartin 	rootptn = -1;
26050dbef1aSdholland 	if (sysctl(mib, 2, &rootptn, &varlen, NULL, 0) < 0)
26150dbef1aSdholland 		return 1;
26250dbef1aSdholland 
26350dbef1aSdholland 	return ptn == rootptn;
26450dbef1aSdholland }
26550dbef1aSdholland 
26650dbef1aSdholland /*
26750dbef1aSdholland  * Pathname  prefixing glue to support installation either
26850dbef1aSdholland  * from in-ramdisk miniroots or on-disk diskimages.
26950dbef1aSdholland  * If our root is on the target disk, the install target is mounted
27050dbef1aSdholland  * on /targetroot and we need to prefix installed pathnames with /targetroot.
27150dbef1aSdholland  * otherwise we are installing to the currently-active root and
27250dbef1aSdholland  * no prefix is needed.
27350dbef1aSdholland  */
27450dbef1aSdholland const char *
target_prefix(void)27550dbef1aSdholland target_prefix(void)
27650dbef1aSdholland {
27750dbef1aSdholland 	/*
27850dbef1aSdholland 	 * XXX fetch sysctl variable for current root, and compare
27950dbef1aSdholland 	 * to the devicename of the install target disk.
28050dbef1aSdholland 	 */
28150dbef1aSdholland 	return(target_already_root() ? "" : targetroot_mnt);
28250dbef1aSdholland }
28350dbef1aSdholland 
28450dbef1aSdholland /*
28550dbef1aSdholland  * concatenate two pathnames.
28650dbef1aSdholland  * XXX returns either input args or result in a static buffer.
28750dbef1aSdholland  * The caller must copy if it wants to use the pathname past the
2886dccb7a0Srillig  * next call to a target-prefixing function, or to modify the inputs.
28950dbef1aSdholland  * Used only internally so this is probably safe.
29050dbef1aSdholland  */
29150dbef1aSdholland const char *
concat_paths(const char * prefix,const char * suffix)29250dbef1aSdholland concat_paths(const char *prefix, const char *suffix)
29350dbef1aSdholland {
29450dbef1aSdholland 	static char real_path[MAXPATHLEN];
29550dbef1aSdholland 
29650dbef1aSdholland 	/* absolute prefix and null suffix? */
29750dbef1aSdholland 	if (prefix[0] == '/' && suffix[0] == 0)
29850dbef1aSdholland 		return prefix;
29950dbef1aSdholland 
30050dbef1aSdholland 	/* null prefix and absolute suffix? */
30150dbef1aSdholland 	if (prefix[0] == 0 && suffix[0] == '/')
30250dbef1aSdholland 		return suffix;
30350dbef1aSdholland 
30450dbef1aSdholland 	/* avoid "//" */
30550dbef1aSdholland 	if (suffix[0] == '/' || suffix[0] == 0)
30650dbef1aSdholland 		snprintf(real_path, sizeof(real_path), "%s%s", prefix, suffix);
30750dbef1aSdholland 	else
30850dbef1aSdholland 		snprintf(real_path, sizeof(real_path), "%s/%s",
30950dbef1aSdholland 		    prefix, suffix);
31050dbef1aSdholland 	return (real_path);
31150dbef1aSdholland }
31250dbef1aSdholland 
31350dbef1aSdholland /*
31450dbef1aSdholland  * Do target prefix expansion on a pathname.
31550dbef1aSdholland  * XXX uses concat_paths and so returns result in a static buffer.
31650dbef1aSdholland  * The caller must copy if it wants to use the pathname past the
3176dccb7a0Srillig  * next call to a target-prefixing function, or to modify the inputs.
31850dbef1aSdholland  * Used only internally so this is probably safe.
31950dbef1aSdholland  *
32050dbef1aSdholland  * Not static so other functions can generate target related file names.
32150dbef1aSdholland  */
32250dbef1aSdholland const char *
target_expand(const char * tgtpath)32350dbef1aSdholland target_expand(const char *tgtpath)
32450dbef1aSdholland {
32550dbef1aSdholland 
32650dbef1aSdholland 	return concat_paths(target_prefix(), tgtpath);
32750dbef1aSdholland }
32850dbef1aSdholland 
32950dbef1aSdholland /* Make a directory, with a prefix like "/targetroot" or possibly just "". */
33050dbef1aSdholland static void
make_prefixed_dir(const char * prefix,const char * path)33150dbef1aSdholland make_prefixed_dir(const char *prefix, const char *path)
33250dbef1aSdholland {
33350dbef1aSdholland 
33450dbef1aSdholland 	run_program(0, "/bin/mkdir -p %s", concat_paths(prefix, path));
33550dbef1aSdholland }
33650dbef1aSdholland 
33750dbef1aSdholland /* Make a directory with a pathname relative to the installation target. */
33850dbef1aSdholland void
make_target_dir(const char * path)33950dbef1aSdholland make_target_dir(const char *path)
34050dbef1aSdholland {
34150dbef1aSdholland 
34250dbef1aSdholland 	make_prefixed_dir(target_prefix(), path);
34350dbef1aSdholland }
34450dbef1aSdholland 
34550dbef1aSdholland 
34650dbef1aSdholland static int
do_target_chdir(const char * dir,int must_succeed)34750dbef1aSdholland do_target_chdir(const char *dir, int must_succeed)
34850dbef1aSdholland {
34950dbef1aSdholland 	const char *tgt_dir;
35050dbef1aSdholland 	int error;
35150dbef1aSdholland 
35250dbef1aSdholland 	error = 0;
35350dbef1aSdholland 	tgt_dir = target_expand(dir);
35450dbef1aSdholland 
3554b2364d9Smartin #ifdef DEBUG
3564b2364d9Smartin 	printf("target_chdir (%s)\n", tgt_dir);
3574b2364d9Smartin 	//return (0);
3584b2364d9Smartin #endif
35950dbef1aSdholland 	/* chdir returns -1 on error and sets errno. */
36050dbef1aSdholland 	if (chdir(tgt_dir) < 0)
36150dbef1aSdholland 		error = errno;
36250dbef1aSdholland 	if (logfp) {
36350dbef1aSdholland 		fprintf(logfp, "cd to %s\n", tgt_dir);
36450dbef1aSdholland 		fflush(logfp);
36550dbef1aSdholland 	}
36650dbef1aSdholland 	if (script) {
36750dbef1aSdholland 		scripting_fprintf(NULL, "cd %s\n", tgt_dir);
36850dbef1aSdholland 		fflush(script);
36950dbef1aSdholland 	}
37050dbef1aSdholland 
37150dbef1aSdholland 	if (error && must_succeed) {
3724103857bSmartin 		const char *args[] = { target_prefix(), strerror(error) };
3734103857bSmartin 		char *err = str_arg_subst(msg_string(MSG_realdir),
3744103857bSmartin 		    __arraycount(args), args);
3754103857bSmartin 		fprintf(stderr, "%s\n", err);
37650dbef1aSdholland 		if (logfp)
3774103857bSmartin 			fprintf(logfp, "%s\n", err);
3784103857bSmartin 		free(err);
37950dbef1aSdholland 		exit(1);
38050dbef1aSdholland 	}
38150dbef1aSdholland 	errno = error;
38250dbef1aSdholland 	return (error);
38350dbef1aSdholland }
38450dbef1aSdholland 
38550dbef1aSdholland void
target_chdir_or_die(const char * dir)38650dbef1aSdholland target_chdir_or_die(const char *dir)
38750dbef1aSdholland {
38850dbef1aSdholland 
38950dbef1aSdholland 	(void)do_target_chdir(dir, 1);
39050dbef1aSdholland }
39150dbef1aSdholland 
39250dbef1aSdholland #ifdef notdef
39350dbef1aSdholland int
target_chdir(const char * dir)39450dbef1aSdholland target_chdir(const char *dir)
39550dbef1aSdholland {
39650dbef1aSdholland 
39750dbef1aSdholland 	return do_target_chdir(dir, 0);
39850dbef1aSdholland }
39950dbef1aSdholland #endif
40050dbef1aSdholland 
40150dbef1aSdholland /*
40250dbef1aSdholland  * Copy a file from the current root into the target system,
40350dbef1aSdholland  * where the  destination pathname is relative to the target root.
40450dbef1aSdholland  * Does not check for copy-to-self when target is  current root.
40550dbef1aSdholland  */
40650dbef1aSdholland int
cp_to_target(const char * srcpath,const char * tgt_path)40750dbef1aSdholland cp_to_target(const char *srcpath, const char *tgt_path)
40850dbef1aSdholland {
40950dbef1aSdholland 	const char *real_path = target_expand(tgt_path);
41050dbef1aSdholland 
41150dbef1aSdholland 	return run_program(0, "/bin/cp %s %s", srcpath, real_path);
41250dbef1aSdholland }
41350dbef1aSdholland 
41450dbef1aSdholland /*
41550dbef1aSdholland  * Duplicate a file from the current root to the same pathname
41650dbef1aSdholland  * in the target system.  Pathname must be an absolute pathname.
41750dbef1aSdholland  * If we're running in the target, do nothing.
41850dbef1aSdholland  */
41950dbef1aSdholland void
dup_file_into_target(const char * filename)42050dbef1aSdholland dup_file_into_target(const char *filename)
42150dbef1aSdholland {
42250dbef1aSdholland 
42350dbef1aSdholland 	if (!target_already_root())
42450dbef1aSdholland 		cp_to_target(filename, filename);
42550dbef1aSdholland }
42650dbef1aSdholland 
42750dbef1aSdholland 
42850dbef1aSdholland /*
42950dbef1aSdholland  * Do a mv where both pathnames are within the target filesystem.
43050dbef1aSdholland  */
43150dbef1aSdholland void
mv_within_target_or_die(const char * frompath,const char * topath)43250dbef1aSdholland mv_within_target_or_die(const char *frompath, const char *topath)
43350dbef1aSdholland {
43450dbef1aSdholland 	char realfrom[STRSIZE];
43550dbef1aSdholland 	char realto[STRSIZE];
43650dbef1aSdholland 
43750dbef1aSdholland 	strlcpy(realfrom, target_expand(frompath), sizeof realfrom);
43850dbef1aSdholland 	strlcpy(realto, target_expand(topath), sizeof realto);
43950dbef1aSdholland 
44050dbef1aSdholland 	run_program(RUN_FATAL, "mv %s %s", realfrom, realto);
44150dbef1aSdholland }
44250dbef1aSdholland 
44350dbef1aSdholland /* Do a cp where both pathnames are within the target filesystem. */
44450dbef1aSdholland int
cp_within_target(const char * frompath,const char * topath,int optional)44550dbef1aSdholland cp_within_target(const char *frompath, const char *topath, int optional)
44650dbef1aSdholland {
44750dbef1aSdholland 	char realfrom[STRSIZE];
44850dbef1aSdholland 	char realto[STRSIZE];
44950dbef1aSdholland 
450f16eda65Smartin 	strlcpy(realfrom, target_expand(frompath), sizeof realfrom);
451f16eda65Smartin 	strlcpy(realto, target_expand(topath), sizeof realto);
45250dbef1aSdholland 
45350dbef1aSdholland 	if (access(realfrom, R_OK) == -1 && optional)
45450dbef1aSdholland 		return 0;
45550dbef1aSdholland 	return (run_program(0, "cp -p %s %s", realfrom, realto));
45650dbef1aSdholland }
45750dbef1aSdholland 
45850dbef1aSdholland /* fopen a pathname in the target. */
45950dbef1aSdholland FILE *
target_fopen(const char * filename,const char * type)46050dbef1aSdholland target_fopen(const char *filename, const char *type)
46150dbef1aSdholland {
46250dbef1aSdholland 
46350dbef1aSdholland 	return fopen(target_expand(filename), type);
46450dbef1aSdholland }
46550dbef1aSdholland 
46650dbef1aSdholland /*
46750dbef1aSdholland  * Do a mount onto a mountpoint in the install target.
46850dbef1aSdholland  * Record mountpoint so we can unmount when finished.
46950dbef1aSdholland  * NB: does not prefix mount-from, which probably breaks nullfs mounts.
47050dbef1aSdholland  */
47150dbef1aSdholland int
target_mount_do(const char * opts,const char * from,const char * on)4724b2364d9Smartin target_mount_do(const char *opts, const char *from, const char *on)
47350dbef1aSdholland {
47450dbef1aSdholland 	struct unwind_mount *m;
47550dbef1aSdholland 	int error;
47650dbef1aSdholland 	int len;
47750dbef1aSdholland 
47850dbef1aSdholland 	len = strlen(on);
47950dbef1aSdholland 	m = malloc(sizeof *m + len);
48050dbef1aSdholland 	if (m == 0)
48150dbef1aSdholland 		return (ENOMEM);	/* XXX */
48250dbef1aSdholland 
48350dbef1aSdholland 	memcpy(m->um_mountpoint, on, len + 1);
48450dbef1aSdholland 
48550dbef1aSdholland #ifdef DEBUG_UNWIND
48650dbef1aSdholland 	endwin();
48750dbef1aSdholland 	fprintf(stderr, "mounting %s with unwind\n", on);
48850dbef1aSdholland 	backtowin();
48950dbef1aSdholland #endif
49050dbef1aSdholland 
4914b2364d9Smartin 	error = run_program(0, "/sbin/mount %s %s %s%s",
4924b2364d9Smartin 			opts, from, target_prefix(), on);
49350dbef1aSdholland 	if (error) {
49450dbef1aSdholland 		free(m);
49550dbef1aSdholland 		return error;
49650dbef1aSdholland 	}
49750dbef1aSdholland 	m->um_prev = unwind_mountlist;
49850dbef1aSdholland 	unwind_mountlist = m;
49950dbef1aSdholland 	return 0;
50050dbef1aSdholland }
50150dbef1aSdholland 
502a7267d53Smartin /*
503a7267d53Smartin  * Special case - we have mounted the target / readonly
504a7267d53Smartin  * to peek at etc/fstab, and now want it undone.
505a7267d53Smartin  */
506a7267d53Smartin void
umount_root(void)507a7267d53Smartin umount_root(void)
508a7267d53Smartin {
509a7267d53Smartin 
510a7267d53Smartin 	/* verify this is the only mount */
511a7267d53Smartin 	if (unwind_mountlist == NULL)
512a7267d53Smartin 		return;
513a7267d53Smartin 	if (unwind_mountlist->um_prev != NULL)
514a7267d53Smartin 		return;
515a7267d53Smartin 
516a7267d53Smartin 	if (run_program(0, "/sbin/umount %s", target_prefix()) != 0)
517a7267d53Smartin 		return;
518a7267d53Smartin 
519a7267d53Smartin 	free(unwind_mountlist);
520a7267d53Smartin 	unwind_mountlist = NULL;
521a7267d53Smartin }
522a7267d53Smartin 
523a7267d53Smartin 
5244b2364d9Smartin int
target_mount(const char * opts,const char * from,const char * on)5254103857bSmartin target_mount(const char *opts, const char *from, const char *on)
5264b2364d9Smartin {
5274103857bSmartin 	return target_mount_do(opts, from, on);
5284b2364d9Smartin }
5294b2364d9Smartin 
530*d24f36faSmartin int
target_unmount(const char * mount_point)531*d24f36faSmartin target_unmount(const char *mount_point)
532*d24f36faSmartin {
533*d24f36faSmartin 	struct unwind_mount *m, *prev = NULL;
534*d24f36faSmartin 	int error;
535*d24f36faSmartin 
536*d24f36faSmartin 	for (m = unwind_mountlist; m != NULL; prev = m, m = m->um_prev)
537*d24f36faSmartin 		if (strcmp(m->um_mountpoint, mount_point) == 0)
538*d24f36faSmartin 			break;
539*d24f36faSmartin 
540*d24f36faSmartin 	if (m == NULL)
541*d24f36faSmartin 		return ENOTDIR;
542*d24f36faSmartin 
543*d24f36faSmartin 	error = run_program(0, "/sbin/umount %s%s",
544*d24f36faSmartin 		    target_prefix(), m->um_mountpoint);
545*d24f36faSmartin 	if (error)
546*d24f36faSmartin 		return error;
547*d24f36faSmartin 
548*d24f36faSmartin 	if (m == unwind_mountlist)
549*d24f36faSmartin 		unwind_mountlist = m->um_prev;
550*d24f36faSmartin 	else
551*d24f36faSmartin 		prev->um_prev = m->um_prev;
552*d24f36faSmartin 	free(m);
553*d24f36faSmartin 
554*d24f36faSmartin 	return 0;
555*d24f36faSmartin }
556*d24f36faSmartin 
5578bb96d39Smartin static bool
delete_wedge(const char * disk,const char * wedge)5588bb96d39Smartin delete_wedge(const char *disk, const char *wedge)
5598bb96d39Smartin {
5608bb96d39Smartin 	struct dkwedge_info dkw;
5618bb96d39Smartin 	char diskpath[MAXPATHLEN];
5628bb96d39Smartin 	int fd, error;
5638bb96d39Smartin 
5648bb96d39Smartin 	fd = opendisk(disk, O_RDWR, diskpath, sizeof(diskpath), 0);
5658bb96d39Smartin 	if (fd < 0)
5668bb96d39Smartin 		return false;
5678bb96d39Smartin 	memset(&dkw, 0, sizeof(dkw));
5688bb96d39Smartin 	strlcpy(dkw.dkw_devname, wedge, sizeof(dkw.dkw_devname));
5698bb96d39Smartin 	error = ioctl(fd, DIOCDWEDGE, &dkw);
5708bb96d39Smartin 	close(fd);
5718bb96d39Smartin 	return error == 0;
5728bb96d39Smartin }
5738bb96d39Smartin 
5748bb96d39Smartin void
register_post_umount_delwedge(const char * disk,const char * wedge)5758bb96d39Smartin register_post_umount_delwedge(const char *disk, const char *wedge)
5768bb96d39Smartin {
5778bb96d39Smartin 	struct umount_delwedge *dw;
5788bb96d39Smartin 
579fade124bSmartin 	if (unwind_mountlist == NULL) {
580fade124bSmartin 		/* we have nothing mounted, can delete it right now */
581fade124bSmartin 		delete_wedge(disk, wedge);
582fade124bSmartin 		return;
583fade124bSmartin 	}
584fade124bSmartin 
5858bb96d39Smartin 	dw = calloc(1, sizeof(*dw));
5868bb96d39Smartin 	dw->next = post_umount_dwlist;
5878bb96d39Smartin 	strlcpy(dw->disk, disk, sizeof(dw->disk));
5888bb96d39Smartin 	strlcpy(dw->wedge, wedge, sizeof(dw->wedge));
5898bb96d39Smartin 	post_umount_dwlist = dw;
5908bb96d39Smartin }
5918bb96d39Smartin 
59250dbef1aSdholland /*
59350dbef1aSdholland  * unwind the mount stack, unmounting mounted filesystems.
59450dbef1aSdholland  * For now, ignore any errors in unmount.
59550dbef1aSdholland  * (Why would we be unable to unmount?  The user has suspended
59650dbef1aSdholland  *  us and forked shell sitting somewhere in the target root?)
59750dbef1aSdholland  */
59850dbef1aSdholland void
unwind_mounts(void)59950dbef1aSdholland unwind_mounts(void)
60050dbef1aSdholland {
60150dbef1aSdholland 	struct unwind_mount *m;
6028bb96d39Smartin 	struct umount_delwedge *dw;
60350dbef1aSdholland 	static volatile int unwind_in_progress = 0;
60450dbef1aSdholland 
60550dbef1aSdholland 	/* signal safety */
60650dbef1aSdholland 	if (unwind_in_progress)
60750dbef1aSdholland 		return;
60850dbef1aSdholland 	unwind_in_progress = 1;
60950dbef1aSdholland 
61050dbef1aSdholland 	while ((m = unwind_mountlist) != NULL) {
61150dbef1aSdholland 		unwind_mountlist = m->um_prev;
61250dbef1aSdholland #ifdef DEBUG_UNWIND
61350dbef1aSdholland 		endwin();
61450dbef1aSdholland 		fprintf(stderr, "unmounting %s\n", m->um_mountpoint);
61550dbef1aSdholland 		backtowin();
61650dbef1aSdholland #endif
61750dbef1aSdholland 		run_program(0, "/sbin/umount %s%s",
61850dbef1aSdholland 			target_prefix(), m->um_mountpoint);
61950dbef1aSdholland 		free(m);
62050dbef1aSdholland 	}
6218bb96d39Smartin 	while ((dw = post_umount_dwlist) != NULL) {
6228bb96d39Smartin 		post_umount_dwlist = dw->next;
6238bb96d39Smartin 		delete_wedge(dw->disk, dw->wedge);
6248bb96d39Smartin 		free(dw);
6258bb96d39Smartin 	}
62650dbef1aSdholland 	unwind_in_progress = 0;
62750dbef1aSdholland }
62850dbef1aSdholland 
62950dbef1aSdholland int
target_collect_file(int kind,char ** buffer,const char * name)63050dbef1aSdholland target_collect_file(int kind, char **buffer, const char *name)
63150dbef1aSdholland {
63250dbef1aSdholland 	const char *realname = target_expand(name);
63350dbef1aSdholland 
63450dbef1aSdholland #ifdef	DEBUG
63550dbef1aSdholland 	printf("collect real name %s\n", realname);
63650dbef1aSdholland #endif
63750dbef1aSdholland 	return collect(kind, buffer, "%s", realname);
63850dbef1aSdholland }
63950dbef1aSdholland 
64050dbef1aSdholland /*
64150dbef1aSdholland  * Verify a pathname already exists in the target root filesystem,
64250dbef1aSdholland  * by running  test "testflag" on the expanded target pathname.
64350dbef1aSdholland  */
64450dbef1aSdholland int
target_test(unsigned int mode,const char * path)64550dbef1aSdholland target_test(unsigned int mode, const char *path)
64650dbef1aSdholland {
64750dbef1aSdholland 	const char *real_path = target_expand(path);
64850dbef1aSdholland 	register int result;
64950dbef1aSdholland 
65050dbef1aSdholland 	result = !file_mode_match(real_path, mode);
65150dbef1aSdholland 	scripting_fprintf(NULL, "if [ $? != 0 ]; then echo \"%s does not exist!\"; fi\n", real_path);
65250dbef1aSdholland 
65350dbef1aSdholland #if defined(DEBUG)
65450dbef1aSdholland 	printf("target_test(%o, %s) returning %d\n", mode, real_path, result);
65550dbef1aSdholland #endif
65650dbef1aSdholland 	return (result);
65750dbef1aSdholland }
65850dbef1aSdholland 
65950dbef1aSdholland /*
66050dbef1aSdholland  * Verify a directory already exists in the target root
66150dbef1aSdholland  * filesystem. Do not create the directory if it doesn't  exist.
66250dbef1aSdholland  * Assumes that sysinst has already mounted the target root.
66350dbef1aSdholland  */
66450dbef1aSdholland int
target_test_dir(const char * path)66550dbef1aSdholland target_test_dir(const char *path)
66650dbef1aSdholland {
66750dbef1aSdholland 
66850dbef1aSdholland  	return target_test(S_IFDIR, path);
66950dbef1aSdholland }
67050dbef1aSdholland 
67150dbef1aSdholland /*
67250dbef1aSdholland  * Verify an ordinary file already exists in the target root
67350dbef1aSdholland  * filesystem. Do not create the directory if it doesn't  exist.
67450dbef1aSdholland  * Assumes that sysinst has already mounted the target root.
67550dbef1aSdholland  */
67650dbef1aSdholland int
target_test_file(const char * path)67750dbef1aSdholland target_test_file(const char *path)
67850dbef1aSdholland {
67950dbef1aSdholland 
68050dbef1aSdholland  	return target_test(S_IFREG, path);
68150dbef1aSdholland }
68250dbef1aSdholland 
68350dbef1aSdholland int
target_test_symlink(const char * path)68450dbef1aSdholland target_test_symlink(const char *path)
68550dbef1aSdholland {
68650dbef1aSdholland 
68750dbef1aSdholland  	return target_test(S_IFLNK, path);
68850dbef1aSdholland }
68950dbef1aSdholland 
69050dbef1aSdholland int
target_file_exists_p(const char * path)69150dbef1aSdholland target_file_exists_p(const char *path)
69250dbef1aSdholland {
69350dbef1aSdholland 
69450dbef1aSdholland 	return (target_test_file(path) == 0);
69550dbef1aSdholland }
69650dbef1aSdholland 
69750dbef1aSdholland int
target_dir_exists_p(const char * path)69850dbef1aSdholland target_dir_exists_p(const char *path)
69950dbef1aSdholland {
70050dbef1aSdholland 
70150dbef1aSdholland 	return (target_test_dir(path) == 0);
70250dbef1aSdholland }
70350dbef1aSdholland 
70450dbef1aSdholland int
target_symlink_exists_p(const char * path)70550dbef1aSdholland target_symlink_exists_p(const char *path)
70650dbef1aSdholland {
70750dbef1aSdholland 
70850dbef1aSdholland 	return (target_test_symlink(path) == 0);
70950dbef1aSdholland }
71050dbef1aSdholland 
71150dbef1aSdholland int
target_mounted(void)71250dbef1aSdholland target_mounted(void)
71350dbef1aSdholland {
71450dbef1aSdholland 	return (unwind_mountlist != NULL);
71550dbef1aSdholland }
716