Fix immutable flag handling in our mtree(8) invocations.
[dragonfly.git] / usr.sbin / installer / dfuibe_installer / fn_install.c
1 /*
2  * Copyright (c)2004,2015 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 /*
70  * NOTE: Even though /var/run doesn't need to be backed up, nearly all
71  *       services depend on it so it is best to leave it on the root.
72  */
73 static const char *nullfs_mountpt[] = {
74         "/usr/obj", "/var/crash", "/var/cache",
75         "/var/spool", "/var/log", "/var/tmp",
76         NULL };
77 static const char *nullfs_mountname[] = {
78         "/build/usr.obj", "/build/var.crash", "/build/var.cache",
79         "/build/var.spool", "/build/var.log", "/build/var.tmp",
80         NULL };
81
82 static void
83 handle_altfs(struct i_fn_args *a, struct commands *cmds)
84 {
85         int i;
86
87         /*
88          * Create directories for null mounts if not specified as a partition.
89          * (null mounts are from /build)
90          */
91         for (i = 0; nullfs_mountpt[i]; ++i) {
92                 if (subpartition_find(storage_get_selected_slice(a->s), "%s", nullfs_mountpt[i]) != NULL)
93                         continue;
94
95                 /*
96                  * Create directory infrastructure for null-mount if
97                  * necessary, then issue the null mount(s).
98                  */
99                 command_add(cmds, "%s%s -p %smnt%s",
100                             a->os_root, cmd_name(a, "MKDIR"),
101                             a->os_root, nullfs_mountname[i]);
102                 command_add(cmds, "%s%s -p %smnt%s",
103                             a->os_root, cmd_name(a, "MKDIR"),
104                             a->os_root, nullfs_mountpt[i]);
105                 command_add(cmds, "%s%s %smnt%s %smnt%s",
106                     a->os_root, cmd_name(a, "MOUNT_NULL"),
107                     a->os_root, nullfs_mountname[i],
108                     a->os_root, nullfs_mountpt[i]);
109         }
110
111         /*
112          * Create directory for /tmp and tmpfs mount if not specified as
113          * a partition.
114          */
115         if (subpartition_find(storage_get_selected_slice(a->s), "%s", "/tmp") == NULL) {
116                 command_add(cmds, "%s%s -p %smnt/tmp",
117                             a->os_root, cmd_name(a, "MKDIR"), a->os_root);
118                 command_add(cmds, "%s%s 1777 %smnt/tmp",
119                             a->os_root, cmd_name(a, "CHMOD"), a->os_root);
120                 command_add(cmds, "%s%s dummy %smnt/tmp",
121                             a->os_root, cmd_name(a, "MOUNT_TMPFS"), a->os_root);
122         }
123 }
124
125 static void
126 unmount_altfs(struct i_fn_args *a __unused, struct commands *cmds __unused)
127 {
128         return;
129 #if 0
130         int i;
131
132         /*
133          * Unmount null mounts
134          */
135         i = sizeof(nullfs_mountpt) / sizeof(nullfs_mountpt[0]) - 1;
136         while (i >= 0) {
137                 if (subpartition_find(storage_get_selected_slice(a->s), "%s", nullfs_mountpt[i]) != NULL)
138                         continue;
139
140                 /*
141                  * Create directory infrastructure for null-mount if
142                  * necessary, then issue the null mount(s).
143                  */
144                 command_add(cmds, "%s%s %smnt%s",
145                             a->os_root, cmd_name(a, "UMOUNT"),
146                             a->os_root, nullfs_mountpt[i]);
147                 --i;
148         }
149
150         /*
151          * Unmount tmpfs mounts
152          */
153         if (subpartition_find(storage_get_selected_slice(a->s), "%s", "/tmp") == NULL) {
154                 command_add(cmds, "%s%s -p %smnt%s",
155                             a->os_root, cmd_name(a, "UMOUNT"),
156                             a->os_root, "/tmp");
157         }
158 #endif
159 }
160
161 /*
162  * fn_install_os: actually put DragonFly on a disk.
163  */
164 void
165 fn_install_os(struct i_fn_args *a)
166 {
167         struct subpartition *sp, *spnext;
168         struct commands *cmds;
169         struct command *cmd;
170         int i, seen_it, prefix, j, needcrypt;
171         FILE *sources_conf;
172         char line[256];
173         char cp_src[64][256];
174         char file_path[256];
175         char *string;
176         int lines = 0;
177         int nfsidx;
178
179         /*
180          * Read SOURCES_CONF_FILE and populate our copy sources.
181          */
182         snprintf(file_path, 256, "%s%s", a->os_root, SOURCES_CONF_FILE);
183         sources_conf = fopen(file_path, "r");
184         i_log(a, "Reading %s", file_path);
185         while(fgets(line, 256, sources_conf) != NULL && lines < 63) {
186                 if(strlen(line)>0)
187                         line[strlen(line)-1] = '\0';
188                 strlcpy(cp_src[lines], line, 256);
189                 i_log(a,"Adding %s to copy source table.", cp_src[lines]);
190                 lines++;
191         }
192         i_log(a,"Added %i total items to copy source table.", lines);
193         strcpy(cp_src[lines], "");
194         fclose(sources_conf);
195
196         cmds = commands_new();
197
198         /*
199          * If swap isn't mounted yet, mount it.
200          */
201         if (measure_activated_swap(a) == 0) {
202                 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
203                     sp != NULL; sp = subpartition_next(sp)) {
204                         if (!subpartition_is_swap(sp))
205                                 continue;
206                         command_add(cmds, "%s%s /dev/%s",
207                             a->os_root,
208                             cmd_name(a, "SWAPON"),
209                             subpartition_is_encrypted(sp) ?
210                             "mapper/swap" : subpartition_get_device_name(sp));
211                 }
212         }
213
214         /*
215          * Unmount anything already mounted on /mnt.
216          */
217         unmount_altfs(a, cmds);
218         unmount_all_under(a, cmds, "%smnt", a->os_root);
219
220         /* Check if crypto support is needed */
221         needcrypt = 0;
222         for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
223              sp != NULL; sp = subpartition_next(sp)) {
224                 if (subpartition_is_encrypted(sp)) {
225                         needcrypt = 1;
226                         break;
227                 }
228         }
229
230         for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
231              sp != NULL; sp = subpartition_next(sp)) {
232                 if (strcmp(subpartition_get_mountpoint(sp), "/") == 0 ||
233                     strcmp(subpartition_get_mountpoint(sp), "/build") == 0) {
234                         /* make sure mountpoint directory exists */
235                         command_add(cmds, "%s%s -p %smnt%s",
236                                     a->os_root, cmd_name(a, "MKDIR"),
237                                     a->os_root,
238                                     subpartition_get_mountpoint(sp));
239                         switch(use_hammer) {
240                         case 1:
241                                 command_add(cmds, "%s%s /dev/%s %smnt%s",
242                                     a->os_root, cmd_name(a, "MOUNT_HAMMER"),
243                                     (subpartition_is_encrypted(sp) ?
244                                         subpartition_get_mapper_name(sp, 0) :
245                                         subpartition_get_device_name(sp)),
246                                     a->os_root,
247                                     subpartition_get_mountpoint(sp));
248                                 break;
249                         case 2:
250                                 command_add(cmds, "%s%s /dev/%s %smnt%s",
251                                     a->os_root, cmd_name(a, "MOUNT_HAMMER2"),
252                                     (subpartition_is_encrypted(sp) ?
253                                         subpartition_get_mapper_name(sp, 0) :
254                                         subpartition_get_device_name(sp)),
255                                     a->os_root,
256                                     subpartition_get_mountpoint(sp));
257                                 break;
258                         case 0:
259                         default:
260                                 command_add(cmds, "%s%s /dev/%s %smnt%s",
261                                     a->os_root, cmd_name(a, "MOUNT"),
262                                     (subpartition_is_encrypted(sp) ?
263                                         subpartition_get_mapper_name(sp, 0) :
264                                         subpartition_get_device_name(sp)),
265                                     a->os_root,
266                                     subpartition_get_mountpoint(sp));
267                                 break;
268                         }
269                 }
270         }
271
272         /*
273          * Create mount points and mount subpartitions on them.
274          */
275         for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
276              sp != NULL; sp = subpartition_next(sp)) {
277                 if (subpartition_is_swap(sp)) {
278                         /*
279                          * Set this subpartition as the dump device.
280                          */
281                         command_add(cmds, "%s%s off",
282                             a->os_root, cmd_name(a, "DUMPON"));
283                         command_add(cmds, "%s%s -v /dev/%s",
284                             a->os_root, cmd_name(a, "DUMPON"),
285                             subpartition_is_encrypted(sp) ?
286                             "mapper/swap" : subpartition_get_device_name(sp));
287
288                         asprintf(&string, "/dev/%s",
289                             subpartition_is_encrypted(sp) ?
290                             "mapper/swap" : subpartition_get_device_name(sp));
291                         config_var_set(rc_conf, "dumpdev", string);
292                         free(string);
293                         continue;
294                 }
295
296                 /*
297                  * mount everything except / and /build (which have already
298                  * been mounted).  This should also get /boot.
299                  */
300                 if (strcmp(subpartition_get_mountpoint(sp), "/") != 0 &&
301                     strcmp(subpartition_get_mountpoint(sp), "/build") != 0) {
302                         /* make sure mountpoint directory exists */
303                         command_add(cmds, "%s%s -p %smnt%s",
304                             a->os_root, cmd_name(a, "MKDIR"),
305                             a->os_root,
306                             subpartition_get_mountpoint(sp));
307                         /* Don't mount it if it's TMPFS-backed. */
308                         if (subpartition_is_tmpfsbacked(sp))
309                                 continue;
310                         command_add(cmds, "%s%s /dev/%s %smnt%s",
311                             a->os_root, cmd_name(a, "MOUNT"),
312                             (subpartition_is_encrypted(sp) ?
313                                 subpartition_get_mapper_name(sp, 0) :
314                                 subpartition_get_device_name(sp)),
315                             a->os_root,
316                             subpartition_get_mountpoint(sp));
317                 }
318         }
319
320         /*
321          * Take care of tmpfs and null-mounts from /build
322          */
323         handle_altfs(a, cmds);
324
325         /*
326          * Actually copy files now.
327          */
328         for (i = 0; cp_src[i] != NULL && cp_src[i][0] != '\0'; i++) {
329                 char *src, *dest, *dn, *tmp_dest;
330
331                 dest = cp_src[i];
332
333                 /*
334                  * If dest would be on an TMPFS-backed
335                  * mountpoint, don't bother copying it.
336                  */
337                 sp = subpartition_of(storage_get_selected_slice(a->s),
338                                      "%s%s", a->os_root, &dest[1]);
339                 if (sp != NULL && subpartition_is_tmpfsbacked(sp)) {
340                         continue;
341                 }
342
343                 /*
344                  * Create intermediate directories, if needed.
345                  */
346                 tmp_dest = aura_strdup(dest);
347                 dn = dirname(tmp_dest);
348                 if (is_dir("%s%s", a->os_root, &dn[1]) &&
349                     !is_dir("%smnt%s", a->os_root, dn)) {
350                         command_add(cmds, "%s%s -p %smnt%s",
351                             a->os_root, cmd_name(a, "MKDIR"),
352                             a->os_root, dn);
353                 }
354                 aura_free(tmp_dest, "directory name");
355
356                 /*
357                  * If a directory by the same name but with the suffix
358                  * ".hdd" exists on the installation media, cpdup that
359                  * instead.  This is particularly useful with /etc, which
360                  * may have significantly different behaviour on the
361                  * live CD compared to a standard HDD boot.
362                  */
363                 if (is_dir("%s%s.hdd", a->os_root, &dest[1]))
364                         asprintf(&src, "%s.hdd", &dest[1]);
365                 else
366                         asprintf(&src, "%s", &dest[1]);
367
368                 /*
369                  * Cpdup the chosen file or directory onto the HDD.
370                  * if it exists on the source.
371                  */
372                 if (is_dir("%s%s", a->os_root, src) ||
373                     is_file("%s%s", a->os_root, src)) {
374                         cmd = command_add(cmds, "%s%s %s%s %smnt%s",
375                             a->os_root, cmd_name(a, "CPDUP"),
376                             a->os_root, src,
377                             a->os_root, dest);
378                         command_set_log_mode(cmd, COMMAND_LOG_QUIET);
379                 }
380         }
381
382         /*
383          * Now, because cpdup does not cross mount points,
384          * we must copy anything that the user might've made a
385          * seperate mount point for (e.g. /usr/libdata/lint.)
386          */
387         nfsidx = 0;
388         sp = NULL;
389         spnext = slice_subpartition_first(storage_get_selected_slice(a->s));
390
391         for (;;) {
392                 const char *mountpt;
393
394                 /*
395                  * Iterate nullfs mounts and then partitions
396                  */
397                 if (nullfs_mountpt[nfsidx]) {
398                         mountpt = nullfs_mountpt[nfsidx];
399                         ++nfsidx;
400                 } else {
401                         sp = spnext;
402                         if (sp == NULL)
403                                 break;
404                         spnext = subpartition_next(sp);
405                         mountpt = subpartition_get_mountpoint(sp);
406                 }
407
408                 /*
409                  * If the subpartition is a swap subpartition or an
410                  * TMPFS-backed mountpoint, don't try to copy anything
411                  * into it.
412                  */
413                 if (sp) {
414                         if (subpartition_is_swap(sp) ||
415                             subpartition_is_tmpfsbacked(sp)) {
416                                 continue;
417                         }
418                 }
419
420                 /*
421                  * If the mountpoint doesn't even exist on the installation
422                  * medium, don't try to copy anything from it!  We assume
423                  * it's an empty subpartition for the user's needs.
424                  */
425                 if (!is_dir("%s%s", a->os_root, mountpt + 1))
426                         continue;
427
428                 /*
429                  * Don't bother copying the mountpoint IF:
430                  * - we've already said to copy it, or something besides it
431                  *   (it's a prefix of something in cp_src); or
432                  * - we haven't said to copy it
433                  *   (nothing in cp_src is a prefix of it.)
434                  */
435                 seen_it = 0;
436                 prefix = 0;
437                 for (i = 0; cp_src[i] != NULL && cp_src[i][0] != '\0'; i++) {
438                         if (strncmp(mountpt, cp_src[i],
439                             strlen(mountpt)) == 0) {
440                                 seen_it = 1;
441                                 break;
442                         }
443                         if (strncmp(cp_src[i], mountpt, strlen(cp_src[i])) == 0) {
444                                 prefix = 1;
445                         }
446                 }
447                 if (seen_it || !prefix)
448                         continue;
449
450                 /*
451                  * Otherwise, cpdup the subpartition.
452                  *
453                  * XXX check for .hdd-extended source dirs here, too,
454                  * eventually - but for now, /etc.hdd will never be
455                  * the kind of tricky sub-mount-within-a-mount-point
456                  * that this part of the code is meant to handle.
457                  */
458                 cmd = command_add(cmds, "%s%s %s%s %smnt%s",
459                         a->os_root, cmd_name(a, "CPDUP"),
460                         a->os_root, mountpt + 1,
461                         a->os_root, mountpt);
462                 command_set_log_mode(cmd, COMMAND_LOG_QUIET);
463         }
464
465         /*
466          * XXX This should not be needed. It was added to fix /var/run/sem
467          *     issues, see d4c25c30fc5f9ffeb258150a9590ef56954435bb.
468          *
469          * Ensure /var has all directories it needs.
470          */
471         command_add(cmds, "%s%s -deiU -f %setc/mtree/BSD.var.dist -p %smnt/var",
472             a->os_root, cmd_name(a, "MTREE"), a->os_root, a->os_root);
473
474         /*
475          * Create symlinks.
476          */
477
478         /* Take care of /sys. */
479         command_add(cmds, "%s%s -s usr/src/sys %smnt/sys",
480             a->os_root, cmd_name(a, "LN"), a->os_root);
481
482         /*
483          * Make sure /home exists (goes on root mount otherwise).
484          */
485         command_add(cmds, "%s%s -p %smnt/home",
486                     a->os_root, cmd_name(a, "MKDIR"), a->os_root);
487
488         /*
489          * XXX check for other possible combinations too?
490          */
491
492         /*
493          * Clean up.  In case some file didn't make it, use rm -f
494          */
495         command_add(cmds, "%s%s -f %smnt/boot/loader.conf",
496             a->os_root, cmd_name(a, "RM"), a->os_root);
497         command_add(cmds, "%s%s -f %smnt/tmp/install.log",
498             a->os_root, cmd_name(a, "RM"), a->os_root);
499         command_add(cmds, "%s%s -f %smnt/tmp/t[12]",
500             a->os_root, cmd_name(a, "RM"), a->os_root);
501         command_add(cmds, "%s%s -f %smnt/tmp/test_in",
502             a->os_root, cmd_name(a, "RM"), a->os_root);
503         command_add(cmds, "%s%s -f %smnt/tmp/test_out",
504             a->os_root, cmd_name(a, "RM"), a->os_root);
505
506         /*
507          * Copy pristine versions over any files we might have installed.
508          * This allows the resulting file tree to be customized.
509          */
510         for (i = 0; cp_src[i] != NULL && cp_src[i][0] != '\0'; i++) {
511                 char *src, *dest, *dn, *tmp_dest;
512
513                 src = cp_src[i];
514                 dest = cp_src[i];
515
516                 /*
517                  * Get the directory that the desired thing to
518                  * copy resides in.
519                  */
520                 tmp_dest = aura_strdup(dest);
521                 dn = dirname(tmp_dest);
522
523                 /*
524                  * If this dir doesn't exist in PRISTINE_DIR
525                  * on the install media, just skip it.
526                  */
527                 if (!is_dir("%s%s%s", a->os_root, PRISTINE_DIR, dn)) {
528                         aura_free(tmp_dest, _("directory name"));
529                         continue;
530                 }
531
532                 /*
533                  * Create intermediate directories, if needed.
534                  */
535                 if (!is_dir("%smnt%s", a->os_root, dn)) {
536                         command_add(cmds, "%s%s -p %smnt%s",
537                             a->os_root, cmd_name(a, "MKDIR"),
538                             a->os_root, dn);
539                 }
540                 aura_free(tmp_dest, "directory name");
541
542                 /*
543                  * Cpdup the chosen file or directory onto the HDD.
544                  */
545                 cmd = command_add(cmds, "%s%s %s%s %smnt%s",
546                     a->os_root, cmd_name(a, "CPDUP"),
547                     a->os_root, src,
548                     a->os_root, dest);
549
550                 cmd = command_add(cmds,
551                     "%s%s %s%s%s %smnt%s",
552                     a->os_root, cmd_name(a, "CPDUP"),
553                     a->os_root, PRISTINE_DIR, src,
554                     a->os_root, dest);
555                 command_set_log_mode(cmd, COMMAND_LOG_QUIET);
556         }
557
558         /*
559          * Rebuild the user database, to get rid of any extra users
560          * from the LiveCD that aren't supposed to be installed
561          * (copying a pristine master.passwd isn't enough.)
562          */
563         command_add(cmds, "%s%s -p -d %smnt/etc %smnt/etc/master.passwd",
564             a->os_root, cmd_name(a, "PWD_MKDB"), a->os_root, a->os_root);
565
566         /*
567          * Create missing directories for special mounts.
568          */
569         command_add(cmds, "%s%s %smnt/proc",
570             a->os_root, cmd_name(a, "MKDIR"), a->os_root);
571         command_add(cmds, "%s%s %smnt/dev",
572             a->os_root, cmd_name(a, "MKDIR"), a->os_root);
573         command_add(cmds, "%s%s %smnt/mnt",
574             a->os_root, cmd_name(a, "MKDIR"), a->os_root);
575
576         /* Write new fstab. */
577         command_add(cmds, "%s%s '%s' >%smnt/etc/fstab",
578             a->os_root, cmd_name(a, "ECHO"),
579             "# Device\t\tMountpoint\tFStype\tOptions\t\tDump\tPass#",
580             a->os_root);
581
582         for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
583              sp != NULL; sp = subpartition_next(sp)) {
584                 if (strcmp(subpartition_get_mountpoint(sp), "swap") == 0) {
585                         command_add(cmds, "%s%s '/dev/%s\t\tnone\t\tswap\tsw\t\t0\t0' >>%smnt/etc/fstab",
586                             a->os_root, cmd_name(a, "ECHO"),
587                             subpartition_is_encrypted(sp) ?
588                             "mapper/swap" : subpartition_get_device_name(sp),
589                             a->os_root);
590                         if (subpartition_is_encrypted(sp)) {
591                                 command_add(cmds,
592                                     "%s%s 'swap\t/dev/%s\tnone\tnone' >>%smnt/etc/crypttab",
593                                     a->os_root, cmd_name(a, "ECHO"),
594                                     subpartition_get_device_name(sp),
595                                     a->os_root);
596                         }
597                 } else {
598                         const char *fsname;
599                         int order;
600
601                         /*
602                          * fs type (/boot is always ufs)
603                          */
604                         if (strcmp(subpartition_get_mountpoint(sp), "/boot") == 0)
605                                 fsname = "ufs";
606                         else if (use_hammer == 2)
607                                 fsname = "hammer2";
608                         else if (use_hammer)
609                                 fsname = "hammer";
610                         else
611                                 fsname = "ufs";
612
613                         if (strcmp(subpartition_get_mountpoint(sp), "/") == 0)
614                                 order = 1;
615                         else
616                                 order = 2;
617
618                         /*
619                          * Adjust loader.conf for root partition
620                          */
621                         if (strcmp(subpartition_get_mountpoint(sp), "/") == 0) {
622                                 if (subpartition_is_encrypted(sp)) {
623                                         command_add(cmds,
624                                             "%s%s 'vfs.root.mountfrom=\"ufs:md0s0\"' >>%smnt/boot/loader.conf",
625                                             a->os_root, cmd_name(a, "ECHO"),
626                                             a->os_root);
627                                         command_add(cmds,
628                                             "%s%s 'vfs.root.realroot=\"crypt:%s:%s:%s\"' >>%smnt/boot/loader.conf",
629                                             a->os_root, cmd_name(a, "ECHO"),
630                                             fsname,
631                                             subpartition_get_device_name(sp),
632                                             subpartition_get_mapper_name(sp, -1),
633                                             a->os_root);
634                                 } else {
635                                         command_add(cmds,
636                                             "%s%s 'vfs.root.mountfrom=\"%s:%s\"' >>%smnt/boot/loader.conf",
637                                             a->os_root, cmd_name(a, "ECHO"),
638                                             fsname,
639                                             subpartition_get_device_name(sp),
640                                             a->os_root);
641                                 }
642                         }
643                         if (subpartition_is_tmpfsbacked(sp)) {
644                                 command_add(cmds, "%s%s 'tmpfs\t\t\t%s\t\ttmpfs\trw,-s%luM\t1\t1' >>%smnt/etc/fstab",
645                                     a->os_root, cmd_name(a, "ECHO"),
646                                     subpartition_get_mountpoint(sp),
647                                     subpartition_get_capacity(sp),
648                                     a->os_root);
649                         } else if (subpartition_is_encrypted(sp)) {
650                                 if (strcmp(subpartition_get_mapper_name(sp, -1), "root") != 0) {
651                                         command_add(cmds, "%s%s '%s\t/dev/%s\tnone\tnone' >>%smnt/etc/crypttab",
652                                             a->os_root, cmd_name(a, "ECHO"),
653                                             subpartition_get_mapper_name(sp, -1),
654                                             subpartition_get_device_name(sp),
655                                             a->os_root);
656                                 }
657                                 command_add(cmds, "%s%s '/dev/%s\t\t%s\t\t%s\trw\t\t2\t2' >>%smnt/etc/fstab",
658                                     a->os_root, cmd_name(a, "ECHO"),
659                                     subpartition_get_mapper_name(sp, 0),
660                                     subpartition_get_mountpoint(sp),
661                                     fsname,
662                                     a->os_root);
663                         } else {
664                                 command_add(cmds, "%s%s '/dev/%s\t\t%s\t\t%s\trw\t\t%d\t%d' >>%smnt/etc/fstab",
665                                     a->os_root, cmd_name(a, "ECHO"),
666                                     subpartition_get_device_name(sp),
667                                     subpartition_get_mountpoint(sp),
668                                     fsname,
669                                     order, order,
670                                     a->os_root);
671                         }
672                 }
673         }
674
675         /*
676          * Take care of NULL mounts from /build for things like /var/crash
677          * and /usr/obj if not specified as a discrete partition.
678          */
679         for (j = 0; nullfs_mountpt[j] != NULL; j++) {
680                 if (subpartition_find(storage_get_selected_slice(a->s),
681                                       "%s", nullfs_mountpt[j]) != NULL) {
682                         continue;
683                 }
684                 command_add(cmds,
685                     "%s%s '%s\t%s\t\tnull\trw\t\t0\t0' >>%smnt/etc/fstab",
686                     a->os_root, cmd_name(a, "ECHO"),
687                     nullfs_mountname[j],
688                     nullfs_mountpt[j],
689                     a->os_root);
690         }
691
692         /*
693          * Take care of /tmp as a tmpfs filesystem
694          */
695         if (subpartition_find(storage_get_selected_slice(a->s), "/tmp") == NULL) {
696                 command_add(cmds,
697                     "%s%s 'tmpfs\t/tmp\t\ttmpfs\trw\t\t0\t0' >>%smnt/etc/fstab",
698                     a->os_root, cmd_name(a, "ECHO"), a->os_root);
699         }
700
701         /*
702          * Take care of /proc
703          */
704         command_add(cmds, "%s%s '%s' >>%smnt/etc/fstab",
705             a->os_root, cmd_name(a, "ECHO"),
706             "proc\t\t\t/proc\t\tprocfs\trw\t\t0\t0",
707             a->os_root);
708
709         /* Backup the disklabel and the log. */
710         command_add(cmds, "%s%s %s > %smnt/etc/disklabel.%s",
711             a->os_root, cmd_name(a, "DISKLABEL64"),
712             slice_get_device_name(storage_get_selected_slice(a->s)),
713             a->os_root,
714             slice_get_device_name(storage_get_selected_slice(a->s)));
715
716 #if 0
717         /* 'chflags nohistory' as needed */
718         for (j = 0; pfs_mountpt[j] != NULL; j++)
719                 if (pfs_nohistory[j] == 1)
720                         command_add(cmds, "%s%s -R nohistory %smnt%s",
721                             a->os_root, cmd_name(a, "CHFLAGS"),
722                             a->os_root, pfs_mountpt[j]);
723 #endif
724
725         /* Do some preparation if encrypted partitions were configured */
726         if (needcrypt) {
727                 command_add(cmds,
728                     "%s%s 'dm_load=\"yes\"' >>%smnt/boot/loader.conf",
729                     a->os_root, cmd_name(a, "ECHO"),
730                     a->os_root);
731                 command_add(cmds,
732                     "%s%s 'dm_target_crypt_load=\"yes\"' >>%smnt/boot/loader.conf",
733                     a->os_root, cmd_name(a, "ECHO"),
734                     a->os_root);
735                 command_add(cmds,
736                     "%s%s 'initrd.img_load=\"YES\"' >>%smnt/boot/loader.conf",
737                     a->os_root, cmd_name(a, "ECHO"),
738                     a->os_root);
739                 command_add(cmds,
740                     "%s%s 'initrd.img_type=\"md_image\"' >>%smnt/boot/loader.conf",
741                     a->os_root, cmd_name(a, "ECHO"),
742                     a->os_root);
743         }
744
745         /* Customize stuff here */
746         if(is_file("%susr/local/bin/after_installation_routines.sh", a->os_root)) {
747                 command_add(cmds, "%susr/local/bin/after_installation_routines.sh",
748                     a->os_root);
749         }
750
751         /* Save the installation log. */
752         command_add(cmds, "%s%s %sinstall.log %smnt/var/log/install.log",
753             a->os_root, cmd_name(a, "CP"),
754             a->tmp, a->os_root);
755         command_add(cmds, "%s%s 600 %smnt/var/log/install.log",
756             a->os_root, cmd_name(a, "CHMOD"), a->os_root);
757
758         /*
759          * Do it!
760          */
761         /* commands_preview(a->c, cmds); */
762         if (!commands_execute(a, cmds)) {
763                 inform(a->c, _("%s was not fully installed."), OPERATING_SYSTEM_NAME);
764                 a->result = 0;
765         } else {
766                 a->result = 1;
767         }
768         commands_free(cmds);
769         cmds = commands_new();
770
771         if (a->result) {
772                 config_vars_write(rc_conf, CONFIG_TYPE_SH, "%smnt/etc/rc.conf",
773                     a->os_root);
774                 config_vars_free(rc_conf);
775                 rc_conf = config_vars_new();
776         }
777
778         /*
779          * Unmount everything we mounted on /mnt.  This is done in a seperate
780          * command chain, so that partitions are unmounted, even if an error
781          * occurs in one of the preceding commands, or it is cancelled.
782          */
783         unmount_altfs(a, cmds);
784         unmount_all_under(a, cmds, "%smnt", a->os_root);
785
786         /*
787          * Once everything is unmounted, if the install went successfully,
788          * make sure once and for all that the disklabel is bootable.
789          */
790         if (a->result)
791                 command_add(cmds, "%s%s -B %s",
792                     a->os_root, cmd_name(a, "DISKLABEL64"),
793                     slice_get_device_name(storage_get_selected_slice(a->s)));
794
795         if (!commands_execute(a, cmds))
796                 inform(a->c, _("Warning: subpartitions were not correctly unmounted."));
797
798         commands_free(cmds);
799
800         /*
801          * Finally, remove all swap and any mappings.
802          */
803         if (swapoff_all(a) == NULL)
804                 inform(a->c, _("Warning: swap could not be turned off."));
805         if (remove_all_mappings(a) == NULL)
806                 inform(a->c, _("Warning: mappings could not be removed."));
807 }