diff --git a/share/installer/cmdnames.conf b/share/installer/cmdnames.conf
index 7c0209d..79f6df8 100644
--- a/share/installer/cmdnames.conf
+++ b/share/installer/cmdnames.conf
@@ -17,6 +17,7 @@ DATE=bin/date
 DD=bin/dd
 ECHO=bin/echo
 LN=bin/ln
+LS=bin/ls
 MKDIR=bin/mkdir
 MV=bin/mv
 RM=bin/rm
diff --git a/usr.sbin/installer/dfuibe_installer/flow.c b/usr.sbin/installer/dfuibe_installer/flow.c
index 96320f7..f532a81 100644
--- a/usr.sbin/installer/dfuibe_installer/flow.c
+++ b/usr.sbin/installer/dfuibe_installer/flow.c
@@ -1225,13 +1225,13 @@ state_create_subpartitions(struct i_fn_args *a)
 	 */
 	command_add(cmds, "%s%s -W %s",
 	    a->os_root, cmd_name(a, "DISKLABEL64"),
-	    slice_get_raw_device_name(storage_get_selected_slice(a->s)));
+	    slice_get_device_name(storage_get_selected_slice(a->s)));
 	command_add(cmds, "%s%s if=/dev/zero of=/dev/%s bs=32k count=16",
 	    a->os_root, cmd_name(a, "DD"),
-	    slice_get_raw_device_name(storage_get_selected_slice(a->s)));
+	    slice_get_device_name(storage_get_selected_slice(a->s)));
 	command_add(cmds, "%s%s -B -r -w %s auto",
 	    a->os_root, cmd_name(a, "DISKLABEL64"),
-	    slice_get_raw_device_name(storage_get_selected_slice(a->s)));
+	    slice_get_device_name(storage_get_selected_slice(a->s)));
 	commands_execute(a, cmds);
 	commands_free(cmds);
 
diff --git a/usr.sbin/installer/dfuibe_installer/fn_disk.c b/usr.sbin/installer/dfuibe_installer/fn_disk.c
index 55b1041..fe5aa89 100644
--- a/usr.sbin/installer/dfuibe_installer/fn_disk.c
+++ b/usr.sbin/installer/dfuibe_installer/fn_disk.c
@@ -205,7 +205,7 @@ fn_format_disk(struct i_fn_args *a)
 
 		command_add(cmds, "%s%s -BI %s",
 		    a->os_root, cmd_name(a, "FDISK"),
-		    disk_get_raw_device_name(storage_get_selected_disk(a->s)));
+		    disk_get_device_name(storage_get_selected_disk(a->s)));
 
 		if (!commands_execute(a, cmds)) {
 			inform(a->c, _("The disk\n\n%s\n\nwas "
@@ -298,7 +298,7 @@ fn_wipe_start_of_disk(struct i_fn_args *a)
 		    "%s%s if=%sdev/zero of=%sdev/%s bs=32k count=16",
 		    a->os_root, cmd_name(a, "DD"),
 		    a->os_root, a->os_root,
-		    disk_get_raw_device_name(storage_get_selected_disk(a->s)));
+		    disk_get_device_name(storage_get_selected_disk(a->s)));
 		if (commands_execute(a, cmds)) {
 			inform(a->c, _("Start of disk was successfully wiped."));
 		} else {
@@ -342,7 +342,7 @@ fn_wipe_start_of_slice(struct i_fn_args *a)
 		command_add(cmds, "%s%s if=%sdev/zero of=%sdev/%s bs=32k count=16",
 		    a->os_root, cmd_name(a, "DD"),
 		    a->os_root, a->os_root,
-		    slice_get_raw_device_name(storage_get_selected_slice(a->s)));
+		    slice_get_device_name(storage_get_selected_slice(a->s)));
 		if (commands_execute(a, cmds)) {
 			inform(a->c, _("Start of primary partition was successfully wiped."));
 		} else {
@@ -453,7 +453,7 @@ fn_install_bootblocks(struct i_fn_args *a)
 	for (d = storage_disk_first(a->s); d != NULL; d = disk_next(d)) {
 		ds = dfui_dataset_new();
 		/* XXX need to see how this is handled in OpenBSD/NetBSD */
-		dfui_dataset_celldata_add(ds, "disk", disk_get_raw_device_name(d));
+		dfui_dataset_celldata_add(ds, "disk", disk_get_device_name(d));
 		dfui_dataset_celldata_add(ds, "boot0cfg", "Y");
 		dfui_dataset_celldata_add(ds, "packet", "Y");
 		dfui_form_dataset_add(f, ds);
@@ -662,7 +662,7 @@ format_slice(struct i_fn_args *a)
 	 */
 	command_add(cmds, "%s%s -v -f %snew.fdisk %s",
 	    a->os_root, cmd_name(a, "FDISK"), a->tmp,
-	    disk_get_raw_device_name(storage_get_selected_disk(a->s)));
+	    disk_get_device_name(storage_get_selected_disk(a->s)));
 
 	/*
 	 * If there is an old 'virgin' disklabel hanging around
diff --git a/usr.sbin/installer/dfuibe_installer/fn_install.c b/usr.sbin/installer/dfuibe_installer/fn_install.c
index d24292e..0b2536b 100644
--- a/usr.sbin/installer/dfuibe_installer/fn_install.c
+++ b/usr.sbin/installer/dfuibe_installer/fn_install.c
@@ -122,6 +122,7 @@ handle_pfs(struct i_fn_args *a, struct commands *cmds)
 void
 fn_install_os(struct i_fn_args *a)
 {
+	struct disk *d;
 	struct subpartition *sp;
 	struct commands *cmds;
 	struct command *cmd;
@@ -529,8 +530,14 @@ fn_install_os(struct i_fn_args *a)
 	command_add(cmds, "%s%s %smnt/mnt",
 	    a->os_root, cmd_name(a, "MKDIR"), a->os_root);
 
-	/* Write new fstab. */
+	/* Write devtab entries if a serial number is available. */
+	for (d = storage_disk_first(a->s); d != NULL; d = disk_next(d))
+		if (disk_get_serno(d) != NULL)
+			command_add(cmds, "%s%s 'disk%d\t\tserno\t\t%s' >>%smnt/etc/devtab",
+			    a->os_root, cmd_name(a, "ECHO"),
+			    disk_get_number(d), disk_get_serno(d), a->os_root);
 
+	/* Write new fstab. */
 	command_add(cmds, "%s%s '%s' >%smnt/etc/fstab",
 	    a->os_root, cmd_name(a, "ECHO"),
 	    "# Device\t\tMountpoint\tFStype\tOptions\t\tDump\tPass#",
@@ -539,15 +546,15 @@ fn_install_os(struct i_fn_args *a)
 	for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
 	     sp != NULL; sp = subpartition_next(sp)) {
 		if (strcmp(subpartition_get_mountpoint(sp), "swap") == 0) {
-			command_add(cmds, "%s%s '/dev/%s\t\tnone\t\tswap\tsw\t\t0\t0' >>%smnt/etc/fstab",
+			command_add(cmds, "%s%s '%s\t\tnone\t\tswap\tsw\t\t0\t0' >>%smnt/etc/fstab",
 			    a->os_root, cmd_name(a, "ECHO"),
-			    subpartition_get_device_name(sp),
+			    subpartition_get_devtab_name(sp),
 			    a->os_root);
 		} else if (use_hammer == 0) {
 			if (strcmp(subpartition_get_mountpoint(sp), "/") == 0) {
-				command_add(cmds, "%s%s '/dev/%s\t\t%s\t\tufs\trw\t\t1\t1' >>%smnt/etc/fstab",
+				command_add(cmds, "%s%s '%s\t\t%s\t\tufs\trw\t\t1\t1' >>%smnt/etc/fstab",
 				    a->os_root, cmd_name(a, "ECHO"),
-				    subpartition_get_device_name(sp),
+				    subpartition_get_devtab_name(sp),
 				    subpartition_get_mountpoint(sp),
 				    a->os_root);
 			} else if (subpartition_is_mfsbacked(sp)) {
@@ -559,17 +566,17 @@ fn_install_os(struct i_fn_args *a)
 					subpartition_get_fsize(sp),
 					a->os_root);
 			} else {
-				command_add(cmds, "%s%s '/dev/%s\t\t%s\t\tufs\trw\t\t2\t2' >>%smnt/etc/fstab",
+				command_add(cmds, "%s%s '%s\t\t%s\t\tufs\trw\t\t2\t2' >>%smnt/etc/fstab",
 				    a->os_root, cmd_name(a, "ECHO"),
-				    subpartition_get_device_name(sp),
+				    subpartition_get_devtab_name(sp),
 				    subpartition_get_mountpoint(sp),
 				    a->os_root);
 			}
 		} else {
 			if (strcmp(subpartition_get_mountpoint(sp), "/") == 0) {
-				command_add(cmds, "%s%s '/dev/%s\t\t%s\t\thammer\trw\t\t1\t1' >>%smnt/etc/fstab",
+				command_add(cmds, "%s%s '%s\t\t%s\t\thammer\trw\t\t1\t1' >>%smnt/etc/fstab",
 				    a->os_root, cmd_name(a, "ECHO"),
-				    subpartition_get_device_name(sp),
+				    subpartition_get_devtab_name(sp),
 				    subpartition_get_mountpoint(sp),
 				    a->os_root);
 				command_add(cmds, "%s%s 'vfs.root.mountfrom=\"hammer:%s\"' >>%smnt/boot/loader.conf",
@@ -577,9 +584,9 @@ fn_install_os(struct i_fn_args *a)
 				    subpartition_get_device_name(sp),
 				    a->os_root);
 			} else if (strcmp(subpartition_get_mountpoint(sp), "/boot") == 0) {
-				command_add(cmds, "%s%s '/dev/%s\t\t%s\t\tufs\trw\t\t1\t1' >>%smnt/etc/fstab",
+				command_add(cmds, "%s%s '%s\t\t%s\t\tufs\trw\t\t1\t1' >>%smnt/etc/fstab",
 				    a->os_root, cmd_name(a, "ECHO"),
-				    subpartition_get_device_name(sp),
+				    subpartition_get_devtab_name(sp),
 				    subpartition_get_mountpoint(sp),
 				    a->os_root);
 			}
diff --git a/usr.sbin/installer/libinstaller/diskutil.c b/usr.sbin/installer/libinstaller/diskutil.c
index 94248f5..71e4917 100644
--- a/usr.sbin/installer/libinstaller/diskutil.c
+++ b/usr.sbin/installer/libinstaller/diskutil.c
@@ -162,6 +162,7 @@ disk_new(struct storage *s, const char *dev_name)
 
 	d->device = aura_strdup(dev_name);
 	d->desc = NULL;
+	d->serno = NULL;
 	d->we_formatted = 0;
 	d->capacity = 0;
 
@@ -236,19 +237,28 @@ disk_get_device_name(const struct disk *d)
 	return(tmp_dev_name);
 }
 
-/*
- * Returns the name of the device node used to represent the
- * raw disk device.
- * Note that the storage used for the returned string is static,
- * and the string is overwritten each time this function is called.
- */
 const char *
-disk_get_raw_device_name(const struct disk *d)
+disk_get_serno(const struct disk *d)
 {
-	static char tmp_dev_name[256];
+	return(d->serno);
+}
 
-	snprintf(tmp_dev_name, 256, "%s", d->device);
-	return(tmp_dev_name);
+void
+disk_set_serno(struct disk *d, const char *serno)
+{
+	d->serno = aura_strdup(serno);
+}
+
+int
+disk_get_number(const struct disk *d)
+{
+	return(d->number);
+}
+
+void
+disk_set_number(struct disk *d, const int number)
+{
+	d->number = number;
 }
 
 /*
@@ -429,21 +439,6 @@ slice_get_device_name(const struct slice *s)
 	return(tmp_dev_name);
 }
 
-/*
- * Returns the name of the device node used to represent
- * the raw slice.
- * Note that the storage used for the returned string is static,
- * and the string is overwritten each time this function is called.
- */
-const char *
-slice_get_raw_device_name(const struct slice *s)
-{
-	static char tmp_dev_name[256];
-
-	snprintf(tmp_dev_name, 256, "%ss%d", s->parent->device, s->number);
-	return(tmp_dev_name);
-}
-
 int
 slice_get_number(const struct slice *s)
 {
@@ -746,7 +741,7 @@ subpartition_get_pfs(const struct subpartition *sp)
 
 /*
  * Returns the name of the device node used to represent
- * the subpartition.
+ * the subpartition, either by serial number or traditional style.
  * Note that the storage used for the returned string is static,
  * and the string is overwritten each time this function is called.
  */
@@ -755,24 +750,31 @@ subpartition_get_device_name(const struct subpartition *sp)
 {
 	static char tmp_dev_name[256];
 
-	snprintf(tmp_dev_name, 256, "%ss%d%c", sp->parent->parent->device,
-	    sp->parent->number, sp->letter);
+	if (sp->parent->parent->serno != NULL)
+		snprintf(tmp_dev_name, 256, "serno/%s.s%d%c",
+		    sp->parent->parent->serno, sp->parent->number, sp->letter);
+	else
+		snprintf(tmp_dev_name, 256, "%ss%d%c",
+		    sp->parent->parent->device, sp->parent->number, sp->letter);
 	return(tmp_dev_name);
 }
 
 /*
- * Returns the name of the device node used to represent
- * the raw subpartition.
+ * Returns the devtab conversion label used to represent the subpartition.
  * Note that the storage used for the returned string is static,
  * and the string is overwritten each time this function is called.
  */
 const char *
-subpartition_get_raw_device_name(const struct subpartition *sp)
+subpartition_get_devtab_name(const struct subpartition *sp)
 {
 	static char tmp_dev_name[256];
 
-	snprintf(tmp_dev_name, 256, "r%ss%d%c", sp->parent->parent->device,
-	    sp->parent->number, sp->letter);
+	if (sp->parent->parent->serno != NULL)
+		snprintf(tmp_dev_name, 256, "disk%d.s%d%c",
+		    sp->parent->parent->number, sp->parent->number, sp->letter);
+	else
+		snprintf(tmp_dev_name, 256, "/dev/%ss%d%c",
+		    sp->parent->parent->device, sp->parent->number, sp->letter);
 	return(tmp_dev_name);
 }
 
diff --git a/usr.sbin/installer/libinstaller/diskutil.h b/usr.sbin/installer/libinstaller/diskutil.h
index 52a6324..3257be5 100644
--- a/usr.sbin/installer/libinstaller/diskutil.h
+++ b/usr.sbin/installer/libinstaller/diskutil.h
@@ -69,7 +69,9 @@ struct disk {
 	struct slice *slice_head;
 	struct slice *slice_tail;
 	char *desc;			/* from whereever we get the best */
+	int number;			/* Position in kern.disks */
 	char *device;			/* `ad0', `da1', and such */
+	char *serno;			/* serial number */
 	int cylinders;			/* geometry information */
 	int heads;
 	int sectors;			/* (sectors per track) */
@@ -127,10 +129,13 @@ struct disk		*disk_new(struct storage *, const char *);
 struct disk		*disk_find(const struct storage *, const char *);
 struct disk		*disk_next(const struct disk *);
 void			 disks_free(struct storage *);
+void			 disk_set_number(struct disk *, const int);
 void			 disk_set_desc(struct disk *, const char *);
+void			 disk_set_serno(struct disk *, const char *);
+int			 disk_get_number(const struct disk *);
 const char		*disk_get_desc(const struct disk *);
 const char		*disk_get_device_name(const struct disk *);
-const char		*disk_get_raw_device_name(const struct disk *);
+const char		*disk_get_serno(const struct disk *);
 struct slice		*disk_slice_first(const struct disk *);
 void			 disk_set_formatted(struct disk *, int);
 int			 disk_get_formatted(const struct disk *);
@@ -144,7 +149,6 @@ struct slice		*slice_next(const struct slice *);
 int			 slice_get_number(const struct slice *);
 const char		*slice_get_desc(const struct slice *);
 const char		*slice_get_device_name(const struct slice *);
-const char		*slice_get_raw_device_name(const struct slice *);
 unsigned long		 slice_get_capacity(const struct slice *);
 unsigned long		 slice_get_start(const struct slice *);
 unsigned long		 slice_get_size(const struct slice *);
@@ -165,7 +169,7 @@ struct subpartition	*subpartition_next(const struct subpartition *);
 int 			 subpartition_get_pfs(const struct subpartition *);
 const char		*subpartition_get_mountpoint(const struct subpartition *);
 const char		*subpartition_get_device_name(const struct subpartition *);
-const char		*subpartition_get_raw_device_name(const struct subpartition *);
+const char		*subpartition_get_devtab_name(const struct subpartition *);
 char			 subpartition_get_letter(const struct subpartition *);
 unsigned long		 subpartition_get_fsize(const struct subpartition *);
 unsigned long		 subpartition_get_bsize(const struct subpartition *);
diff --git a/usr.sbin/installer/libinstaller/survey.c b/usr.sbin/installer/libinstaller/survey.c
index ce81425..deedbc6 100644
--- a/usr.sbin/installer/libinstaller/survey.c
+++ b/usr.sbin/installer/libinstaller/survey.c
@@ -149,6 +149,7 @@ survey_storage(struct i_fn_args *a)
 	FILE *f;
 	char *filename;
 	struct disk *d = NULL;
+	int number = 0;
 	int failure = 0;
 	size_t len;
 	struct aura_dict *di;
@@ -219,8 +220,23 @@ survey_storage(struct i_fn_args *a)
 		    disk,
 		    a->tmp);
 		cmd = command_add(cmds, "%s%s '@END' >>%ssurvey.txt",
+ 		    a->os_root, cmd_name(a, "ECHO"), a->tmp);
+		command_set_log_mode(cmd, COMMAND_LOG_SILENT);
+
+		/*
+		 * Look for the disk's serial number.
+		 */
+		cmd = command_add(cmds, "%s%s '@SERNO' >>%ssurvey.txt",
 		    a->os_root, cmd_name(a, "ECHO"), a->tmp);
 		command_set_log_mode(cmd, COMMAND_LOG_SILENT);
+		cmd = command_add(cmds, "%s%s -l /dev/serno | %s%s \"`%s%s -l /dev/%s | %s%s '{print $5, $6;}'`\" | %s%s '{print $10;}' >>%ssurvey.txt",
+		    a->os_root, cmd_name(a, "LS"),
+		    a->os_root, cmd_name(a, "GREP"),
+		    a->os_root, cmd_name(a, "LS"),
+		    disk,
+		    a->os_root, cmd_name(a, "AWK"),
+		    a->os_root, cmd_name(a, "AWK"),
+		    a->tmp);
 
 		/*
 		 * Probe the disk with fdisk.
@@ -264,11 +280,16 @@ survey_storage(struct i_fn_args *a)
 		if (strcmp(line, "@DISK") == 0) {
 			if (fgets_chomp(line, 255, f)) {
 				d = disk_new(a->s, line);
+				disk_set_number(d, number++);
 			}
 		} else if (strcmp(line, "@DESC") == 0) {
 			while (d != NULL && strcmp(line, "@END") != 0 && fgets_chomp(line, 255, f)) {
 				disk_set_desc(d, line);
 			}
+		} else if (strcmp(line, "@SERNO") == 0) {
+			if (fgets_chomp(line, 255, f)) {
+				disk_set_serno(d, line);
+			}
 		} else if (strcmp(line, "@SLICES") == 0) {
 			int cyl, hd, sec;
 			int number, type, flags;
