1 /*
2  * Copyright (c)2004 The DragonFly Project.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *   Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  *
11  *   Redistributions in binary form must reproduce the above copyright
12  *   notice, this list of conditions and the following disclaimer in
13  *   the documentation and/or other materials provided with the
14  *   distribution.
15  *
16  *   Neither the name of the DragonFly Project nor the names of its
17  *   contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31  * OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /*
35  * fn_install.c
36  * Installer Function : Install OS Files.
37  * $Id: fn_install.c,v 1.74 2006/04/18 19:43:48 joerg Exp $
38  */
39 
40 #include <libgen.h>
41 #include <string.h>
42 
43 #define SOURCES_CONF_FILE "usr/share/installer/sources.conf"
44 
45 #ifdef ENABLE_NLS
46 #include <libintl.h>
47 #define _(String) gettext (String)
48 #else
49 #define _(String) (String)
50 #endif
51 
52 #include "libaura/mem.h"
53 #include "libaura/buffer.h"
54 #include "libaura/fspred.h"
55 
56 #include "libdfui/dfui.h"
57 #include "libdfui/system.h"
58 
59 #include "libinstaller/commands.h"
60 #include "libinstaller/confed.h"
61 #include "libinstaller/diskutil.h"
62 #include "libinstaller/functions.h"
63 #include "libinstaller/uiutil.h"
64 
65 #include "flow.h"
66 #include "pathnames.h"
67 #include "fn.h"
68 
69 static const char *pfs_mountpt[] = {"/var", "/tmp", "/home",
70 	"/usr/obj", "/var/crash", "/var/tmp", NULL};
71 
72 static const int pfs_nohistory[] = {0, 1, 0, 1, 1, 1};
73 
74 static void
75 handle_pfs(struct i_fn_args *a, struct commands *cmds)
76 {
77 	int j;
78 
79 	/*
80 	 * Create PFS root directory.
81 	 */
82 	command_add(cmds, "%s%s -p %smnt/pfs",
83 	    a->os_root, cmd_name(a, "MKDIR"),
84 	    a->os_root);
85 
86 	for (j = 0; pfs_mountpt[j] != NULL; j++) {
87 		/*
88 		 * We have a PFS for a subdirectory, e.g. /var/crash, so we
89 		 * need to create /pfs/var.crash
90 		 */
91 		if (rindex(pfs_mountpt[j]+1, '/') != NULL) {
92 			command_add(cmds, "%s%s pfs-master %smnt/pfs%s.%s",
93 			    a->os_root, cmd_name(a, "HAMMER"),
94 			    a->os_root, dirname(pfs_mountpt[j]),
95 			    basename(pfs_mountpt[j]));
96 			command_add(cmds, "%s%s -p %smnt%s",
97 			    a->os_root, cmd_name(a, "MKDIR"),
98 			    a->os_root, pfs_mountpt[j]);
99 			command_add(cmds, "%s%s %smnt/pfs%s.%s %smnt%s",
100 			    a->os_root, cmd_name(a, "MOUNT_NULL"),
101 			    a->os_root, dirname(pfs_mountpt[j]),
102 			    basename(pfs_mountpt[j]),
103 			    a->os_root, pfs_mountpt[j]);
104 		} else {
105 			command_add(cmds, "%s%s pfs-master %smnt/pfs%s",
106 			    a->os_root, cmd_name(a, "HAMMER"),
107 			    a->os_root, pfs_mountpt[j]);
108 			command_add(cmds, "%s%s -p %smnt%s",
109 			    a->os_root, cmd_name(a, "MKDIR"),
110 			    a->os_root, pfs_mountpt[j]);
111 			command_add(cmds, "%s%s %smnt/pfs%s %smnt%s",
112 			    a->os_root, cmd_name(a, "MOUNT_NULL"),
113 			    a->os_root, pfs_mountpt[j],
114 			    a->os_root, pfs_mountpt[j]);
115 		}
116 	}
117 }
118 
119 /*
120  * fn_install_os: actually put DragonFly on a disk.
121  */
122 void
123 fn_install_os(struct i_fn_args *a)
124 {
125 	struct subpartition *sp;
126 	struct commands *cmds;
127 	struct command *cmd;
128 	int i, seen_it, prefix, j, needcrypt;
129 	FILE *sources_conf;
130 	char line[256];
131 	char cp_src[64][256];
132 	char file_path[256];
133 	char *string;
134 	int lines = 0;
135 
136 	/*
137 	 * Read SOURCES_CONF_FILE and populate our copy sources.
138 	 */
139 	snprintf(file_path, 256, "%s%s", a->os_root, SOURCES_CONF_FILE);
140 	sources_conf = fopen(file_path, "r");
141 	i_log(a, "Reading %s", file_path);
142 	while(fgets(line, 256, sources_conf) != NULL && lines < 63) {
143 		if(strlen(line)>0)
144 			line[strlen(line)-1] = '\0';
145 		strlcpy(cp_src[lines], line, 256);
146 		i_log(a,"Adding %s to copy source table.", cp_src[lines]);
147 		lines++;
148 	}
149 	i_log(a,"Added %i total items to copy source table.", lines);
150 	strcpy(cp_src[lines], "");
151 	fclose(sources_conf);
152 
153 	cmds = commands_new();
154 
155 	/*
156 	 * If swap isn't mounted yet, mount it.
157 	 */
158 	if (measure_activated_swap(a) == 0) {
159 		for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
160 		    sp != NULL; sp = subpartition_next(sp)) {
161 			if (!subpartition_is_swap(sp))
162 				continue;
163 			command_add(cmds, "%s%s /dev/%s",
164 			    a->os_root,
165 			    cmd_name(a, "SWAPON"),
166 			    subpartition_is_encrypted(sp) ?
167 			    "mapper/swap" : subpartition_get_device_name(sp));
168 		}
169 	}
170 
171 	/*
172 	 * Unmount anything already mounted on /mnt.
173 	 */
174 	unmount_all_under(a, cmds, "%smnt", a->os_root);
175 
176 	/* Check if crypto support is needed */
177 	needcrypt = 0;
178 	for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
179 	     sp != NULL; sp = subpartition_next(sp)) {
180 		if (subpartition_is_encrypted(sp)) {
181 			needcrypt = 1;
182 			break;
183 		}
184 	}
185 
186 	for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
187 	     sp != NULL; sp = subpartition_next(sp)) {
188 		if (strcmp(subpartition_get_mountpoint(sp), "/") == 0) {
189 			if (use_hammer == 1) {
190 				command_add(cmds, "%s%s /dev/%s %smnt%s",
191 				    a->os_root, cmd_name(a, "MOUNT_HAMMER"),
192 				    subpartition_is_encrypted(sp) ?
193 				    "mapper/root" : subpartition_get_device_name(sp),
194 				    a->os_root,
195 				    subpartition_get_mountpoint(sp));
196 			} else {
197 				command_add(cmds, "%s%s /dev/%s %smnt%s",
198 				    a->os_root, cmd_name(a, "MOUNT"),
199 				    subpartition_get_device_name(sp),
200 				    a->os_root,
201 				    subpartition_get_mountpoint(sp));
202 			}
203 		}
204 	}
205 
206 	/*
207 	 * Create mount points and mount subpartitions on them.
208 	 */
209 	for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
210 	     sp != NULL; sp = subpartition_next(sp)) {
211 		if (subpartition_is_swap(sp)) {
212 			/*
213 			 * Set this subpartition as the dump device.
214 			 */
215 			command_add(cmds, "%s%s -v /dev/%s",
216 			    a->os_root, cmd_name(a, "DUMPON"),
217 			    subpartition_is_encrypted(sp) ?
218 			    "mapper/swap" : subpartition_get_device_name(sp));
219 
220 			asprintf(&string, "/dev/%s",
221 			    subpartition_is_encrypted(sp) ?
222 			    "mapper/swap" : subpartition_get_device_name(sp));
223 			config_var_set(rc_conf, "dumpdev", string);
224 			free(string);
225 			continue;
226 		}
227 
228 		if (use_hammer == 0) {
229 			/* / is already mounted */
230 			if (strcmp(subpartition_get_mountpoint(sp), "/") != 0) {
231 				command_add(cmds, "%s%s -p %smnt%s",
232 				    a->os_root, cmd_name(a, "MKDIR"),
233 				    a->os_root,
234 				    subpartition_get_mountpoint(sp));
235 				/* Don't mount it if it's TMPFS-backed. */
236 				if (subpartition_is_tmpfsbacked(sp))
237 					continue;
238 				if (subpartition_is_encrypted(sp)) {
239 					command_add(cmds, "%s%s /dev/mapper/%s %smnt%s",
240 					    a->os_root, cmd_name(a, "MOUNT"),
241 					    subpartition_get_mountpoint(sp) + 1,
242 					    a->os_root,
243 					    subpartition_get_mountpoint(sp));
244 				} else {
245 					command_add(cmds, "%s%s /dev/%s %smnt%s",
246 					    a->os_root, cmd_name(a, "MOUNT"),
247 					    subpartition_get_device_name(sp),
248 					    a->os_root,
249 					    subpartition_get_mountpoint(sp));
250 				}
251 			}
252 		} else if (strcmp(subpartition_get_mountpoint(sp), "/boot") == 0) {
253 			command_add(cmds, "%s%s -p %smnt%s",
254 			    a->os_root, cmd_name(a, "MKDIR"),
255 			    a->os_root,
256 			    subpartition_get_mountpoint(sp));
257 			command_add(cmds, "%s%s /dev/%s %smnt%s",
258 			    a->os_root, cmd_name(a, "MOUNT"),
259 			    subpartition_get_device_name(sp),
260 			    a->os_root,
261 			    subpartition_get_mountpoint(sp));
262 		}
263 	}
264 
265 	/*
266 	 * Take care of HAMMER PFS.
267 	 */
268 	if (use_hammer == 1)
269 		handle_pfs(a, cmds);
270 
271 	/*
272 	 * Actually copy files now.
273 	 */
274 
275 	for (i = 0; cp_src[i] != NULL && cp_src[i][0] != '\0'; i++) {
276 		char *src, *dest, *dn, *tmp_dest;
277 
278 		dest = cp_src[i];
279 
280 		/*
281 		 * If dest would be on an TMPFS-backed
282 		 * mountpoint, don't bother copying it.
283 		 */
284 		sp = subpartition_of(storage_get_selected_slice(a->s),
285 				     "%s%s", a->os_root, &dest[1]);
286 		if (sp != NULL && subpartition_is_tmpfsbacked(sp)) {
287 			continue;
288 		}
289 
290 		/*
291 		 * Create intermediate directories, if needed.
292 		 */
293 		tmp_dest = aura_strdup(dest);
294 		dn = dirname(tmp_dest);
295 		if (is_dir("%s%s", a->os_root, &dn[1]) &&
296 		    !is_dir("%smnt%s", a->os_root, dn)) {
297 			command_add(cmds, "%s%s -p %smnt%s",
298 			    a->os_root, cmd_name(a, "MKDIR"),
299 			    a->os_root, dn);
300 		}
301 		aura_free(tmp_dest, "directory name");
302 
303 		/*
304 		 * If a directory by the same name but with the suffix
305 		 * ".hdd" exists on the installation media, cpdup that
306 		 * instead.  This is particularly useful with /etc, which
307 		 * may have significantly different behaviour on the
308 		 * live CD compared to a standard HDD boot.
309 		 */
310 		if (is_dir("%s%s.hdd", a->os_root, &dest[1]))
311 			asprintf(&src, "%s.hdd", &dest[1]);
312 		else
313 			asprintf(&src, "%s", &dest[1]);
314 
315 		if (is_dir("%s%s", a->os_root, src) || is_file("%s%s", a->os_root, src)) {
316 			/*
317 			 * Cpdup the chosen file or directory onto the HDD.
318 			 * if it exists on the source.
319 			 */
320 			cmd = command_add(cmds, "%s%s %s%s %smnt%s",
321 			    a->os_root, cmd_name(a, "CPDUP"),
322 			    a->os_root, src,
323 			    a->os_root, dest);
324 			command_set_log_mode(cmd, COMMAND_LOG_QUIET);
325 		}
326 	}
327 
328 	/*
329 	 * Now, because cpdup does not cross mount points,
330 	 * we must copy anything that the user might've made a
331 	 * seperate mount point for (e.g. /usr/libdata/lint.)
332 	 */
333 	for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
334 	     sp != NULL; sp = subpartition_next(sp)) {
335 		/*
336 		 * If the subpartition is a swap subpartition or an
337 		 * TMPFS-backed mountpoint, don't try to copy anything
338 		 * into it.
339 		 */
340 		if (subpartition_is_swap(sp) || subpartition_is_tmpfsbacked(sp))
341 			continue;
342 
343 		/*
344 		 * If the mountpoint doesn't even exist on the installation
345 		 * medium, don't try to copy anything from it!  We assume
346 		 * it's an empty subpartition for the user's needs.
347 		 */
348 		if (!is_dir("%s%s", a->os_root, &subpartition_get_mountpoint(sp)[1]))
349 			continue;
350 
351 		/*
352 		 * Don't bother copying the mountpoint IF:
353 		 * - we've already said to copy it, or something besides it
354 		 *   (it's a prefix of something in cp_src); or
355 		 * - we haven't said to copy it
356 		 *   (nothing in cp_src is a prefix of it.)
357 		 */
358 		seen_it = 0;
359 		prefix = 0;
360 		for (i = 0; cp_src[i] != NULL && cp_src[i][0] != '\0'; i++) {
361 			if (strncmp(subpartition_get_mountpoint(sp), cp_src[i],
362 			    strlen(subpartition_get_mountpoint(sp))) == 0) {
363 				seen_it = 1;
364 				break;
365 			}
366 			if (strncmp(cp_src[i], subpartition_get_mountpoint(sp),
367 			    strlen(cp_src[i])) == 0) {
368 				prefix = 1;
369 			}
370 		}
371 		if (seen_it || !prefix)
372 			continue;
373 
374 		/*
375 		 * Otherwise, cpdup the subpartition.
376 		 *
377 		 * XXX check for .hdd-extended source dirs here, too,
378 		 * eventually - but for now, /etc.hdd will never be
379 		 * the kind of tricky sub-mount-within-a-mount-point
380 		 * that this part of the code is meant to handle.
381 		 */
382 		cmd = command_add(cmds, "%s%s %s%s %smnt%s",
383 		    a->os_root, cmd_name(a, "CPDUP"),
384 		    a->os_root, &subpartition_get_mountpoint(sp)[1],
385 		    a->os_root, subpartition_get_mountpoint(sp));
386 		command_set_log_mode(cmd, COMMAND_LOG_QUIET);
387 	}
388 
389 	/*
390 	 * Create symlinks.
391 	 */
392 
393 	/* Take care of /sys. */
394 	command_add(cmds, "%s%s -s usr/src/sys %smnt/sys",
395 	    a->os_root, cmd_name(a, "LN"), a->os_root);
396 
397 	/*
398 	 * If the user has both /var and /tmp subpartitions,
399 	 * symlink /var/tmp to /tmp.
400 	 */
401 	if (subpartition_find(storage_get_selected_slice(a->s), "/tmp") != NULL &&
402 	    subpartition_find(storage_get_selected_slice(a->s), "/var") != NULL) {
403 		command_add(cmds, "%s%s 1777 %smnt/tmp",
404 		    a->os_root, cmd_name(a, "CHMOD"), a->os_root);
405 		command_add(cmds, "%s%s -rf %smnt/var/tmp",
406 		    a->os_root, cmd_name(a, "RM"), a->os_root);
407 		command_add(cmds, "%s%s -s /tmp %smnt/var/tmp",
408 		    a->os_root, cmd_name(a, "LN"), a->os_root);
409 	}
410 
411 	/*
412 	 * If the user has /var, but no /tmp,
413 	 * symlink /tmp to /var/tmp.
414 	 */
415 	if (subpartition_find(storage_get_selected_slice(a->s), "/tmp") == NULL &&
416 	    subpartition_find(storage_get_selected_slice(a->s), "/var") != NULL) {
417 		command_add(cmds, "%s%s -rf %smnt/tmp",
418 		    a->os_root, cmd_name(a, "RM"), a->os_root);
419 		command_add(cmds, "%s%s -s /var/tmp %smnt/tmp",
420 		    a->os_root, cmd_name(a, "LN"), a->os_root);
421 	}
422 
423 	/*
424 	 * If the user has /usr, but no /home,
425 	 * symlink /home to /usr/home.
426 	 */
427 	if (subpartition_find(storage_get_selected_slice(a->s), "/home") == NULL &&
428 	    subpartition_find(storage_get_selected_slice(a->s), "/usr") != NULL) {
429 		command_add(cmds, "%s%s -rf %smnt/home",
430 		    a->os_root, cmd_name(a, "RM"), a->os_root);
431 		command_add(cmds, "%s%s %smnt/usr/home",
432 		    a->os_root, cmd_name(a, "MKDIR"), a->os_root);
433 		command_add(cmds, "%s%s -s /usr/home %smnt/home",
434 		    a->os_root, cmd_name(a, "LN"), a->os_root);
435 	}
436 
437 	/*
438 	 * XXX check for other possible combinations too?
439 	 */
440 
441 	/*
442 	 * Clean up.  In case some file didn't make it, use rm -f
443 	 */
444 	command_add(cmds, "%s%s -f %smnt/boot/loader.conf",
445 	    a->os_root, cmd_name(a, "RM"), a->os_root);
446 	command_add(cmds, "%s%s -f %smnt/tmp/install.log",
447 	    a->os_root, cmd_name(a, "RM"), a->os_root);
448 	command_add(cmds, "%s%s -f %smnt/tmp/t[12]",
449 	    a->os_root, cmd_name(a, "RM"), a->os_root);
450 	command_add(cmds, "%s%s -f %smnt/tmp/test_in",
451 	    a->os_root, cmd_name(a, "RM"), a->os_root);
452 	command_add(cmds, "%s%s -f %smnt/tmp/test_out",
453 	    a->os_root, cmd_name(a, "RM"), a->os_root);
454 
455 	/*
456 	 * Copy pristine versions over any files we might have installed.
457 	 * This allows the resulting file tree to be customized.
458 	 */
459 	for (i = 0; cp_src[i] != NULL && cp_src[i][0] != '\0'; i++) {
460 		char *src, *dest, *dn, *tmp_dest;
461 
462 		src = cp_src[i];
463 		dest = cp_src[i];
464 
465 		/*
466 		 * Get the directory that the desired thing to
467 		 * copy resides in.
468 		 */
469 		tmp_dest = aura_strdup(dest);
470 		dn = dirname(tmp_dest);
471 
472 		/*
473 		 * If this dir doesn't exist in PRISTINE_DIR
474 		 * on the install media, just skip it.
475 		 */
476 		if (!is_dir("%s%s%s", a->os_root, PRISTINE_DIR, dn)) {
477 			aura_free(tmp_dest, _("directory name"));
478 			continue;
479 		}
480 
481 		/*
482 		 * Create intermediate directories, if needed.
483 		 */
484 		if (!is_dir("%smnt%s", a->os_root, dn)) {
485 			command_add(cmds, "%s%s -p %smnt%s",
486 			    a->os_root, cmd_name(a, "MKDIR"),
487 			    a->os_root, dn);
488 		}
489 		aura_free(tmp_dest, "directory name");
490 
491 		/*
492 		 * Cpdup the chosen file or directory onto the HDD.
493 		 */
494 		cmd = command_add(cmds, "%s%s %s%s %smnt%s",
495 		    a->os_root, cmd_name(a, "CPDUP"),
496 		    a->os_root, src,
497 		    a->os_root, dest);
498 
499 		cmd = command_add(cmds,
500 		    "%s%s %s%s%s %smnt%s",
501 		    a->os_root, cmd_name(a, "CPDUP"),
502 		    a->os_root, PRISTINE_DIR, src,
503 		    a->os_root, dest);
504 		command_set_log_mode(cmd, COMMAND_LOG_QUIET);
505 	}
506 
507 	/*
508 	 * Rebuild the user database, to get rid of any extra users
509 	 * from the LiveCD that aren't supposed to be installed
510 	 * (copying a pristine master.passwd isn't enough.)
511 	 */
512 	command_add(cmds, "%s%s -p -d %smnt/etc %smnt/etc/master.passwd",
513 	    a->os_root, cmd_name(a, "PWD_MKDB"), a->os_root, a->os_root);
514 
515 	/* Create missing directories. */
516 	command_add(cmds, "%s%s %smnt/proc",
517 	    a->os_root, cmd_name(a, "MKDIR"), a->os_root);
518 	command_add(cmds, "%s%s %smnt/mnt",
519 	    a->os_root, cmd_name(a, "MKDIR"), a->os_root);
520 
521 	/* Write new fstab. */
522 	command_add(cmds, "%s%s '%s' >%smnt/etc/fstab",
523 	    a->os_root, cmd_name(a, "ECHO"),
524 	    "# Device\t\tMountpoint\tFStype\tOptions\t\tDump\tPass#",
525 	    a->os_root);
526 
527 	for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
528 	     sp != NULL; sp = subpartition_next(sp)) {
529 		if (strcmp(subpartition_get_mountpoint(sp), "swap") == 0) {
530 			command_add(cmds, "%s%s '/dev/%s\t\tnone\t\tswap\tsw\t\t0\t0' >>%smnt/etc/fstab",
531 			    a->os_root, cmd_name(a, "ECHO"),
532 			    subpartition_is_encrypted(sp) ?
533 			    "mapper/swap" : subpartition_get_device_name(sp),
534 			    a->os_root);
535 			if (subpartition_is_encrypted(sp)) {
536 				command_add(cmds,
537 				    "%s%s 'swap\t/dev/%s\tnone\tnone' >>%smnt/etc/crypttab",
538 				    a->os_root, cmd_name(a, "ECHO"),
539 				    subpartition_get_device_name(sp),
540 				    a->os_root);
541 			}
542 		} else if (use_hammer == 0) {
543 			if (strcmp(subpartition_get_mountpoint(sp), "/") == 0) {
544 				command_add(cmds, "%s%s '/dev/%s\t\t%s\t\tufs\trw\t\t1\t1' >>%smnt/etc/fstab",
545 				    a->os_root, cmd_name(a, "ECHO"),
546 				    subpartition_get_device_name(sp),
547 				    subpartition_get_mountpoint(sp),
548 				    a->os_root);
549 			} else if (subpartition_is_tmpfsbacked(sp)) {
550 				command_add(cmds, "%s%s 'tmpfs\t\t\t%s\t\ttmpfs\trw,-s%luM\t1\t1' >>%smnt/etc/fstab",
551 				    a->os_root, cmd_name(a, "ECHO"),
552 				    subpartition_get_mountpoint(sp),
553 				    subpartition_get_capacity(sp),
554 				    a->os_root);
555 			} else if (subpartition_is_encrypted(sp)) {
556 				command_add(cmds, "%s%s '%s\t/dev/%s\tnone\tnone' >>%smnt/etc/crypttab",
557 				    a->os_root, cmd_name(a, "ECHO"),
558 				    subpartition_get_mountpoint(sp) + 1,
559 				    subpartition_get_device_name(sp),
560 				    a->os_root);
561 				command_add(cmds, "%s%s '/dev/mapper/%s\t\t%s\t\tufs\trw\t\t2\t2' >>%smnt/etc/fstab",
562 				    a->os_root, cmd_name(a, "ECHO"),
563 				    subpartition_get_mountpoint(sp) + 1,
564 				    subpartition_get_mountpoint(sp),
565 				    a->os_root);
566 			} else {
567 				command_add(cmds, "%s%s '/dev/%s\t\t%s\t\tufs\trw\t\t2\t2' >>%smnt/etc/fstab",
568 				    a->os_root, cmd_name(a, "ECHO"),
569 				    subpartition_get_device_name(sp),
570 				    subpartition_get_mountpoint(sp),
571 				    a->os_root);
572 			}
573 		} else {
574 			if (strcmp(subpartition_get_mountpoint(sp), "/") == 0) {
575 				command_add(cmds, "%s%s '/dev/%s\t\t%s\t\thammer\trw\t\t1\t1' >>%smnt/etc/fstab",
576 				    a->os_root, cmd_name(a, "ECHO"),
577 				    subpartition_get_device_name(sp),
578 				    subpartition_get_mountpoint(sp),
579 				    a->os_root);
580 				if (subpartition_is_encrypted(sp)) {
581 					command_add(cmds,
582 					    "%s%s 'vfs.root.mountfrom=\"ufs:md0s0\"' >>%smnt/boot/loader.conf",
583 					    a->os_root, cmd_name(a, "ECHO"),
584 					    a->os_root);
585 					command_add(cmds,
586 					    "%s%s 'vfs.root.realroot=\"crypt:hammer:%s:root\"' >>%smnt/boot/loader.conf",
587 					    a->os_root, cmd_name(a, "ECHO"),
588 					    subpartition_get_device_name(sp),
589 					    a->os_root);
590 				} else {
591 					command_add(cmds,
592 					    "%s%s 'vfs.root.mountfrom=\"hammer:%s\"' >>%smnt/boot/loader.conf",
593 					    a->os_root, cmd_name(a, "ECHO"),
594 					    subpartition_get_device_name(sp),
595 					    a->os_root);
596 				}
597 			} else if (strcmp(subpartition_get_mountpoint(sp), "/boot") == 0) {
598 				command_add(cmds, "%s%s '/dev/%s\t\t%s\t\tufs\trw\t\t1\t1' >>%smnt/etc/fstab",
599 				    a->os_root, cmd_name(a, "ECHO"),
600 				    subpartition_get_device_name(sp),
601 				    subpartition_get_mountpoint(sp),
602 				    a->os_root);
603 			}
604 		}
605 	}
606 
607 	/*
608 	 * Take care of HAMMER PFS null mounts.
609 	 */
610 	if (use_hammer == 1) {
611 		for (j = 0; pfs_mountpt[j] != NULL; j++) {
612 			if (rindex(pfs_mountpt[j]+1, '/') != NULL)
613 				command_add(cmds, "%s%s '/pfs%s.%s\t%s\t\tnull\trw\t\t0\t0' >>%smnt/etc/fstab",
614 				    a->os_root, cmd_name(a, "ECHO"),
615 				    dirname(pfs_mountpt[j]),
616 				    basename(pfs_mountpt[j]),
617 				    pfs_mountpt[j],
618 				    a->os_root);
619 			else
620 				command_add(cmds, "%s%s '/pfs%s\t\t%s\t\tnull\trw\t\t0\t0' >>%smnt/etc/fstab",
621 				    a->os_root, cmd_name(a, "ECHO"),
622 				    pfs_mountpt[j],
623 				    pfs_mountpt[j],
624 				    a->os_root);
625 		}
626 	}
627 
628 	command_add(cmds, "%s%s '%s' >>%smnt/etc/fstab",
629 	    a->os_root, cmd_name(a, "ECHO"),
630 	    "proc\t\t\t/proc\t\tprocfs\trw\t\t0\t0",
631 	    a->os_root);
632 
633 	/* Backup the disklabel and the log. */
634 	command_add(cmds, "%s%s %s > %smnt/etc/disklabel.%s",
635 	    a->os_root, cmd_name(a, "DISKLABEL64"),
636 	    slice_get_device_name(storage_get_selected_slice(a->s)),
637 	    a->os_root,
638 	    slice_get_device_name(storage_get_selected_slice(a->s)));
639 
640 	/* 'chflags nohistory' as needed */
641 	for (j = 0; pfs_mountpt[j] != NULL; j++)
642 		if (pfs_nohistory[j] == 1)
643 			command_add(cmds, "%s%s -R nohistory %smnt%s",
644 			    a->os_root, cmd_name(a, "CHFLAGS"),
645 			    a->os_root, pfs_mountpt[j]);
646 
647 	/* Do some preparation if encrypted partitions were configured */
648 	if (needcrypt) {
649 		command_add(cmds,
650 		    "%s%s 'dm_load=\"yes\"' >>%smnt/boot/loader.conf",
651 		    a->os_root, cmd_name(a, "ECHO"),
652 		    a->os_root);
653 		command_add(cmds,
654 		    "%s%s 'dm_target_crypt_load=\"yes\"' >>%smnt/boot/loader.conf",
655 		    a->os_root, cmd_name(a, "ECHO"),
656 		    a->os_root);
657 		if (use_hammer) {
658 			command_add(cmds,
659 			    "%s%s 'initrd.img_load=\"YES\"' >>%smnt/boot/loader.conf",
660 			    a->os_root, cmd_name(a, "ECHO"),
661 			    a->os_root);
662 			command_add(cmds,
663 			    "%s%s 'initrd.img_type=\"md_image\"' >>%smnt/boot/loader.conf",
664 			    a->os_root, cmd_name(a, "ECHO"),
665 			    a->os_root);
666 		}
667 	}
668 
669 	/* Customize stuff here */
670 	if(is_file("%susr/local/bin/after_installation_routines.sh", a->os_root)) {
671 		command_add(cmds, "%susr/local/bin/after_installation_routines.sh",
672 		    a->os_root);
673 	}
674 
675 	/* Save the installation log. */
676 	command_add(cmds, "%s%s %sinstall.log %smnt/var/log/install.log",
677 	    a->os_root, cmd_name(a, "CP"),
678 	    a->tmp, a->os_root);
679 	command_add(cmds, "%s%s 600 %smnt/var/log/install.log",
680 	    a->os_root, cmd_name(a, "CHMOD"), a->os_root);
681 
682 	/*
683 	 * Do it!
684 	 */
685 	/* commands_preview(a->c, cmds); */
686 	if (!commands_execute(a, cmds)) {
687 		inform(a->c, _("%s was not fully installed."), OPERATING_SYSTEM_NAME);
688 		a->result = 0;
689 	} else {
690 		a->result = 1;
691 	}
692 	commands_free(cmds);
693 	cmds = commands_new();
694 
695 	if (a->result) {
696 		config_vars_write(rc_conf, CONFIG_TYPE_SH, "%smnt/etc/rc.conf",
697 		    a->os_root);
698 		config_vars_free(rc_conf);
699 		rc_conf = config_vars_new();
700 	}
701 
702 	/*
703 	 * Unmount everything we mounted on /mnt.  This is done in a seperate
704 	 * command chain, so that partitions are unmounted, even if an error
705 	 * occurs in one of the preceding commands, or it is cancelled.
706 	 */
707 	unmount_all_under(a, cmds, "%smnt", a->os_root);
708 
709 	/*
710 	 * Once everything is unmounted, if the install went successfully,
711 	 * make sure once and for all that the disklabel is bootable.
712 	 */
713 	if (a->result)
714 		command_add(cmds, "%s%s -B %s",
715 		    a->os_root, cmd_name(a, "DISKLABEL64"),
716 		    slice_get_device_name(storage_get_selected_slice(a->s)));
717 
718 	if (!commands_execute(a, cmds))
719 		inform(a->c, _("Warning: subpartitions were not correctly unmounted."));
720 
721 	commands_free(cmds);
722 
723 	/*
724 	 * Finally, remove all swap and any mappings.
725 	 */
726 	if (swapoff_all(a) == NULL)
727 		inform(a->c, _("Warning: swap could not be turned off."));
728 	if (remove_all_mappings(a) == NULL)
729 		inform(a->c, _("Warning: mappings could not be removed."));
730 }
731