diff --git a/distrib/utils/sysinst/Makefile.inc b/distrib/utils/sysinst/Makefile.inc
index 19c67d8..ff14908 100644
--- a/distrib/utils/sysinst/Makefile.inc
+++ b/distrib/utils/sysinst/Makefile.inc
@@ -64,6 +64,7 @@ COPTS.mbr.c += -Wno-format-nonliteral
 COPTS.msg_defs.c += -Wno-format-nonliteral
 COPTS.bsddisklabel.c += -Wno-format-nonliteral
 COPTS.md.c += -Wno-format-nonliteral
+COPTS.partman.c += -Wno-format-nonliteral
 
 # Host to ftp from.  Default:
 #	"ftp.NetBSD.org"
diff --git a/distrib/utils/sysinst/bsddisklabel.c b/distrib/utils/sysinst/bsddisklabel.c
index 745cdf1..888e1e6 100644
--- a/distrib/utils/sysinst/bsddisklabel.c
+++ b/distrib/utils/sysinst/bsddisklabel.c
@@ -52,8 +52,6 @@
 #include "msg_defs.h"
 #include "menu_defs.h"
 
-static int check_partitions(void);
-
 /* For the current state of this file blame abs@NetBSD.org */
 /* Even though he wasn't the last to hack it, but he did admit doing so :-) */
 
@@ -91,6 +89,7 @@ save_ptn(int ptn, daddr_t start, daddr_t size, int fstype, const char *mountpt)
 	static int maxptn;
 	partinfo *p;
 	int pp;
+	char *buf;
 
 	if (maxptn == 0)
 		maxptn = getmaxpartitions();
@@ -119,12 +118,20 @@ save_ptn(int ptn, daddr_t start, daddr_t size, int fstype, const char *mountpt)
 	p->pi_size = size;
 	set_ptype(p, fstype, mountpt ? PIF_NEWFS : 0);
 
-	if (mountpt != NULL) {
+	/* Hack because we does not have something like FS_LVMPV */
+	p->lvmpv = 0;
+	if (mountpt != NULL && strcmp(mountpt, "lvm") == 0)
+		p->lvmpv = 1;
+	else if (mountpt != NULL) {
 		for (pp = 0; pp < maxptn; pp++) {
 			if (strcmp(pm->bsdlabel[pp].pi_mount, mountpt) == 0)
 				pm->bsdlabel[pp].pi_flags &= ~PIF_MOUNT;
 		}
-		strlcpy(p->pi_mount, mountpt, sizeof p->pi_mount);
+		if (mountpt[0] != '/')
+			asprintf(&buf, "/%s", mountpt);
+		else
+			asprintf(&buf, "%s", mountpt);
+		strlcpy(p->pi_mount, buf, sizeof p->pi_mount);
 		p->pi_flags |= PIF_MOUNT;
 		/* Default to logging, UFS2. */
 		if (p->pi_fstype == FS_BSDFFS) {
@@ -136,6 +143,7 @@ save_ptn(int ptn, daddr_t start, daddr_t size, int fstype, const char *mountpt)
 				p->pi_flags |= PIF_FFSv2;
 #endif
 		}
+		free(buf);
 	}
 
 	return ptn;
@@ -218,7 +226,7 @@ set_ptn_size(menudesc *m, void *arg)
 		return 0;
 
 	if (p->mount[0] == 0) {
-		msg_prompt_win(partman_go?"Mountpoint or 'raid' or 'cgd'?":MSG_askfsmount,
+		msg_prompt_win(partman_go?MSG_askfsmountadv:MSG_askfsmount,
 			-1, 18, 0, 0, NULL, p->mount, sizeof p->mount);
 		if (p->mount[0] == 0)
 			return 0;
@@ -346,6 +354,7 @@ get_ptn_sizes(daddr_t part_start, daddr_t sectors, int no_swap)
 	int sm;				/* sectors in 1MB */
 	struct ptn_size *p;
 	daddr_t size;
+	static int swap_created = 0, root_created = 0;
 
 	if (pm->pi.menu_no < 0)
 	pm->pi = (struct ptn_info) { -1, {
@@ -382,7 +391,7 @@ get_ptn_sizes(daddr_t part_start, daddr_t sectors, int no_swap)
 
 	if (pm->pi.menu_no < 0) {
 		/* If there is a swap partition elsewhere, don't add one here.*/
-		if (no_swap) {
+		if (no_swap || (swap_created && partman_go)) {
 			pm->pi.ptn_sizes[PI_SWAP].size = 0;
 		} else {
 #if DEFSWAPSIZE == -1
@@ -451,6 +460,11 @@ get_ptn_sizes(daddr_t part_start, daddr_t sectors, int no_swap)
 			pm->pi.free_space -= i;
 		}
 
+		if (root_created && partman_go) {
+			pm->pi.ptn_sizes[PI_ROOT].size = 0;
+			pm->pi.pool_part = 0;
+		}
+
 		/* Ensure all of / is readable by the system boot code */
 		i = pm->pi.ptn_sizes[PI_ROOT].limit;
 		if (i != 0 && (i -= pm->pi.ptn_sizes[PI_ROOT].size) < 0) {
@@ -519,7 +533,11 @@ get_ptn_sizes(daddr_t part_start, daddr_t sectors, int no_swap)
 		}
 		if (size == 0)
 			continue;
+		if (i == PART_ROOT && size > 0)
+			root_created = 1;
 		if (i == PART_SWAP) {
+			if (size > 0)
+				swap_created = 1;
 			save_ptn(i, part_start, size, FS_SWAP, NULL);
 			continue;
 		}
@@ -528,7 +546,7 @@ get_ptn_sizes(daddr_t part_start, daddr_t sectors, int no_swap)
 			continue;			
 		} else if (!strcmp(p->mount, "cgd")) {
 			save_ptn(i, part_start, size, FS_CGD, NULL);
-			continue;						
+			continue;
 		}
 		save_ptn(i, part_start, size, FS_BSDFFS, p->mount);
 	}
@@ -708,16 +726,20 @@ make_bsd_partitions(void)
 
 	if (layoutkind == LY_SETNEW)
 		get_ptn_sizes(partstart, ptend - partstart, no_swap);
-
-	if (layoutkind == LY_NEWRAID) {
+	
+	else if (layoutkind == LY_NEWRAID) {
 		set_ptype(&(pm->bsdlabel[PART_E]), FS_RAID, 0);
 		pm->bsdlabel[PART_E].pi_size = pm->ptsize;
 	}
-
-	if (layoutkind == LY_NEWCGD) {
+	else if (layoutkind == LY_NEWCGD) {
 		set_ptype(&(pm->bsdlabel[PART_E]), FS_CGD, 0);
 		pm->bsdlabel[PART_E].pi_size = pm->ptsize;
 	}
+	else if (layoutkind == LY_NEWLVM) {
+		set_ptype(&(pm->bsdlabel[PART_E]), FS_BSDFFS, 0);
+		pm->bsdlabel[PART_E].pi_size = pm->ptsize;
+		pm->bsdlabel[PART_E].lvmpv = 1;
+	}
 
 	/*
 	 * OK, we have a partition table. Give the user the chance to
@@ -737,7 +759,8 @@ make_bsd_partitions(void)
 			sizeof pm->bsddiskname);
 
 	/* save label to disk for MI code to update. */
-	(void) savenewlabel(pm->bsdlabel, maxpart);
+	if (! partman_go)
+		(void) savenewlabel(pm->bsdlabel, maxpart);
 
 	/* Everything looks OK. */
 	return (1);
@@ -746,11 +769,11 @@ make_bsd_partitions(void)
 /*
  * check that there is at least a / somewhere.
  */
-static int
+int
 check_partitions(void)
 {
 #ifdef HAVE_BOOTXX_xFS
-	int rv;
+	int rv = 1;
 	char *bootxx;
 #endif
 #ifndef HAVE_UFS2_BOOT
diff --git a/distrib/utils/sysinst/configmenu.c b/distrib/utils/sysinst/configmenu.c
index 0530c23..1d2c50d 100644
--- a/distrib/utils/sysinst/configmenu.c
+++ b/distrib/utils/sysinst/configmenu.c
@@ -69,6 +69,9 @@ enum {
 	CONFIGOPT_NTPDATE,
 	CONFIGOPT_MDNSD,
 	CONFIGOPT_XDM,
+	CONFIGOPT_CGD,
+	CONFIGOPT_LVM,
+	CONFIGOPT_RAIDFRAME,
 	CONFIGOPT_LAST
 };
 
@@ -92,10 +95,12 @@ configinfo config_list[] = {
 	{MSG_enable_ntpd, CONFIGOPT_NTPD, "ntpd", toggle_rcvar, NULL},
 	{MSG_run_ntpdate, CONFIGOPT_NTPDATE, "ntpdate", toggle_rcvar, NULL},
 	{MSG_enable_mdnsd, CONFIGOPT_MDNSD, "mdnsd", toggle_rcvar, NULL},
-	{"Enable XDM", CONFIGOPT_XDM, "xdm", toggle_rcvar, NULL},
-	{"Enable CGD", CONFIGOPT_XDM, "cgd", toggle_rcvar, NULL},
+	{MSG_enable_xdm, CONFIGOPT_XDM, "xdm", toggle_rcvar, NULL},
+	{MSG_enable_cgd, CONFIGOPT_CGD, "cgd", toggle_rcvar, NULL},
+	{MSG_enable_lvm, CONFIGOPT_LVM, "lvm", toggle_rcvar, NULL},
+	{MSG_enable_raid, CONFIGOPT_RAIDFRAME, "raidframe", toggle_rcvar, NULL},
 	{NULL,		CONFIGOPT_LAST,	NULL, NULL, NULL}
-}; // TODO: XDM
+};
 
 static void
 config_list_init(void)
@@ -414,7 +419,7 @@ do_configmenu()
 
 	/* if the target isn't mounted already, figure it out. */
 	if (target_mounted() == 0) {
-		partman_go = 1;
+		partman_go = 0;
 		if (find_disks(msg_string(MSG_configure_prior)) < 0)
 			return;
 
diff --git a/distrib/utils/sysinst/defs.h b/distrib/utils/sysinst/defs.h
index 6cae884..6b56f0f 100644
--- a/distrib/utils/sysinst/defs.h
+++ b/distrib/utils/sysinst/defs.h
@@ -38,8 +38,10 @@
 /* defs.h -- definitions for use in the sysinst program. */
 
 /* System includes needed for this. */
+#include <sys/queue.h>
 #include <sys/types.h>
 #include <sys/disklabel.h>
+#include <sys/disk.h>
 
 const char *getfslabelname(uint8_t);
 
@@ -51,7 +53,6 @@ deconst(const void *p)
 
 #include "msg_defs.h"
 #include "menu_defs.h"
-#include "mbr.h" // TODO: sss
 
 #define min(a,b)	((a) < (b) ? (a) : (b))
 #define max(a,b)	((a) > (b) ? (a) : (b))
@@ -85,10 +86,7 @@ deconst(const void *p)
 #define RUN_XFER_DIR	0x0200		/* cd to xfer_dir in child */
 
 /* for bsddisklabel.c */
-#define LY_SETNEW 1
-#define LY_NEWRAID 2
-#define LY_NEWCGD 3
-#define LY_USEEXIST 4
+enum { LY_SETNEW, LY_NEWRAID, LY_NEWCGD, LY_NEWLVM, LY_USEEXIST };
 
 /* Installation sets */
 enum {
@@ -191,6 +189,7 @@ typedef struct distinfo {
 	const char	*marker_file;	/* set assumed installed if exists */
 } distinfo;
 
+#define MOUNTLEN 20
 typedef struct _partinfo {
 	struct partition pi_partition;
 #define pi_size		pi_partition.p_size
@@ -199,7 +198,7 @@ typedef struct _partinfo {
 #define pi_fstype	pi_partition.p_fstype
 #define pi_frag		pi_partition.p_frag
 #define pi_cpg		pi_partition.p_cpg
-	char	pi_mount[20];
+	char	pi_mount[MOUNTLEN];
 	uint	pi_isize;		/* bytes per inode (for # inodes) */
 	uint	pi_flags;
 #define PIF_NEWFS	0x0001		/* need to 'newfs' partition */
@@ -217,13 +216,15 @@ typedef struct _partinfo {
 #define PIF_RESET	0x1000		/* internal - restore previous values */
     const char *mnt_opts;
     const char *fsname;
+    char mounted[MOUNTLEN];
+    int lvmpv; /* should we use partition as LVM PV? */
 } partinfo;	/* Single partition from a disklabel */
 
 struct ptn_info {
 	int		menu_no;
 	struct ptn_size {
 		int	ptn_id;
-		char	mount[20];
+		char	mount[MOUNTLEN];
 		daddr_t	dflt_size;
 		daddr_t	size;
 		int	limit;
@@ -251,7 +252,6 @@ int layoutkind;
 int sizemult;
 const char *multname;
 int partman_go; /* run extended partition manager */
-int fstab_prepared; /* Should we create new /etc/fstab or append old? */
 
 /* logging variables */
 
@@ -268,22 +268,26 @@ daddr_t tmp_ramdisk_size;
 
 unsigned int root_limit;    /* BIOS (etc) read limit */
 
-/* All information that is unique for each drive */
 enum SHRED_T { SHRED_NONE=0, SHRED_ZEROS, SHRED_RANDOM, SHRED_CRYPTO };
+
+/* All information that is unique for each drive */
+SLIST_HEAD(pm_head_t, pm_devs_t) pm_head;
+
 typedef struct pm_devs_t {
-    int changed; /* Flag indicating to partman that device need saving */
+    int unsaved; /* Flag indicating to partman that device need saving */
     int found; /* Flag to delete unplugged and unconfigured devices */
+    int blocked; /* Device is busy and cannot be changed */
+    void *refdev; /* If device is blocked thats is a pointers to a parent dev */
+    int isspecial; /* LVM LV or DK device that doesnot accept disklabel */
     char diskdev[SSTRSIZE]; /* Actual name of the disk. */
     char diskdev_descr[STRSIZE];
-    char id_dk[SSTRSIZE];
     int bootable;
 #define DISKNAME_SIZE 16
     char bsddiskname[DISKNAME_SIZE];
     partinfo oldlabel[MAXPARTITIONS]; /* What we found on the disk */
     partinfo bsdlabel[MAXPARTITIONS]; /* What we want it to look like */
-    mbr_info_t mbr;
+    int gpt;
     int no_mbr; /* set for raid (etc) */
-    int use_gpt;
     int rootpart; /* partition we install into */
     const char *disktype; /* ST506, SCSI, ... */
     const char *doessf;
@@ -295,11 +299,31 @@ typedef struct pm_devs_t {
     /* If we have an MBR boot partition, start and size in sectors */
     int bootstart, bootsize;
     struct ptn_info pi;
-    struct pm_devs_t *next;
+    SLIST_ENTRY(pm_devs_t) l;
 } pm_devs_t;
 pm_devs_t *pm; /* Pointer to currend device with which we work */
-pm_devs_t *pm_head; /* Pointer to head of list with all devices */
-pm_devs_t *pm_found; /* Pointer for next allocating device in find_disks() */
+pm_devs_t *pm_new; /* Pointer for next allocating device in find_disks() */
+
+#define MAX_WEDGES 16 /* num of dk* devices */
+typedef struct pm_wedge_t {
+    int allocated;
+    int todel;
+    pm_devs_t *pm;
+    int ptn;
+} pm_wedge_t;
+pm_wedge_t wedges[MAX_WEDGES];
+
+/* Generic structure for partman */
+typedef struct {
+    int retvalue;
+    int dev_num;
+    int wedge_num;
+    void *dev_ptr;
+    int dev_ptr_delta;
+    char fullname[SSTRSIZE];
+    enum {PM_DISK_T=1, PM_PART_T, PM_WEDGE_T, PM_SPEC_T, PM_RAID_T, PM_CGD_T,
+        PM_VND_T, PM_LVM_T, PM_LVMLV_T} type;
+} part_entry_t;
 
 /* Relative file name for storing a distribution. */
 char xfer_dir[STRSIZE];
@@ -414,15 +438,10 @@ int	mount_disks(void);
 int	set_swap(const char *, partinfo *);
 int	check_swap(const char *, int);
 char *bootxx_name(void);
-const char *fstype_name(int);
 void label_read(void);
+int get_dkwedges(struct dkwedge_info **, const char *);
+const char *get_gptfs_by_id(int);
 
-/* from partman.c */
-int	partman(void);
-int partman_mountmenu(void);
-int partman_shred(char *, int);
-int partman_unconfigure(void);
-int partman_cgd_edit_adddisk(int, pm_devs_t *);
 
 /* from disks_lfs.c */
 int	fs_is_lfs(void *);
@@ -435,6 +454,8 @@ int	edit_and_check_label(partinfo *, int, int, int);
 void	set_bsize(partinfo *, int);
 void	set_fsize(partinfo *, int);
 void	set_ptype(partinfo *, int, int);
+int edit_ptn(menudesc *, void *);
+int checkoverlap(partinfo *, int, int, int);
 
 /* from install.c */
 void	do_install(void);
@@ -536,6 +557,7 @@ void	dup_file_into_target(const char *);
 void	mv_within_target_or_die(const char *, const char *);
 int	cp_within_target(const char *, const char *, int);
 int	target_mount(const char *, const char *, int, const char *);
+int target_mount_do(const char *, const char *, const char *);
 int	target_test(unsigned int, const char *);
 int	target_dir_exists_p(const char *);
 int	target_file_exists_p(const char *);
@@ -543,6 +565,21 @@ int	target_symlink_exists_p(const char *);
 void	unwind_mounts(void);
 int	target_mounted(void);
 
+/* from partman.c */
+int partman(void);
+int pm_partusage(pm_devs_t *, int, int);
+int pm_getrefdev(pm_devs_t *);
+void pm_setfstype(pm_devs_t *, int, int);
+int pm_editpart(int);
+void pm_rename(pm_devs_t *);
+int pm_shred(pm_devs_t *, int, int);
+void pm_umount(pm_devs_t *, int);
+int pm_unconfigure(pm_devs_t *);
+int pm_cgd_edit(void *, part_entry_t *);
+int pm_gpt_convert(pm_devs_t *);
+void pm_wedges_fill(pm_devs_t *);
+void pm_make_bsd_partitions(pm_devs_t *);
+
 /* from bsddisklabel.c */
 int	make_bsd_partitions(void);
 int	save_ptn(int, daddr_t, daddr_t, int, const char *);
@@ -550,6 +587,7 @@ void	set_ptn_titles(menudesc *, int, void *);
 void	set_ptn_menu(struct ptn_info *);
 int	set_ptn_size(menudesc *, void *);
 void	get_ptn_sizes(daddr_t, daddr_t, int);
+int check_partitions(void);
 
 /* from aout2elf.c */
 int move_aout_libs(void);
diff --git a/distrib/utils/sysinst/disks.c b/distrib/utils/sysinst/disks.c
index 5400696..251eb54 100644
--- a/distrib/utils/sysinst/disks.c
+++ b/distrib/utils/sysinst/disks.c
@@ -41,6 +41,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <util.h>
+#include <uuid.h>
 
 #include <sys/param.h>
 #include <sys/swap.h>
@@ -48,6 +49,7 @@
 #include <ufs/ffs/fs.h>
 #define FSTYPENAMES
 #include <sys/disklabel.h>
+#include <sys/disklabel_gpt.h>
 
 #include <dev/scsipi/scsipi_all.h>
 #include <sys/scsiio.h>
@@ -73,6 +75,29 @@ struct disk_desc {
 	uint	dd_totsec;
 };
 
+/* gpt(8) use different filesystem names.
+   So, we cant use ./common/lib/libutil/getfstypename.c */
+struct gptfs_t {
+    const char *name;
+    int id;
+    uuid_t uuid;
+};
+static const struct gptfs_t gpt_filesystems[] = {
+    { "swap", FS_SWAP, GPT_ENT_TYPE_NETBSD_SWAP, },
+    { "ffs", FS_BSDFFS, GPT_ENT_TYPE_NETBSD_FFS, },
+    { "lfs", FS_BSDLFS, GPT_ENT_TYPE_NETBSD_LFS, },
+    { "linux", FS_EX2FS, GPT_ENT_TYPE_LINUX_DATA, },
+    { "windows,", FS_MSDOS, GPT_ENT_TYPE_MS_BASIC_DATA, },
+    { "hfs", FS_HFS, GPT_ENT_TYPE_APPLE_HFS, },
+    { "ufs", FS_OTHER, GPT_ENT_TYPE_APPLE_UFS, },
+    { "ccd", FS_CCD, GPT_ENT_TYPE_NETBSD_CCD, },
+    { "raid", FS_RAID, GPT_ENT_TYPE_NETBSD_RAIDFRAME, },
+    { "cgd", FS_CGD, GPT_ENT_TYPE_NETBSD_CGD, },
+    { "efi", FS_OTHER, GPT_ENT_TYPE_EFI, },
+    { "bios", FS_OTHER, GPT_ENT_TYPE_BIOS, },
+    { NULL, -1, GPT_ENT_TYPE_UNUSED, },
+};
+
 /* Local prototypes */
 static int foundffs(struct data *, size_t);
 #ifdef USE_SYSVBFS
@@ -80,6 +105,8 @@ static int foundsysvbfs(struct data *, size_t);
 #endif
 static int fsck_preen(const char *, int, const char *);
 static void fixsb(const char *, const char *, char);
+static int is_gpt(const char *);
+static int incoregpt(pm_devs_t *, partinfo *);
 
 #ifndef DISK_NAMES
 #define DISK_NAMES "wd", "sd", "ld", "raid"
@@ -296,7 +323,7 @@ get_descr(struct disk_desc *dd)
 	/* try SCSI */
 	if (get_descr_scsi(dd, fd))
 		goto done;
-	/* TODO: get description from raid, cgd, vnd... */
+	/* XXX: get description from raid, cgd, vnd... */
 
 done:
 	if (fd >= 0)
@@ -355,10 +382,10 @@ find_disks(const char *doingwhat)
 	struct disk_desc disks[MAX_DISKS];
 	menu_ent dsk_menu[nelem(disks) + 1]; // + 1 for extended partitioning entry
 	struct disk_desc *disk;
-	pm_devs_t *pm_i, *pm_swap;
 	int i, already_found;
 	int numdisks, selected_disk = -1;
 	int menu_no;
+	pm_devs_t *pm_i, *pm_last = NULL;
 
 	/* Find disks. */
 	numdisks = get_disks(disks);
@@ -369,7 +396,10 @@ find_disks(const char *doingwhat)
 	/* Kill typeahead, it won't be what the user had in mind */
 	fpurge(stdin);
 
-	if (! partman_go) {
+	/* partman_go: <0 - we want to see menu with extended partitioning
+				  ==0 - we want to see simple select disk menu
+				   >0 - we do not want to see any menus, just detect all disks */
+	if (partman_go <= 0) {
 		if (numdisks == 0) {
 			/* No disks found! */
 			msg_display(MSG_nodisk);
@@ -384,14 +414,14 @@ find_disks(const char *doingwhat)
 				dsk_menu[i].opt_flags = OPT_EXIT;
 				dsk_menu[i].opt_action = set_menu_select;
 			}
-			
-			dsk_menu[i].opt_name = "Extended partitioning"; // TODO: localize
-			dsk_menu[i].opt_menu = OPT_NOMENU;
-			dsk_menu[i].opt_flags = OPT_EXIT;
-			dsk_menu[i].opt_action = set_menu_select;
-
+			if (partman_go < 0) {
+				dsk_menu[i].opt_name = MSG_partman;
+				dsk_menu[i].opt_menu = OPT_NOMENU;
+				dsk_menu[i].opt_flags = OPT_EXIT;
+				dsk_menu[i].opt_action = set_menu_select;
+			}
 			menu_no = new_menu(MSG_Available_disks,
-				dsk_menu, numdisks + 1, -1, 4, 0, 0, MC_SCROLL,
+				dsk_menu, numdisks + ((partman_go<0)?1:0), -1, 4, 0, 0, MC_SCROLL,
 				NULL, NULL, NULL, NULL, NULL);
 			if (menu_no == -1)
 				return -1;
@@ -399,18 +429,15 @@ find_disks(const char *doingwhat)
 			process_menu(menu_no, &selected_disk);
 			free_menu(menu_no);
 		}
-		if (selected_disk == numdisks) {
+		if (partman_go < 0 && selected_disk == numdisks) {
 			partman_go = 1;
 	    	return -2;
-		}
+		} else
+			partman_go = 0;
 		if (selected_disk < 0 || selected_disk >= numdisks)
 	    	return -1;
 	}
 
-	/* Mark all devicec as not found */
-	for (pm_i = pm_head->next; partman_go && pm_i != NULL;
-		 pm_i = pm_i->next)
-			pm_i->found = 0;
 	/* Fill pm struct with device(s) info */
 	for (i = 0; i < numdisks; i++) {
 		if (! partman_go)
@@ -418,17 +445,19 @@ find_disks(const char *doingwhat)
 		else {
 			disk = disks + i;
 			already_found = 0;
-			for (pm_i = pm_head; pm_i->next != NULL; pm_i = pm_i->next)
+			SLIST_FOREACH(pm_i, &pm_head, l) {
+				pm_last = pm_i;
 				if (!already_found && 
-						strcmp(pm_i->next->diskdev, disk->dd_name) == 0) {
-					pm_i->next->found = 1;
-					already_found = 1;
+						strcmp(pm_i->diskdev, disk->dd_name) == 0) {
+					pm_i->found = 1;
+					break;
 				}
-			if (already_found)
+			}
+			if (pm_i != NULL && pm_i->found)
 				/* We already added this device, skipping */
 				continue;
 		}
-		pm = pm_found;
+		pm = pm_new;
 		pm->found = 1;
 		pm->bootable = 0;
 		pm->pi.menu_no = -1;
@@ -439,20 +468,19 @@ find_disks(const char *doingwhat)
 		/* Use as a default disk if the user has the sets on a local disk */
 		strlcpy(localfs_dev, disk->dd_name, sizeof localfs_dev);
 
+		pm->gpt = is_gpt(pm->diskdev);
+		pm->no_mbr = disk->dd_no_mbr || pm->gpt;
 		pm->sectorsize = disk->dd_secsize;
 		pm->dlcyl = disk->dd_cyl;
 		pm->dlhead = disk->dd_head;
 		pm->dlsec = disk->dd_sec;
 		pm->dlsize = disk->dd_totsec;
-		pm->no_mbr = disk->dd_no_mbr;
 		if (pm->dlsize == 0)
 			pm->dlsize = disk->dd_cyl * disk->dd_head * disk->dd_sec;
-		if (pm->dlsize > UINT32_MAX) {
+		if (pm->dlsize > UINT32_MAX && ! partman_go) {
 			if (logfp)
 				fprintf(logfp, "Cannot process disk %s: too big size (%d)\n",
-					pm->diskdev, (int)pm->dlsize); // TODO: localize
-			if (partman_go)
-				continue;
+					pm->diskdev, (int)pm->dlsize);
 			msg_display(MSG_toobigdisklabel);
 			process_menu(MENU_ok, NULL);
 			return -1;
@@ -461,28 +489,18 @@ find_disks(const char *doingwhat)
 
 		label_read();
 		if (partman_go) {
-			pm_i->next = pm_found;
-			pm_found = malloc(sizeof (pm_devs_t));
-			memset(pm_found, 0, sizeof *pm_found);
-			pm_found->next = NULL;
+			pm_getrefdev(pm_new);
+			if (SLIST_EMPTY(&pm_head) || pm_last == NULL)
+				 SLIST_INSERT_HEAD(&pm_head, pm_new, l);
+			else
+				 SLIST_INSERT_AFTER(pm_last, pm_new, l);
+			pm_new = malloc(sizeof (pm_devs_t));
+			memset(pm_new, 0, sizeof *pm_new);
 		} else
 			/* We is not in partman and do not want to process all devices, exit */
 			break;
 	}
-	for (pm_i = pm_head; partman_go && pm_i->next != NULL;
-			pm_i = pm_i->next)
-		if (! pm_i->next->found) {
-			/* If device not found then delete it */
-			if (pm_i->next->next == NULL) {
-				free(pm_i->next);
-				pm_i->next = NULL;
-				break;
-			} else {
-				pm_swap = pm_i->next->next;
-				free(pm_i->next);
-				pm_i->next = pm_swap;
-			}
-		}
+
 	return numdisks;
 }
 
@@ -491,10 +509,14 @@ label_read(void)
 {
 	/* Get existing/default label */
 	memset(&pm->oldlabel, 0, sizeof pm->oldlabel);
-	incorelabel(pm->diskdev, pm->oldlabel);
+	if (! pm->gpt)
+		incorelabel(pm->diskdev, pm->oldlabel);
+	else
+		incoregpt(pm, pm->oldlabel);
 	/* Set 'target' label to current label in case we don't change it */
 	memcpy(&pm->bsdlabel, &pm->oldlabel, sizeof pm->bsdlabel);
-	savenewlabel(pm->oldlabel, getmaxpartitions());
+	if (! pm->gpt)
+		savenewlabel(pm->oldlabel, getmaxpartitions());
 }
 
 void
@@ -583,7 +605,7 @@ make_filesystems(void)
 	int ptn_order[nelem(pm->bsdlabel)];
 	int error = 0;
 	unsigned int maxpart = getmaxpartitions();
-	char *newfs;
+	char *newfs = NULL, *dev = NULL, *devdev = NULL;
 	partinfo *lbl;
 
 	if (maxpart > nelem(pm->bsdlabel))
@@ -612,6 +634,18 @@ make_filesystems(void)
 			/* No mount point */
 			continue;
 
+		if (pm->isspecial) {
+			asprintf(&dev, "%s", pm->diskdev);
+			ptn = 0 - 'a';
+		} else {
+			asprintf(&dev, "%s%c", pm->diskdev, 'a' + ptn);
+		}
+		if (dev == NULL)
+			return (ENOMEM);
+		asprintf(&devdev, "/dev/%s", dev);
+		if (devdev == NULL)
+			return (ENOMEM);
+
 		newfs = NULL;
 		lbl->mnt_opts = NULL;
 		lbl->fsname = NULL;
@@ -667,21 +701,20 @@ make_filesystems(void)
 			if (lbl->pi_fstype == FS_MSDOS) {
 			        /* newfs only if mount fails */
 			        if (run_program(RUN_SILENT | RUN_ERROR_OK,
-				    "mount -rt msdos /dev/%s%c /mnt2",
-				    pm->diskdev, 'a' + ptn) != 0)
+				    "mount -rt msdos /dev/%s /mnt2", dev) != 0)
 					error = run_program(
 					    RUN_DISPLAY | RUN_PROGRESS,
-					    "%s /dev/r%s%c",
-					    newfs, pm->diskdev, 'a' + ptn);
+					    "%s /dev/r%s",
+					    newfs, dev);
 				else {
-			        	run_program(RUN_SILENT | RUN_ERROR_OK,
+			        run_program(RUN_SILENT | RUN_ERROR_OK,
 					    "umount /mnt2");
 					error = 0;
 				}
 			} else
 #endif
 			error = run_program(RUN_DISPLAY | RUN_PROGRESS,
-			    "%s /dev/r%s%c", newfs, pm->diskdev, 'a' + ptn);
+			    "%s /dev/r%s", newfs, dev);
 		} else {
 			/* We'd better check it isn't dirty */
 			error = fsck_preen(pm->diskdev, ptn, lbl->fsname);
@@ -690,20 +723,21 @@ make_filesystems(void)
 		if (error != 0)
 			return error;
 
+		lbl->pi_flags ^= PIF_NEWFS;
 		md_pre_mount();
 
 		if (partman_go == 0 && lbl->pi_flags & PIF_MOUNT &&
 				lbl->mnt_opts != NULL) {
 			make_target_dir(lbl->pi_mount);
-			error = target_mount(lbl->mnt_opts, pm->diskdev, ptn,
-					    lbl->pi_mount);
+			error = target_mount_do(lbl->mnt_opts, devdev, lbl->pi_mount);
 			if (error) {
-				msg_display(MSG_mountfail,
-					    pm->diskdev, 'a' + ptn, lbl->pi_mount);
+				msg_display(MSG_mountfail, dev, ' ', lbl->pi_mount);
 				process_menu(MENU_ok, NULL);
 				return error;
 			}
 		}
+		free(devdev);
+		free(dev);
 	}
 	return 0;
 }
@@ -714,16 +748,14 @@ make_fstab(void)
 	FILE *f;
 	int i, swap_dev = -1;
 	const char *dump_dev;
+	char *dev = NULL;
+	pm_devs_t *pm_i, *pm_with_swap;
 
 	/* Create the fstab. */
-	if (fstab_prepared == 0) {
-		make_target_dir("/etc");
-		f = target_fopen("/etc/fstab", "w");
-		scripting_fprintf(NULL, "cat <<EOF >%s/etc/fstab\n", target_prefix());
-	} else {
-		f = target_fopen("/etc/fstab", "a");
-		scripting_fprintf(NULL, "cat <<EOF >>%s/etc/fstab\n", target_prefix());
-	}
+	make_target_dir("/etc");
+	f = target_fopen("/etc/fstab", "w");
+	scripting_fprintf(NULL, "cat <<EOF >%s/etc/fstab\n", target_prefix());
+
 	if (logfp)
 		(void)fprintf(logfp,
 		    "Making %s/etc/fstab (%s).\n", target_prefix(), pm->diskdev);
@@ -739,112 +771,138 @@ make_fstab(void)
 		f = stdout;
 #endif
 	}
-	if (!fstab_prepared)
-		scripting_fprintf(f, "# NetBSD %s/etc/fstab\n# See /usr/share/examples/"
-			"fstab/ for more examples.\n", target_prefix());
-	for (i = 0; i < getmaxpartitions(); i++) {
-		const char *s = "";
-		const char *mp = pm->bsdlabel[i].pi_mount;
-		const char *fstype = "ffs";
-		int fsck_pass = 0, dump_freq = 0;
-
-		if (!*mp) {
-			/*
-			 * No mount point specified, comment out line and
-			 * use /mnt as a placeholder for the mount point.
-			 */
-			s = "# ";
-			mp = "/mnt";
-		}
 
-		switch (pm->bsdlabel[i].pi_fstype) {
-		case FS_UNUSED:
-			continue;
-		case FS_BSDLFS:
-			/* If there is no LFS, just comment it out. */
-			if (!check_lfs_progs())
+	scripting_fprintf(f, "# NetBSD %s/etc/fstab\n# See /usr/share/examples/"
+			"fstab/ for more examples.\n", target_prefix());
+	if (! partman_go) {
+		/* We want to process only one disk... */
+		pm_i = pm;
+		goto onlyonediskinfstab;
+	}
+	SLIST_FOREACH(pm_i, &pm_head, l) {
+		onlyonediskinfstab:
+		for (i = 0; i < getmaxpartitions(); i++) {
+			const char *s = "";
+			const char *mp = pm_i->bsdlabel[i].pi_mount;
+			const char *fstype = "ffs";
+			int fsck_pass = 0, dump_freq = 0;
+			
+			if (dev != NULL)
+				free(dev);
+			if (pm_i->isspecial)
+				asprintf(&dev, "%s", pm_i->diskdev);
+			else
+				asprintf(&dev, "%s%c", pm_i->diskdev, 'a' + i);
+			if (dev == NULL)
+				return (ENOMEM);
+
+			if (!*mp) {
+				/*
+				 * No mount point specified, comment out line and
+				 * use /mnt as a placeholder for the mount point.
+				 */
 				s = "# ";
-			fstype = "lfs";
-			/* XXX fsck_lfs considered harmfull */
-			fsck_pass = 0;
-			dump_freq = 1;
-			break;
-		case FS_BSDFFS:
-			fsck_pass = (strcmp(mp, "/") == 0) ? 1 : 2;
-			dump_freq = 1;
-			break;
-		case FS_MSDOS:
-			fstype = "msdos";
-			break;
-		case FS_SWAP:
-			if (swap_dev == -1) {
-				swap_dev = i;
-				dump_dev = ",dp";
-			} else {
-				dump_dev ="";
+				mp = "/mnt";
 			}
-			scripting_fprintf(f, "/dev/%s%c\t\tnone\tswap\tsw%s\t\t 0 0\n",
-				pm->diskdev, 'a' + i, dump_dev);
-			continue;
+
+			switch (pm_i->bsdlabel[i].pi_fstype) {
+			case FS_UNUSED:
+				continue;
+			case FS_BSDLFS:
+				/* If there is no LFS, just comment it out. */
+				if (!check_lfs_progs())
+					s = "# ";
+				fstype = "lfs";
+				/* XXX fsck_lfs considered harmfull */
+				fsck_pass = 0;
+				dump_freq = 1;
+				break;
+			case FS_BSDFFS:
+				fsck_pass = (strcmp(mp, "/") == 0) ? 1 : 2;
+				dump_freq = 1;
+				break;
+			case FS_MSDOS:
+				fstype = "msdos";
+				break;
+			case FS_SWAP:
+				if (pm_i->isspecial)
+					continue;
+				if (swap_dev == -1) {
+					swap_dev = i;
+					dump_dev = ",dp";
+					pm_with_swap = pm_i;
+				} else {
+					dump_dev = "";
+				}
+				scripting_fprintf(f, "/dev/%s\t\tnone\tswap\tsw%s\t\t 0 0\n",
+					dev, dump_dev);
+				continue;
 #ifdef USE_SYSVBFS
-		case FS_SYSVBFS:
-			fstype = "sysvbfs";
-			make_target_dir("/stand");
-			break;
+			case FS_SYSVBFS:
+				fstype = "sysvbfs";
+				make_target_dir("/stand");
+				break;
 #endif
-		default:
-			fstype = "???";
-			s = "# ";
-			break;
+			default:
+				fstype = "???";
+				s = "# ";
+				break;
+			}
+			/* The code that remounts root rw doesn't check the partition */
+			if (strcmp(mp, "/") == 0 && !(pm_i->bsdlabel[i].pi_flags & PIF_MOUNT))
+				s = "# ";
+
+	 		scripting_fprintf(f,
+			  "%s/dev/%s\t\t%s\t%s\trw%s%s%s%s%s%s%s%s\t\t %d %d\n",
+			   s, dev, mp, fstype,
+			   pm_i->bsdlabel[i].pi_flags & PIF_LOG ? ",log" : "",
+			   pm_i->bsdlabel[i].pi_flags & PIF_MOUNT ? "" : ",noauto",
+			   pm_i->bsdlabel[i].pi_flags & PIF_ASYNC ? ",async" : "",
+			   pm_i->bsdlabel[i].pi_flags & PIF_NOATIME ? ",noatime" : "",
+			   pm_i->bsdlabel[i].pi_flags & PIF_NODEV ? ",nodev" : "",
+			   pm_i->bsdlabel[i].pi_flags & PIF_NODEVMTIME ? ",nodevmtime" : "",
+			   pm_i->bsdlabel[i].pi_flags & PIF_NOEXEC ? ",noexec" : "",
+			   pm_i->bsdlabel[i].pi_flags & PIF_NOSUID ? ",nosuid" : "",
+			   dump_freq, fsck_pass);
+	 		if (pm_i->isspecial)
+	 			/* Special device (such as dk*) have only one partition */
+	 			break;
 		}
-		/* The code that remounts root rw doesn't check the partition */
-		if (strcmp(mp, "/") == 0 && !(pm->bsdlabel[i].pi_flags & PIF_MOUNT))
-			s = "# ";
-
- 		scripting_fprintf(f,
-		  "%s/dev/%s%c\t\t%s\t%s\trw%s%s%s%s%s%s%s%s\t\t %d %d\n",
-		   s, pm->diskdev, 'a' + i, mp, fstype,
-		   pm->bsdlabel[i].pi_flags & PIF_LOG ? ",log" : "",
-		   pm->bsdlabel[i].pi_flags & PIF_MOUNT ? "" : ",noauto",
-		   pm->bsdlabel[i].pi_flags & PIF_ASYNC ? ",async" : "",
-		   pm->bsdlabel[i].pi_flags & PIF_NOATIME ? ",noatime" : "",
-		   pm->bsdlabel[i].pi_flags & PIF_NODEV ? ",nodev" : "",
-		   pm->bsdlabel[i].pi_flags & PIF_NODEVMTIME ? ",nodevmtime" : "",
-		   pm->bsdlabel[i].pi_flags & PIF_NOEXEC ? ",noexec" : "",
-		   pm->bsdlabel[i].pi_flags & PIF_NOSUID ? ",nosuid" : "",
-		   dump_freq, fsck_pass);
+		/* Simple install, only one disk */
+		if (!partman_go)
+			break;
 	}
-	if (!fstab_prepared) {
-		if (tmp_ramdisk_size != 0) {
+	if (tmp_ramdisk_size != 0) {
 #ifdef HAVE_TMPFS
-			scripting_fprintf(f, "tmpfs\t\t/tmp\ttmpfs\trw,-m=1777,-s=%"
-			    PRIi64 "\n",
-			    tmp_ramdisk_size * 512);
+		scripting_fprintf(f, "tmpfs\t\t/tmp\ttmpfs\trw,-m=1777,-s=%"
+		    PRIi64 "\n",
+		    tmp_ramdisk_size * 512);
 #else
-			if (swap_dev != -1)
-				scripting_fprintf(f, "/dev/%s%c\t\t/tmp\tmfs\trw,-s=%"
-				    PRIi64 "\n",
-				    pm->diskdev, 'a' + swap_dev, tmp_ramdisk_size);
-			else
-				scripting_fprintf(f, "swap\t\t/tmp\tmfs\trw,-s=%"
-				    PRIi64 "\n",
-				    tmp_ramdisk_size);
+		if (swap_dev != -1 && pm_with_swap != NULL)
+			scripting_fprintf(f, "/dev/%s%c\t\t/tmp\tmfs\trw,-s=%"
+			    PRIi64 "\n",
+			    pm_with_swap->diskdev, 'a' + swap_dev, tmp_ramdisk_size);
+		else
+			scripting_fprintf(f, "swap\t\t/tmp\tmfs\trw,-s=%"
+			    PRIi64 "\n",
+			    tmp_ramdisk_size);
 #endif
-		}
-
-		/* Add /kern, /proc and /dev/pts to fstab and make mountpoint. */
-		scripting_fprintf(f, "kernfs\t\t/kern\tkernfs\trw\n");
-		scripting_fprintf(f, "ptyfs\t\t/dev/pts\tptyfs\trw\n");
-		scripting_fprintf(f, "procfs\t\t/proc\tprocfs\trw\n");
-		scripting_fprintf(f, "/dev/" CD_NAME "\t\t/cdrom\tcd9660\tro,noauto\n");
-		make_target_dir("/kern");
-		make_target_dir("/proc");
-		make_target_dir("/dev/pts");
-		make_target_dir("/cdrom");
 	}
+
+	/* Add /kern, /proc and /dev/pts to fstab and make mountpoint. */
+	scripting_fprintf(f, "kernfs\t\t/kern\tkernfs\trw\n");
+	scripting_fprintf(f, "ptyfs\t\t/dev/pts\tptyfs\trw\n");
+	scripting_fprintf(f, "procfs\t\t/proc\tprocfs\trw\n");
+	scripting_fprintf(f, "/dev/" CD_NAME "\t\t/cdrom\tcd9660\tro,noauto\n");
+	make_target_dir("/kern");
+	make_target_dir("/proc");
+	make_target_dir("/dev/pts");
+	make_target_dir("/cdrom");
+
 	scripting_fprintf(NULL, "EOF\n");
 
-	fstab_prepared = 1;
+	if (dev != NULL)
+		free(dev);
 	fclose(f);
 	fflush(NULL);
 	return 0;
@@ -901,7 +959,7 @@ fsck_preen(const char *disk, int ptn, const char *fsname)
 	char *prog;
 	int error;
 
-	ptn += 'a';
+	ptn = (ptn < 0)? 0 : 'a' + ptn;
 	if (fsname == NULL)
 		return 0;
 	/* first, check if fsck program exists, if not, assume ok */
@@ -942,7 +1000,7 @@ fixsb(const char *prog, const char *disk, char ptn)
 	struct fs *fs = &sblk.fs;
 
 	snprintf(sblk.buf, sizeof(sblk.buf), "/dev/r%s%c",
-		disk, ptn == ' ' ? 0 : ptn);
+		disk, (ptn == ' ' || ptn < 0)? 0 : ptn);
 	fd = open(sblk.buf, O_RDONLY);
 	if (fd == -1)
 		return;
@@ -983,8 +1041,9 @@ static int
 mount_root(void)
 {
 	int	error;
+	int ptn = (pm->isspecial)? 0 - 'a' : pm->rootpart;
 
-	error = fsck_preen(pm->diskdev, pm->rootpart, "ffs");
+	error = fsck_preen(pm->diskdev, ptn, "ffs");
 	if (error != 0)
 		return error;
 
@@ -996,7 +1055,7 @@ mount_root(void)
 	 * XXX consider -o remount in case target root is
 	 * current root, still readonly from single-user?
 	 */
-	return target_mount("", pm->diskdev, pm->rootpart, "");
+	return target_mount("", pm->diskdev, ptn, "");
 }
 
 /* Get information on the file systems mounted from the root filesystem.
@@ -1028,7 +1087,7 @@ mount_disks(void)
 	else {
 		error = mount_root();
 		if (error != 0 && error != EBUSY)
-			return 0;
+			return error;
 	}
 
 	/* Check the target /etc/fstab exists before trying to parse it. */
@@ -1036,7 +1095,7 @@ mount_disks(void)
 	    target_file_exists_p("/etc/fstab") == 0) {
 		msg_display(MSG_noetcfstab, pm->diskdev);
 		process_menu(MENU_ok, NULL);
-		return 0;
+		return -1;
 	}
 
 
@@ -1046,7 +1105,7 @@ mount_disks(void)
 		/* error ! */
 		msg_display(MSG_badetcfstab, pm->diskdev);
 		process_menu(MENU_ok, NULL);
-		return 0;
+		return -2;
 	}
 	error = walk(fstab, (size_t)fstabsize, fstabbuf, numfstabbuf);
 	free(fstab);
@@ -1175,30 +1234,146 @@ bootxx_name(void)
 }
 #endif
 
+static int
+get_fsid_by_gptuuid(const char *str)
+{
+	int i;
+	uuid_t uuid;
+	uint32_t status;
+
+	uuid_from_string(str, &uuid, &status);
+	if (status == uuid_s_ok) {
+		for (i = 0; gpt_filesystems[i].id > 0; i++)
+			if (uuid_equal(&uuid, &(gpt_filesystems[i].uuid), NULL))
+				return gpt_filesystems[i].id;
+	}
+	return FS_OTHER;
+}
+
 const char *
-fstype_name(int fstype)
+get_gptfs_by_id(int filesystem)
 {
-	switch (fstype) {
-		case FS_BSDFFS:
-			return "FFS";
-		case FS_BSDLFS:
-			return "LFS";
-		case FS_SWAP:
-			return "SWAP";
-		case FS_EX2FS:
-			return "EXT2";
-		case FS_MSDOS:
-			return "FAT";
-		case FS_APPLEUFS:
-			return "APPLEUFS";
-		case FS_SYSVBFS:
-			return "SYSVB";
-		case FS_RAID:
-			return "RAID";
-		case FS_CGD:
-			return "CGD";
-		case FS_UNUSED:
-			return "none";
+	int i;
+	for (i = 0; gpt_filesystems[i].id > 0; i++)
+		if (filesystem == gpt_filesystems[i].id)
+			return gpt_filesystems[i].name;
+	return NULL;
+}
+
+/* from dkctl.c */
+static int
+get_dkwedges_sort(const void *a, const void *b)
+{
+	const struct dkwedge_info *dkwa = a, *dkwb = b;
+	const daddr_t oa = dkwa->dkw_offset, ob = dkwb->dkw_offset;
+	return (oa < ob) ? -1 : (oa > ob) ? 1 : 0;
+}
+
+int
+get_dkwedges(struct dkwedge_info **dkw, const char *diskdev)
+{
+	int fd;
+	char buf[STRSIZE];
+	size_t bufsize;
+	struct dkwedge_list dkwl;
+
+	*dkw = NULL;
+	dkwl.dkwl_buf = *dkw;
+	dkwl.dkwl_bufsize = 0;
+	fd = opendisk(diskdev, O_RDONLY, buf, STRSIZE, 0);
+	if (fd < 0)
+		return -1;
+
+	for (;;) {
+		if (ioctl(fd, DIOCLWEDGES, &dkwl) == -1)
+			return -2;
+		if (dkwl.dkwl_nwedges == dkwl.dkwl_ncopied)
+			break;
+		bufsize = dkwl.dkwl_nwedges * sizeof(**dkw);
+		if (dkwl.dkwl_bufsize < bufsize) {
+			*dkw = realloc(dkwl.dkwl_buf, bufsize);
+			if (*dkw == NULL)
+				return -3;
+			dkwl.dkwl_buf = *dkw;
+			dkwl.dkwl_bufsize = bufsize;
+		}
+	}
+
+	if (dkwl.dkwl_nwedges > 0)
+		qsort(*dkw, dkwl.dkwl_nwedges, sizeof(**dkw), get_dkwedges_sort);
+
+	close(fd);
+	return dkwl.dkwl_nwedges;
+}
+
+/* XXX: rewrite */
+static int
+incoregpt(pm_devs_t *pm_cur, partinfo *lp)
+{
+	int i, num;
+	uint32_t p_start, p_size, p_num;
+	char *textbuf, *t, *tt, p_type[STRSIZE];
+	struct dkwedge_info *dkw;
+
+	num = get_dkwedges(&dkw, pm_cur->diskdev);
+	if (dkw != NULL) {
+		for (i = 0; i < num && i < MAX_WEDGES; i++)
+			run_program(RUN_SILENT, "dkctl %s delwedge %s",
+				pm_cur->diskdev, dkw[i].dkw_devname);
+		free (dkw);
 	}
-	return "???";
-}
\ No newline at end of file
+
+	if (collect(T_OUTPUT, &textbuf, "gpt show -u %s 2>/dev/null", pm_cur->diskdev) < 1)
+		return -1;
+
+	(void)strtok(textbuf, "\n"); /* ignore first line */
+	while ((t = strtok(NULL, "\n")) != NULL) {
+		i = 0; p_start = -1; p_size = -1; p_num = -1; strcpy(p_type, ""); /* init */
+		while ((tt = strsep(&t, " \t")) != NULL) {
+			if (strlen(tt) < 1)
+				continue;
+			if (i == 0)
+				p_start = atoi(tt);
+			if (i == 1)
+				p_size = atoi(tt);
+			if (i == 2)
+				p_num = atoi(tt);
+			if (i > 2 || (i == 2 && p_num == 0))
+				if (
+					strcmp(tt, "GPT") &&
+					strcmp(tt, "part") &&
+					strcmp(tt, "-")
+					)
+						strncat(p_type, tt, STRSIZE);
+			i++;
+		}
+		if (p_start < 1 || p_size < 1)
+			continue;
+		else if (! strcmp(p_type, "Pritable"))
+			pm_cur->ptstart = p_start + p_size;
+		else if (! strcmp(p_type, "Sectable"))
+			pm_cur->ptsize = p_start - pm_cur->ptstart - 1;
+		else if (p_num < 1 && strlen(p_type) > 0)
+			/* Utilitary entry (PMBR, etc) */
+			continue;
+		else if (p_num < 1) {
+			/* Free space */
+			continue;
+		} else {
+			/* Usual partition */
+			lp[p_num].pi_size = p_size;
+			lp[p_num].pi_offset = p_start;
+			lp[p_num].pi_fstype = get_fsid_by_gptuuid(p_type);
+		}
+	}
+	free(textbuf);
+
+	return 0;
+}
+
+static int
+is_gpt(const char *dev)
+{
+	return ! run_program(RUN_SILENT | RUN_ERROR_OK,
+		"sh -c 'gpt show %s |grep -e Pri\\ GPT\\ table'", dev);
+}
diff --git a/distrib/utils/sysinst/install.c b/distrib/utils/sysinst/install.c
index 10935e3..7e6a440 100644
--- a/distrib/utils/sysinst/install.c
+++ b/distrib/utils/sysinst/install.c
@@ -47,8 +47,7 @@ do_install(void)
 {
 	int find_disks_ret;
 	int retcode = 0;
-	partman_go = 0;
-	fstab_prepared = 0;
+	partman_go = -1;
 
 #ifndef DEBUG
 	msg_display(MSG_installusure);
@@ -66,11 +65,12 @@ do_install(void)
 			msg_display(MSG_abort);
 			process_menu(MENU_ok, NULL);
 			return;
-		}		
+		}
 	} else if (find_disks_ret < 0)
 		return;
 	else {
 	/* Classical partitioning wizard */
+		partman_go = 0;
 		clear();
 		refresh();
 
@@ -99,9 +99,12 @@ do_install(void)
 		if (!yesno)
 			return;
 
-		if (md_pre_disklabel() != 0 || write_disklabel() != 0 ||
-			md_post_disklabel() != 0 ||make_filesystems() ||
-			make_fstab() != 0 || md_post_newfs() != 0)
+		if (md_pre_disklabel() != 0 ||
+			write_disklabel() != 0 ||
+			md_post_disklabel() != 0 ||
+			make_filesystems() ||
+			make_fstab() != 0 ||
+			md_post_newfs() != 0)
 			return;
 	}
 
diff --git a/distrib/utils/sysinst/label.c b/distrib/utils/sysinst/label.c
index a91e866..f7f7506 100644
--- a/distrib/utils/sysinst/label.c
+++ b/distrib/utils/sysinst/label.c
@@ -141,6 +141,17 @@ checklabel(partinfo *lp, int nparts, int rawpart, int bsdpart,
 	return (0);
 }
 
+int
+checkoverlap(partinfo *lp, int nparts, int rawpart, int bsdpart)
+{
+	int i, j;
+	if (checklabel(lp, nparts, rawpart, bsdpart, &i, &j)) {
+		msg_display(MSG_partitions_overlap,'a'+i,'a'+j);
+		return 1;
+	}
+	return 0;
+}
+
 static int
 check_one_root(partinfo *lp, int nparts)
 {
@@ -343,7 +354,7 @@ static void set_ptn_header(menudesc *m, void *arg);
 static void set_ptn_label(menudesc *m, int opt, void *arg);
 int all_fstype_menu = -1;
 
-static int
+int
 edit_ptn(menudesc *menu, void *arg)
 {
 	static menu_ent fs_fields[] = {
@@ -632,8 +643,6 @@ edit_and_check_label(partinfo *lp, int nparts, int rawpart, int bsdpart)
 	pm->current_cylsize = pm->dlcylsize;
 
 	for (;;) {
-		int i, j;
-
 		/* first give the user the option to edit the label... */
 		process_menu(menu_no, &pi);
 
@@ -643,10 +652,7 @@ edit_and_check_label(partinfo *lp, int nparts, int rawpart, int bsdpart)
 			msg_display(MSG_must_be_one_root);
 		else 
 			/* Check for overlaps */
-			if (checklabel(lp, nparts, rawpart, bsdpart, &i, &j))
-				/* partitions overlap */
-				msg_display(MSG_partitions_overlap,'a'+i,'a'+j);
-			else
+			if (checkoverlap(lp, nparts, rawpart, bsdpart) == 0)
 				return 1;
 
 		/*XXX ???*/
diff --git a/distrib/utils/sysinst/main.c b/distrib/utils/sysinst/main.c
index c7592a6..d808a86 100644
--- a/distrib/utils/sysinst/main.c
+++ b/distrib/utils/sysinst/main.c
@@ -130,20 +130,21 @@ init(void)
 	const struct f_arg *arg;
 	
 	sizemult = 1;
+	multname = msg_string(MSG_secname);
 	tmp_ramdisk_size = 0;
 	clean_xfer_dir = 0;
 	mnt2_mounted = 0;
 	fd_type = "msdos";
 	layoutkind = LY_SETNEW;
 
-	pm_head = malloc (sizeof (pm_devs_t));
-	memset(pm_head, 0, sizeof *pm_head);
-	pm_found = malloc (sizeof (pm_devs_t));
-	memset(pm_found, 0, sizeof *pm_found);
+	pm_head = (struct pm_head_t) SLIST_HEAD_INITIALIZER(pm_head);
+	SLIST_INIT(&pm_head);
+	pm_new = malloc (sizeof (pm_devs_t));
+	memset(pm_new, 0, sizeof *pm_new);
 
 	for (arg = fflagopts; arg->name != NULL; arg++)
 		strlcpy(arg->var, arg->dflt, arg->size);
-	strlcpy(pm_found->bsddiskname, bsddiskname, sizeof pm_found->bsddiskname);
+	strlcpy(pm_new->bsddiskname, bsddiskname, sizeof pm_new->bsddiskname);
 	pkg.xfer_type = pkgsrc.xfer_type = "http";
 	
 	clr_arg.bg=COLOR_BLUE;
@@ -216,7 +217,7 @@ main(int argc, char **argv)
 	}
 	if (has_colors()) {
 		start_color();
-		do_coloring (clr_arg.fg,clr_arg.bg);
+		do_coloring(clr_arg.fg,clr_arg.bg);
 	}
 	msg_window(mainwin);
 
@@ -498,7 +499,7 @@ process_f_flag(char *f_name)
 			break;
 		}
 	}
-	strlcpy(pm_found->bsddiskname, bsddiskname, sizeof pm_found->bsddiskname);
+	strlcpy(pm_new->bsddiskname, bsddiskname, sizeof pm_new->bsddiskname);
 
 	fclose(fp);
 }
diff --git a/distrib/utils/sysinst/mbr.h b/distrib/utils/sysinst/mbr.h
index 8d1ccf87..e5fe2b9 100644
--- a/distrib/utils/sysinst/mbr.h
+++ b/distrib/utils/sysinst/mbr.h
@@ -76,7 +76,7 @@ struct mbr_info_t {
 /* incore fdisk (mbr, bios) geometry */
 int bcyl, bhead, bsec;
 
-mbr_info_t mbr; // TODO: xxx
+mbr_info_t mbr;
 
 #ifdef BOOTSEL
 struct mbr_bootsel *mbs;
diff --git a/distrib/utils/sysinst/menus.mi b/distrib/utils/sysinst/menus.mi
index 6fd5a1e..d939153 100644
--- a/distrib/utils/sysinst/menus.mi
+++ b/distrib/utils/sysinst/menus.mi
@@ -506,51 +506,116 @@ menu pkgsrc, y=-4, x=0, w=70, no box, no clear,
 		};
 	option MSG_quit_install, exit, action { yesno = SET_SKIP; };
 
-menu pmentry, x=50, y=5, exit, default exit; /* TODO: localize */
-	option "Prepare MBR",		exit, action { pm->changed = 1; md_get_info(); };
-	option "Prepare GPT [WIP]",	exit, action { pm->changed = 1; };
-	option "Edit BSD partitions", exit, action { *(int *)arg = 1; pm->changed = 1;
-								layoutkind = LY_SETNEW;
-								md_make_bsd_partitions();
-								if (pm->bsdlabel[pm->rootpart].pi_flags & PIF_MOUNT)
-									pm->bootable = 1;
-								else
-									pm->bootable = 0; };
-	option "Set disk name",		exit, action { msg_prompt_win(MSG_packname, -1,
-								18,	0, 0, pm->bsddiskname, pm->bsddiskname,
-								sizeof pm->bsddiskname); };
-	option "RAID there",		exit, action { *(int *)arg = 1; pm->changed = 1;
-												layoutkind = LY_NEWRAID;
-												md_make_bsd_partitions(); };
-	option "Encrypt",			exit, action { *(int *)arg = 1; pm->changed = 1;
-												layoutkind = LY_NEWCGD;
-												md_make_bsd_partitions();
-												partman_cgd_edit_adddisk(0, pm); };
-	option "Bootable flag",		exit, action { pm->changed = 1;
+
+menu pmdiskentry, x=50, y=5, exit, default exit;
+	option MSG_editbsdpart, exit, action { pm_make_bsd_partitions(pm); };
+	option MSG_editmbr,		exit, action { md_get_info();
+											md_pre_disklabel();
+											memset(&pm->bsdlabel, 0, sizeof pm->bsdlabel);};
+	option MSG_switchgpt,	exit, action { if (pm_gpt_convert(pm) == 0)
+												pm_partusage(pm, -1, 1); };
+	option MSG_renamedisk,	exit, action { pm->unsaved = 1; pm_rename(pm); };
+	option MSG_fmtasraid,	exit, action { pm->unsaved = 1;
+											pm_partusage(pm, -1, 1);
+											layoutkind = LY_NEWRAID;
+											md_make_bsd_partitions();};
+	option MSG_fmtaslvm,	exit, action { pm->unsaved = 1;
+											pm_partusage(pm, -1, 1);
+											layoutkind = LY_NEWLVM;
+											md_make_bsd_partitions(); };
+	option MSG_encrypt,		exit, action { pm->unsaved = 1;
+											pm_partusage(pm, -1, 1);
+											layoutkind = LY_NEWCGD;
+											md_make_bsd_partitions();
+											pm_cgd_edit(0, &(part_entry_t)
+												{.dev_ptr = pm, .dev_num = PART_E}
+											); };
+	option MSG_setbootable,	exit, action { pm->unsaved = 1;
+											pm->bootable = !pm->bootable; };
+	option MSG_erase,		next menu shred_modes;
+	option MSG_undo,		exit, action { label_read(); pm->unsaved = 0;
+											pm_partusage(pm, -1, 1); };
+	option MSG_unconfig,	exit, action { if (pm_unconfigure(pm) == 0)
+												pm_partusage(pm, -1, 1); };
+
+menu pmpartentry, x=50, y=5, exit, default exit;
+	option MSG_edit,		exit, action { 
+									pm->unsaved = 1;
+									int tpfs = pm->bsdlabel[*(int*)arg].pi_fstype;
+									int tplvm = pm->bsdlabel[*(int*)arg].lvmpv;
+									pm_editpart(*(int*)arg);
+									if (tpfs != pm->bsdlabel[*(int*)arg].pi_fstype ||
+										tplvm != pm->bsdlabel[*(int*)arg].lvmpv)
+										/* Oops, partition type changed */
+										pm_partusage(pm, *(int*)arg, 1);
+								};
+	option MSG_fmtasraid,	exit, action {
+									if (pm->gpt || pm->isspecial) {
+										process_menu(MENU_ok, deconst(MSG_notsupported));
+										return -1;
+									}
+									pm->unsaved = 1;
+									pm_partusage(pm, *(int*)arg, 1);
+									pm_setfstype(pm, *(int*)arg, FS_RAID);
+								};
+	option MSG_fmtaslvm,	exit, action {
+									if (pm->gpt || pm->isspecial) {
+										process_menu(MENU_ok, deconst(MSG_notsupported));
+										return -1;
+									}
+									pm->unsaved = 1;
+									pm_partusage(pm, *(int*)arg, 1);
+									pm_setfstype(pm, *(int*)arg, FS_BSDFFS);
+								    pm->bsdlabel[*(int*)arg].lvmpv = 1;
+								};
+	option MSG_encrypt,		exit, action {
+									if (pm->gpt || pm->isspecial) {
+										process_menu(MENU_ok, deconst(MSG_notsupported));
+										return -1;
+									}
+									pm->unsaved = 1;
+									pm_partusage(pm, *(int*)arg, 1);
+									pm_setfstype(pm, *(int*)arg, FS_CGD);
+									pm_cgd_edit(0,
+										&(part_entry_t){.dev_ptr = pm,
+														.dev_num = *(int*)arg});
+								};
+	option MSG_erase,		next menu shred_modes;
+	option MSG_doumount,	exit, action { pm_umount(pm, *(int*)arg); };
+	option MSG_Delete_partition,	exit, action {
+									pm->unsaved = 1;
+									pm_partusage(pm, *(int*)arg, 1);
+									if (pm->isspecial)
+										pm_unconfigure(pm);
+									else
+										pm->bsdlabel[*(int*)arg].pi_fstype = FS_UNUSED;
+									};
+
+menu pmgptentry, x=50, y=8, exit, default exit;
+	option MSG_editbsdpart, exit, action { pm_make_bsd_partitions(pm); };
+	option MSG_switchmbr,	exit, action { if (pm_gpt_convert(pm) == 0)
+												pm_partusage(pm, -1, 1); };
+	option MSG_setbootable,	exit, action { pm->unsaved = 1;
 												pm->bootable = !pm->bootable; };
-	option "Safe erase",		next menu shred_modes;
-	option "Undo changes",		exit, action { label_read(); pm->changed = 0; };
-	option "Mount...",			exit, action { partman_mountmenu(); };
-	option "Umount/Unconfigure", exit, action { *(int *)arg = 1;
-												partman_unconfigure(); };
+	option MSG_erase,		next menu shred_modes;
+	option MSG_undo,		exit, action { label_read(); pm->unsaved = 0;
+											pm_partusage(pm, -1, 1); };
+	option MSG_unconfig,	exit, action { if (pm_unconfigure(pm) == 0)
+												pm_partusage(pm, -1, 1); };
 
 menu shred_modes, x=50, y=5, exit, default exit;
-	option "Fill by zeros",			exit, action { partman_shred(pm->diskdev,
-													SHRED_ZEROS); };
-	option "Fill by random data",	exit, action { partman_shred(pm->diskdev,
-													SHRED_RANDOM); };
-	option "Fill by crypto data",	exit, action { partman_shred(pm->diskdev,
-													SHRED_CRYPTO); };
+	option MSG_fillzeros,	exit,
+							action { pm_shred(pm, *(int*)arg, SHRED_ZEROS); };
+	option MSG_fillrandom,	exit,
+							action { pm_shred(pm, *(int*)arg, SHRED_RANDOM); };
+	option MSG_fillcrypto,	exit,
+							action { pm_shred(pm, *(int*)arg, SHRED_CRYPTO); };
 
 menu raidlevel;
-	option "0 - No parity, only simple striping.", exit,
-		action { *(int *)arg = 0; };
-	option "1 - Mirroring.  The parity is the mirror.", exit,
-		action { *(int *)arg = 1; };
-	option "4 - Striping with parity stored on the last component.", exit,
-		action { *(int *)arg = 4; };
-	option "5 - Striping with parity at the all components.", exit,
-		action { *(int *)arg = 5; };
+	option MSG_raid0, exit, action { *(int *)arg = 0; };
+	option MSG_raid1, exit, action { *(int *)arg = 1; };
+	option MSG_raid4, exit, action { *(int *)arg = 4; };
+	option MSG_raid5, exit, action { *(int *)arg = 5; };
 
 menu cgd_enctype;
 	option "aes-cbc",			exit, action { *(const char**)arg = "aes-cbc"; };
@@ -574,4 +639,3 @@ menu cgd_verifytype;
 	option "disklabel",			exit, action { *(const char**)arg = "disklabel"; };
 	option "ffs",				exit, action { *(const char**)arg = "ffs"; };
 	option "re-enter",			exit, action { *(const char**)arg = "re-enter"; };
-
diff --git a/distrib/utils/sysinst/msg.mi.de b/distrib/utils/sysinst/msg.mi.de
index cd0c6b4..603e40c 100644
--- a/distrib/utils/sysinst/msg.mi.de
+++ b/distrib/utils/sysinst/msg.mi.de
@@ -1066,6 +1066,10 @@ message enable_sshd {sshd aktivieren}
 message enable_ntpd {ntpd aktivieren}
 message run_ntpdate {ntpdate beim Starten ausführen}
 message enable_mdnsd {mdnsd aktivieren}
+message enable_xdm {xdm aktivieren}
+message enable_cgd {cgd aktivieren}
+message enable_lvm {lvm aktivieren}
+message enable_raid {raidframe aktivieren}
 message configmenu {Zusätzliche Einstellungen konfigurieren.}
 message doneconfig {Konfiguration abgeschlossen.}
 message Install_pkgin {pkgin installieren und Datenbank initialisieren}
@@ -1093,3 +1097,148 @@ message pkgin_failed
 {Die Installation von pkgin ist fehlgeschlagen, evtl. weil keine Binärpakete 
 vorhanden sind. Bitte den Pfad der Pakete überprüfen und noch einmal versuchen.}
 message failed {Fehlgeschlagen}
+
+
+message notsupported {Operation wird nicht unterstützt!}
+message askfsmountadv {Mountpoint oder 'raid' oder 'cgd' oder 'lvm'?}
+message partman {Erweiterte Partitionierung}
+message editbsdpart {Bearbeiten BSD-Partitionen}
+message editmbr {Bearbeiten und speichern MBR}
+message switchgpt {Wechseln Sie zu GPT}
+message switchmbr {Wechseln Sie zu MBR}
+message renamedisk {Stellen Sie Festplatten-Namen}
+message fmtasraid {Format als RAID}
+message fmtaslvm {Format als LVM-PV}
+message encrypt {Verschlüsseln}
+message setbootable {Boot-Flag}
+message erase {Safe Erase}
+message undo {Rückgängigmachen von Änderungen}
+message unconfig {Dekonfigurieren}
+message edit {Bearbeiten}
+message doumount {Force-umount}
+message fillzeros {Füllen von Nullen}
+message fillrandom {Füllen von zufälligen Daten}
+message fillcrypto {Füllen von Crypto-Daten}
+message raid0 {0 - Keine Parität, nur einfache Striping.}
+message raid1 {1 - Mirroring. Die Parität ist der Spiegel.}
+message raid4 {4 - Striping mit Parität auf die letzte Komponente gespeichert.}
+message raid5 {5 - Striping mit Parität an den alle Komponenten.}
+
+message fremove {ENTFERNEN}
+message remove {Entfernen}
+message add {Hinzufügen}
+message auto {auto}
+
+message removepartswarn {Diese entfernen Sie alle Partitionen auf der Festplatte. Wollen Sie fortsetzen?}
+message saveprompt {Speichern Sie die Änderungen vor dem Abschluss?}
+message cantsave {Änderungen können nicht gespeichert werden.}
+message noroot {Kein Root-Partition definiert ist, kann nicht fortgesetzt werden \n}
+message wannaunblock {Das Gerät ist blockiert. Wollen Sie zwingen sie zu entsperren und weiter?}
+message wannatry {Wollen Sie probieren?}
+message create_cgd {Erstellen kryptographische Volumen (CGD)}
+message create_cnd {Erstellen Sie virtuelle Disk-Image (VND)}
+message create_vg {Erstellen Volume-Gruppe (LVM VG)}
+message create_lv {      Erstellen logischer Volumen}
+message create_raid {Erstellen Software-RAID}
+message updpmlist {Aktualisieren Sie Geräte-Liste}
+message savepm {Speichern Sie die Änderungen}
+message pmblocked {GESPERRT}
+message pmunchanged {NICHTS}
+message pmsetboot {BOOTEN}
+message pmused {BENUTZT}
+message pmmounted {(montiert)}
+message pmunused {(unbenutzt)}
+message pmgptdisk {Festplatte mit GPT}
+
+message finishpm {Partitionierung beenden}
+message limitcount {Grenze für die Anzahl der Geräte erreicht wurde!}
+message invaliddev {Ungültige Gerät!}
+message avdisks {Verfügbare Festplatten:}
+message nofreedev {Kann nicht zugewiesen werden Geräteknoten!}
+message partman_header
+{Partition Manager. Alle Festplatten, Partitionen usw. und dort angezeigt.
+Auf den ersten MBR-Partitionen machen, dann machen BSD-Label.
+Wenn Sie RAID verwenden, LVM oder CGD, gehen Sie folgendermaßen vor:
+1) Erstellen BSD-Partitionen mit Typ benötigt; 2) Erstellen Sie RAID /
+LVM VG / CGD mit diesen Partitionen; 3) Speichern Sie es;
+4) Erstellen Sie Partitionen für RAID / CGD oder Logical Volumes für LVM.}
+
+message raid_menufmt {   raid%d (ebene %1d) on %-34s %11uM}
+message raid_err_menufmt {   LEER RAID!}
+message raid_disks_fmt {Festplatten: %27s}
+message raid_spares_fmt {Ersatzbedarf: %26s}
+message raid_level_fmt {RAID ebene:       %22d}
+message raid_numrow_fmt {numRow:           %22d}
+message raid_numcol_fmt {numCol:           %22d}
+message raid_numspare_fmt {numSpare:         %22d}
+message raid_sectpersu_fmt {sectPerSU:        %22d}
+message raid_superpar_fmt {SUsPerParityUnit: %22d}
+message raid_superrec_fmt {SUsPerReconUnit:  %22d}
+message raid_nomultidim {Mehrdimensionale Arrays werden nicht unterstützt!}
+message raid_numrow_ask {numRow?}
+message raid_numcol_ask {numCol?}
+message raid_numspare_ask {numSpare?}
+message raid_sectpersu_ask {sectPerSU?}
+message raid_superpar_ask {SUsPerParityUnit?}
+message raid_superrec_ask {SUsPerReconUnit?}
+message raid_disks {Festplatten im RAID:}
+message vnd_err_menufmt {   PATH nicht definiert!}
+message vnd_assgn_menufmt {   vnd%1d auf %-50s ASSIGN}
+message vnd_menufmt {   vnd%1d auf %-44s %11uM}
+message vnd_path_fmt {Dateipfad: %29s}
+message vnd_assgn_fmt {Weisen Sie existieren Bild: %12s}
+message vnd_size_fmt {Größe:           %22sM}
+message vnd_ro_fmt {Nur lesen:        %22s}
+message vnd_geom_fmt {Stellen Sie Geometrie von Hand: %8s}
+message vnd_bps_fmt {Byte pro Sektor:      %18s}
+message vnd_spt_fmt {Sektoren pro Spur:    %18s}
+message vnd_tpc_fmt {Spuren pro Zylinder:  %18s}
+message vnd_cyl_fmt {Zylinder:         %22s}
+message vnd_path_ask {Dateipfad?}
+message vnd_size_ask {Größe (MB)?}
+message vnd_bps_ask {Byte pro Sektor?}
+message vnd_spt_ask {Sektoren pro Spur?}
+message vnd_tpc_ask {Spuren pro Zylinder?}
+message vnd_cyl_ask {Zylinder?}
+message cgd_err_menufmt {   DISK NICHT DEFINIERT!}
+message cgd_menufmt {   cgd%1d %-48s %11uM}
+message cgd_dev_fmt {Grundgerät:     %24s}
+message cgd_enc_fmt {Mausklick und:  %24s}
+message cgd_key_fmt {Schlüsselgröße: %24d}
+message cgd_iv_fmt {IV-Algorithmus: %24s}
+message cgd_keygen_fmt {Schlüsselgenerierung: %18s}
+message cgd_verif_fmt {Verification Methode: %18s}
+message lvm_disks {Festplatten im VG:}
+message lvm_menufmt {   %-44s %20sM}
+message lvm_err_menufmt {   VG LEER!}
+message lvm_disks_fmt {PV's: %34s}
+message lvm_name_fmt {Name: %34s}
+message lvm_maxlv_fmt {MaxLogicalVolumes:  %20s}
+message lvm_maxpv_fmt {MaxPhysicalVolumes: %20s}
+message lvm_extsiz_fmt {PhysicalExtentSize: %20s}
+message lvm_name_ask {Name?}
+message lvm_maxlv_ask {MaxLogicalVolumes?}
+message lvm_maxpv_ask {MaxPhysicalVolumes?}
+message lvm_extsiz_ask {PhysicalExtentSize (MB)?}
+message lvmlv_menufmt {      Logische Volumen%-35s% 11uM}
+message lvmlv_name_fmt {Name: %34s}
+message lvmlv_size_fmt {Größe: %32dM}
+message lvmlv_ro_fmt {Nur lesen:  %27s}
+message lvmlv_cont_fmt {Zusammenhängend: %23s}
+message lvmlv_extnum_fmt {LogicalExtentsNumber: %18s}
+message lvmlv_minor_fmt {Minor-Nummer: %26s}
+message lvmlv_mirrors_fmt {Mirrors: %27d}
+message lvmlv_regsiz_fmt {MirrorLogRegionSize: %18s}
+message lvmlv_pers_fmt {Persistent Minor-Nummer: %14s}
+message lvmlv_readahsect_fmt {ReadAheadSectors: %18s}
+message lvmlv_stripes_fmt {Stripes: %27s}
+message lvmlv_stripesiz_fmt {StripeSize: %27s}
+message lvmlv_zero_fmt {Nullsetzen der ersten KB:% 13s}
+message lvmlv_name_ask {Name?}
+message lvmlv_size_ask {Größe (MB)?}
+message lvmlv_extnum_ask {LogicalExtentsNumber?}
+message lvmlv_minor_ask {Minor-Nummer?}
+message lvmlv_mirrors_ask {Spiegel?}
+message lvmlv_regsiz_ask {MirrorLogRegionSize?}
+message lvmlv_readahsect_ask {ReadAheadSectors?}
+message lvmlv_stripes_ask {Stripes?}
diff --git a/distrib/utils/sysinst/msg.mi.en b/distrib/utils/sysinst/msg.mi.en
index abbd3ae..8c6c623 100644
--- a/distrib/utils/sysinst/msg.mi.en
+++ b/distrib/utils/sysinst/msg.mi.en
@@ -998,6 +998,10 @@ message enable_sshd {Enable sshd}
 message enable_ntpd {Enable ntpd}
 message run_ntpdate {Run ntpdate at boot}
 message enable_mdnsd {Enable mdnsd}
+message enable_xdm {Enable xdm}
+message enable_cgd {Enable cgd}
+message enable_lvm {Enable lvm}
+message enable_raid {Enable raidframe}
 message configmenu {Configure the additional items as needed.}
 message doneconfig {Finished configuring}
 message Install_pkgin {Install pkgin and update package summary}
@@ -1023,3 +1027,149 @@ message pkgin_failed
 {Installation of pkgin failed, possibly because no binary packages
 exist.  Please check the package path and try again.}
 message failed {Failed}
+
+
+message notsupported {Operation not supported!}
+message askfsmountadv {Mountpoint or 'raid' or 'cgd' or 'lvm'?}
+message partman {Extended partitioning}
+message editbsdpart {Edit BSD partitions}
+message editmbr {Edit and save MBR}
+message switchgpt {Switch to GPT}
+message switchmbr {Switch to MBR}
+message renamedisk {Set disk name}
+message fmtasraid {Format as RAID}
+message fmtaslvm {Format as LVM PV}
+message encrypt {Encrypt}
+message setbootable {Bootable flag}
+message erase {Safe erase}
+message undo {Undo changes}
+message unconfig {Unconfigure}
+message edit {Edit}
+message doumount {Force umount}
+message fillzeros {Fill by zeros}
+message fillrandom {Fill by random data}
+message fillcrypto {Fill by crypto data}
+message raid0 {0 - No parity, only simple striping.}
+message raid1 {1 - Mirroring.  The parity is the mirror.}
+message raid4 {4 - Striping with parity stored on the last component.}
+message raid5 {5 - Striping with parity at the all components.}
+
+message fremove {REMOVE}
+message remove {Remove}
+message add {Add}
+message auto {auto}
+
+message removepartswarn {This remove all partitions on disk. Do you want to continue?}
+message saveprompt {Save changes before finishing?}
+message cantsave {Changes cannot be saved.}
+message noroot {No root partition defined, cannot continue\n}
+message wannaunblock {
+Device is blocked. It's editing may cause problems.
+Do you want to force unblock it and continue?}
+message wannatry {Do you want to try?}
+message create_cgd {Create cryptographic volume (CGD)}
+message create_cnd {Create virtual disk image (VND)}
+message create_vg {Create volume group (LVM VG)}
+message create_lv {      Create logical volume}
+message create_raid {Create software RAID}
+message updpmlist {Update devices list}
+message savepm {Save changes}
+message pmblocked {BLOCKED}
+message pmunchanged {UNCHANGED}
+message pmsetboot {BOOT}
+message pmused {USED}
+message pmmounted {(mounted)}
+message pmunused {(unused)}
+message pmgptdisk {GPT-labeled disk}
+
+message finishpm {Finish partitioning}
+message limitcount {Limit for the devices count was reached!}
+message invaliddev {Invalid device!}
+message avdisks {Available disks:}
+message nofreedev {Cannot allocate device node!}
+message partman_header
+{Partition manager. All disks, partitions and etc. displayed there.
+At first make MBR partitions, then make BSD label. If you want to use RAID,
+LVM or CGD, follow these steps: 1) Create BSD partitions with needed type;
+2) Create RAID/LVM VG/CGD using these partitions; 3) Save it;
+4) Create partitions for RAID/CGD or Logical Volumes for LVM.}
+
+message raid_menufmt {   raid%d (level %1d) on %-34s %11uM}
+message raid_err_menufmt {   EMPTY RAID!}
+message raid_disks_fmt {Disks: %33s}
+message raid_spares_fmt {Spares: %32s}
+message raid_level_fmt {RAID level:       %22d}
+message raid_numrow_fmt {numRow:           %22d}
+message raid_numcol_fmt {numCol:           %22d}
+message raid_numspare_fmt {numSpare:         %22d}
+message raid_sectpersu_fmt {sectPerSU:        %22d}
+message raid_superpar_fmt {SUsPerParityUnit: %22d}
+message raid_superrec_fmt {SUsPerReconUnit:  %22d}
+message raid_nomultidim {Multi-dimensional arrays are NOT supported!}
+message raid_numrow_ask {numRow?}
+message raid_numcol_ask {numCol?}
+message raid_numspare_ask {numSpare?}
+message raid_sectpersu_ask {sectPerSU?}
+message raid_superpar_ask {SUsPerParityUnit?}
+message raid_superrec_ask {SUsPerReconUnit?}
+message raid_disks {Disks in RAID:}
+message vnd_err_menufmt {   PATH NOT DEFINED!}
+message vnd_assgn_menufmt {   vnd%1d on %-51s ASSIGN}
+message vnd_menufmt {   vnd%1d on %-45s %11uM}
+message vnd_path_fmt {File path: %29s}
+message vnd_assgn_fmt {Assign exist image: %20s}
+message vnd_size_fmt {Size:            %22sM}
+message vnd_ro_fmt {Read-only:        %22s}
+message vnd_geom_fmt {Set geometry by hand: %18s}
+message vnd_bps_fmt {Bytes per Sector:     %18s}
+message vnd_spt_fmt {Sectors per Track:    %18s}
+message vnd_tpc_fmt {Tracks per Cylinder:  %18s}
+message vnd_cyl_fmt {Cylinders:        %22s}
+message vnd_path_ask {File path?}
+message vnd_size_ask {Size (MB)?}
+message vnd_bps_ask {Bytes per Sector?}
+message vnd_spt_ask {Sectors per Track?}
+message vnd_tpc_ask {Tracks per Cylinder?}
+message vnd_cyl_ask {Cylinders?}
+message cgd_err_menufmt {   DISK NOT DEFINED!}
+message cgd_menufmt {   cgd%1d %-48s %11uM}
+message cgd_dev_fmt {Base device:    %24s}
+message cgd_enc_fmt {Encyption:      %24s}
+message cgd_key_fmt {Key size:       %24d}
+message cgd_iv_fmt {IV algorithm:   %24s}
+message cgd_keygen_fmt {Key generation: %24s}
+message cgd_verif_fmt {Verification method:   %17s}
+message lvm_disks {Disks in VG:}
+message lvm_menufmt {   %-44s %20sM}
+message lvm_err_menufmt {   EMPTY VG!}
+message lvm_disks_fmt {PV's: %34s}
+message lvm_name_fmt {Name: %34s}
+message lvm_maxlv_fmt {MaxLogicalVolumes:  %20s}
+message lvm_maxpv_fmt {MaxPhysicalVolumes: %20s}
+message lvm_extsiz_fmt {PhysicalExtentSize: %20s}
+message lvm_name_ask {Name?}
+message lvm_maxlv_ask {MaxLogicalVolumes?}
+message lvm_maxpv_ask {MaxPhysicalVolumes?}
+message lvm_extsiz_ask {PhysicalExtentSize (MB)?}
+message lvmlv_menufmt {      Logical volume %-35s %11uM}
+message lvmlv_name_fmt {Name: %34s}
+message lvmlv_size_fmt {Size: %33dM}
+message lvmlv_ro_fmt {Read-only:   %27s}
+message lvmlv_cont_fmt {Contiguous:  %27s}
+message lvmlv_extnum_fmt {LogicalExtentsNumber: %18s}
+message lvmlv_minor_fmt {Minor number: %26s}
+message lvmlv_mirrors_fmt {Mirrors:     %27d}
+message lvmlv_regsiz_fmt {MirrorLogRegionSize:  %18s}
+message lvmlv_pers_fmt {Persistent minor number:  %14s}
+message lvmlv_readahsect_fmt {ReadAheadSectors:     %18s}
+message lvmlv_stripes_fmt {Stripes:     %27s}
+message lvmlv_stripesiz_fmt {StripeSize:  %27s}
+message lvmlv_zero_fmt {Zeroing of the first KB:   %13s}
+message lvmlv_name_ask {Name?}
+message lvmlv_size_ask {Size (MB)?}
+message lvmlv_extnum_ask {LogicalExtentsNumber?}
+message lvmlv_minor_ask {Minor number?}
+message lvmlv_mirrors_ask {Mirrors?}
+message lvmlv_regsiz_ask {MirrorLogRegionSize?}
+message lvmlv_readahsect_ask {ReadAheadSectors?}
+message lvmlv_stripes_ask {Stripes?}
diff --git a/distrib/utils/sysinst/msg.mi.es b/distrib/utils/sysinst/msg.mi.es
index 147a461..339e385 100644
--- a/distrib/utils/sysinst/msg.mi.es
+++ b/distrib/utils/sysinst/msg.mi.es
@@ -1032,10 +1032,14 @@ message empty {***EMPTY***}
 message timezone {Timezone}
 message change_rootpw {Change root password}
 message enable_binpkg {Enable installation of binary packages}
-message enable_sshd {Enable sshd}
-message enable_ntpd {Enable ntpd}
+message enable_sshd {Activar sshd}
+message enable_ntpd {Activar ntpd}
 message run_ntpdate {Run ntpdate at boot}
-message enable_mdnsd {Enable mdnsd}
+message enable_mdnsd {Activar mdnsd}
+message enable_xdm {Activar xdm}
+message enable_cgd {Activar cgd}
+message enable_lvm {Activar lvm}
+message enable_raid {Activar raidframe}
 message configmenu {Configure the additional items as needed.}
 message doneconfig {Finished configuring}
 message Install_pkgin {Install pkgin and update package summary}
@@ -1060,3 +1064,148 @@ message quit_install {Quit without installing pkgsrc} /*TODO*/
 message pkgin_failed 
 {Installation of pkgin failed, possibly because no binary packages  exist.  Please check the package path and try again.}
 message failed {Failed}
+
+
+message notsupported {Operación no admitida!}
+message askfsmountadv {Punto de montaje o 'raid' o 'CGD' o 'lvm'?}
+message partman {Partición extendida}
+message editbsdpart {Editar particiones BSD}
+message editmbr {Editar y guardar MBR}
+message switchgpt {Cambiar a GPT}
+message switchmbr {Cambiar a MBR}
+message renamedisk {Establece el nombre del disco}
+message fmtasraid {Formato como RAID}
+message fmtaslvm {Formato como LVM PV}
+message encrypt {Cifrar}
+message setbootable {La bandera de arranque}
+message erase {Borrado seguro}
+message undo {Deshacer los cambios}
+message unconfig {Desconfigurar}
+message edit {Editar}
+message doumount {Fuerza umount}
+message fillzeros {Llenar con ceros}
+message fillrandom {Llene los datos al azar}
+message fillcrypto {Rellene los datos de cifrado}
+message raid0 {0 - Sin paridad, creación de bandas sólo es simple.}
+message raid1 {1 - Creación de reflejos. La paridad es el espejo.}
+message raid4 {4 - Striping con paridad almacenada en el último componente. component.}
+message raid5 {5 - Striping con paridad en los componentes de todos. components.}
+
+message fremove {QUITAR}
+message remove {Quitar}
+message add {Añadir}
+message auto {auto}
+
+message removepartswarn {Esta eliminar todas las particiones en el disco. ¿Desea continuar? want to continue?}
+message saveprompt {Guarde los cambios antes de terminar?}
+message cantsave {Los cambios no se pueden guardar.}
+message noroot {No hay una partición raíz definida, no puede continuar \n}
+message wannaunblock {El dispositivo está bloqueado. ¿Quiere forzar a desbloquear y continuar? unblock it and continue?}
+message wannatry {¿Quieres probar?}
+message create_cgd {Crear cifrado de volumen (CGD)}
+message create_cnd {Crear imagen de disco virtual (VND)}
+message create_vg {Crear grupo de volúmenes (LVM VG)}
+message create_lv {      Crear volúmenes lógicos}
+message create_raid {Crear RAID por software}
+message updpmlist {Actualizar lista de dispositivos}
+message savepm {Guardar los cambios}
+message pmblocked {BLOQUEADO}
+message pmunchanged {SIN USO}
+message pmsetboot {ARRANCAR}
+message pmused {UTILIZA}
+message pmmounted {(montado)}
+message pmunused {(sin usar)}
+message pmgptdisk {Disco con GPT}
+
+message finishpm {Finalizar el particionado}
+message limitcount {Límite para el número de dispositivos se llegó!}
+message invaliddev {No válido dispositivo!}
+message avdisks {Discos disponibles:}
+message nofreedev {No se puede asignar nodo de dispositivo!}
+message partman_header
+{Partition Manager. Todos los discos, particiones y etc muestra allí.
+Al principio, las particiones MBR hacen, a continuación, hacer etiquetas BSD.
+Si desea utilizar RAID, LVM o CGD, siga estos pasos:
+1) Crear particiones BSD con el tipo necesario;
+2) Crear RAID / LVM VG / CGD el uso de estas particiones; 3) Guárdalo;
+4) Crear particiones de volúmenes RAID / CGD o lógico de LVM.}
+
+message raid_menufmt {   raid%d (nivel %1d) en %-34s %11uM}
+message raid_err_menufmt {   RAID VACIO!}
+message raid_disks_fmt {Discos: %32s}
+message raid_spares_fmt {Piezas de recambio: %20s}
+message raid_level_fmt {RAID de nivel:    %22d}
+message raid_numrow_fmt {numRow:           %22d}
+message raid_numcol_fmt {numCol:           %22d}
+message raid_numspare_fmt {numSpare:         %22d}
+message raid_sectpersu_fmt {sectPerSU:        %22d}
+message raid_superpar_fmt {SUsPerParityUnit: %22d}
+message raid_superrec_fmt {SUsPerReconUnit:  %22d}
+message raid_nomultidim {Matrices multidimensionales no son compatibles!}
+message raid_numrow_ask {numRow?}
+message raid_numcol_ask {numCol?}
+message raid_numspare_ask {numSpare?}
+message raid_sectpersu_ask {sectPerSU?}
+message raid_superpar_ask {SUsPerParityUnit?}
+message raid_superrec_ask {SUsPerReconUnit?}
+message raid_disks {Los discos en RAID:}
+message vnd_err_menufmt {   CAMINO NO DEFINIDO!}
+message vnd_assgn_menufmt {   vnd%1d en %-51s ASSIGN}
+message vnd_menufmt {   vnd%1d en %-45s %11uM}
+message vnd_path_fmt {Ruta del archivo: %22s}
+message vnd_assgn_fmt {Asignar existe la imagen: %14s}
+message vnd_size_fmt {Tamaño:          %22sM}
+message vnd_ro_fmt {Sólo lectura:     %22s}
+message vnd_geom_fmt {Establecer la geometría de la mano: %4s}
+message vnd_bps_fmt {Bytes por sector:     %18s}
+message vnd_spt_fmt {Sectores por pista:   %18s}
+message vnd_tpc_fmt {Pistas por cilindro:  %18s}
+message vnd_cyl_fmt {Cilindros:        %22s}
+message vnd_path_ask {Ruta de acceso?}
+message vnd_size_ask {Tamaño (MB)?}
+message vnd_bps_ask {Bytes por sector?}
+message vnd_spt_ask {Sectores por pista?}
+message vnd_tpc_ask {Pistas por cilindro?}
+message vnd_cyl_ask {Cilindros}
+message cgd_err_menufmt {   DISCO NO SE DEFINE!}
+message cgd_menufmt {   cgd%1d %-48s %11uM}
+message cgd_dev_fmt {Dispositivo de base: %19s}
+message cgd_enc_fmt {Encriptación:        %19s}
+message cgd_key_fmt {Tamaño de la clave:  %19d}
+message cgd_iv_fmt {Algoritmo IV:        %19s}
+message cgd_keygen_fmt {La generación de claves: %15s}
+message cgd_verif_fmt {Método de verificación:  %15s}
+message lvm_disks {Discos en VG:}
+message lvm_menufmt {   %-44s %20sM}
+message lvm_err_menufmt {   VACIAR VG!}
+message lvm_disks_fmt {PV's: %34s}
+message lvm_name_fmt {Nombre: %32s}
+message lvm_maxlv_fmt {MaxLogicalVolumes:  %20s}
+message lvm_maxpv_fmt {MaxPhysicalVolumes: %20s}
+message lvm_extsiz_fmt {PhysicalExtentSize: %20s}
+message lvm_name_ask {Nombre?}
+message lvm_maxlv_ask {MaxLogicalVolumes?}
+message lvm_maxpv_ask {MaxPhysicalVolumes?}
+message lvm_extsiz_ask {PhysicalExtentSize (MB)?}
+message lvmlv_menufmt {      El volumen lógico %-33s% 11uM}
+message lvmlv_name_fmt {Nombre: %32s}
+message lvmlv_size_fmt {Tamaño: %31dM}
+message lvmlv_ro_fmt {Sólo lectura:  %25s}
+message lvmlv_cont_fmt {Contigua:      %25s}
+message lvmlv_extnum_fmt {LogicalExtentsNumber: %18s}
+message lvmlv_minor_fmt {Menor número:  %25s}
+message lvmlv_mirrors_fmt {Espejos:       %25d}
+message lvmlv_regsiz_fmt {MirrorLogRegionSize:  %18s}
+message lvmlv_pers_fmt {Número de persistente menor: %11s}
+message lvmlv_readahsect_fmt {ReadAheadSectors:     %18s}
+message lvmlv_stripes_fmt {Rayas:         %25s}
+message lvmlv_stripesiz_fmt {Stripesize:    %25s}
+message lvmlv_zero_fmt {Puesta a cero de la primera KB: %8s}
+message lvmlv_name_ask {Nombre?}
+message lvmlv_size_ask {Tamaño (MB)?}
+message lvmlv_extnum_ask {LogicalExtentsNumber?}
+message lvmlv_minor_ask {Número menor de edad?}
+message lvmlv_mirrors_ask {Espejos?}
+message lvmlv_regsiz_ask {MirrorLogRegionSize?}
+message lvmlv_readahsect_ask {ReadAheadSectors?}
+message lvmlv_stripes_ask {Rayas?}
diff --git a/distrib/utils/sysinst/msg.mi.fr b/distrib/utils/sysinst/msg.mi.fr
index c23f09c..b4d2c12 100644
--- a/distrib/utils/sysinst/msg.mi.fr
+++ b/distrib/utils/sysinst/msg.mi.fr
@@ -1104,6 +1104,10 @@ message enable_sshd {Activer sshd}
 message enable_ntpd {Activer ntpd}
 message run_ntpdate {Executer ntpdate au démarrage}
 message enable_mdnsd {Activer mdnsd}
+message enable_xdm {Activer xdm}
+message enable_cgd {Activer cgd}
+message enable_lvm {Activer lvm}
+message enable_raid {Activer raidframe}
 message configmenu {Configurer les items suivants si nécéssaire.}
 message doneconfig {Configuration terminée}
 message Install_pkgin {Installer pkgin et mettre à jour le sommaire des paquetages}
@@ -1132,3 +1136,148 @@ message pkgin_failed
 {L'installation de pkgin a échoué, peut-être parce que son paquetage binaire
 n'existe pas.  Vérifiez le chemin et essayez à nouveau.}
 message failed {Échoué}
+
+
+message notsupported {Le fonctionnement n'est pas pris en charge!}
+message askfsmountadv {Point de montage ou de 'raid' ou 'cgd' ou 'lvm'?}
+message partman {Partitionnement étendue}
+message editbsdpart {Modifier les partitions BSD}
+message editmbr {Modifiez et enregistrez MBR}
+message switchgpt {Mettre à GPT}
+message switchmbr {Basculer vers MBR}
+message renamedisk {Définir le nom du disque}
+message fmtasraid {Format en RAID}
+message fmtaslvm {Format de LVM PV}
+message encrypt {Crypter}
+message setbootable {Drapeau d'amorçage}
+message erase {Fonction d'effacement sécurisé}
+message undo {Annuler les changements}
+message unconfig {Annulation de la configuration}
+message edit {Éditer}
+message doumount {Groupe umount}
+message fillzeros {Remplir de zéros}
+message fillrandom {Remplissez par des données aléatoires}
+message fillcrypto {Remplissez par crypto données}
+message raid0 {0 - Pas de parité, l'entrelacement seulement simple.}
+message raid1 {1 - Mirroring. La parité est le miroir.}
+message raid4 {4 - Entrelacement avec parité stockées sur le dernier composant. component.}
+message raid5 {5 - Entrelacement avec parité à tous les composants. components.}
+
+message fremove {ENLEVER}
+message remove {Supprimer}
+message add {Ajouter}
+message auto {auto}
+
+message removepartswarn {Cette supprimer toutes les partitions sur le disque. Voulez-vous continuer? want to continue?}
+message saveprompt {Enregistrer les modifications avant de terminer?}
+message cantsave {Aucune modification ne peut être sauvé.}
+message noroot {Aucune partition racine défini, ne peut pas continuer \n continue\n}
+message wannaunblock {L'appareil est bloqué. Voulez-vous forcer le débloquer et continuer? unblock it and continue?}
+message wannatry {Voulez-vous essayer?}
+message create_cgd {Le volume cryptographique Créer (CGD)}
+message create_cnd {Créer une image de disque virtuel (VND)}
+message create_vg {Créer un groupe de volumes LVM (VG)}
+message create_lv {      Créer un volume logique}
+message create_raid {Créer un RAID logiciel}
+message updpmlist {Mettre à jour la liste des dispositifs}
+message savepm {Enregistrer les modifications}
+message pmblocked {BLOQUE}
+message pmunchanged {INCHANGÉ}
+message pmsetboot {BOOT}
+message pmused {UTILISÉ}
+message pmmounted {(monté)}
+message pmunused {(non utilisé)}
+message pmgptdisk {Disque avec GPT}
+
+message finishpm {Terminer le partitionnement}
+message limitcount {Limite pour le nombre de dispositifs a été atteint!}
+message invaliddev {Blancs appareil!}
+message avdisks {Disques disponibles:}
+message nofreedev {Impossible d'allouer noeud de périphérique!}
+message partman_header
+{Gestionnaire de partition. Tous les disques, les partitions et etc affiché.
+Dans un premier temps partitions MBR faire, puis faire étiquette BSD.
+Si vous souhaitez utiliser RAID, LVM ou DMC, procédez comme suit:
+1) Créer les partitions BSD de type de besoin; 2) Créer un système RAID /
+LVM VG / DMC utilisation de ces partitions; 3) la sauver;
+4) Créer des partitions pour les volumes RAID / DMC ou logique par LVM.}
+
+message raid_menufmt {   raid%d (niveau %1d) sur %-32s %11uM}
+message raid_err_menufmt {   RAID VIDE!}
+message raid_disks_fmt {Disques: %31s}
+message raid_spares_fmt {Pièces de rechange: %20s}
+message raid_level_fmt {Niveau RAID:      %22d}
+message raid_numrow_fmt {numRow:           %22d}
+message raid_numcol_fmt {numCol:           %22d}
+message raid_numspare_fmt {numSpare:         %22d}
+message raid_sectpersu_fmt {sectPerSU:        %22d}
+message raid_superpar_fmt {SUsPerParityUnit: %22d}
+message raid_superrec_fmt {SUsPerReconUnit:  %22d}
+message raid_nomultidim {Tableaux multi-dimensionnels sont pas pris en charge!}
+message raid_numrow_ask {numRow?}
+message raid_numcol_ask {numCol?}
+message raid_numspare_ask {numSpare?}
+message raid_sectpersu_ask {sectPerSU?}
+message raid_superpar_ask {SUsPerParityUnit?}
+message raid_superrec_ask {SUsPerReconUnit?}
+message raid_disks {Disques en RAID:}
+message vnd_err_menufmt {   PATH NOT DEFINED!}
+message vnd_assgn_menufmt {   vnd%1d sur %-50s ASSIGN}
+message vnd_menufmt {   vnd%1d sur %-44s %11uM}
+message vnd_path_fmt {Chemin du fichier: %20s}
+message vnd_assgn_fmt {Attribuer existent image: %14s}
+message vnd_size_fmt {Taille:            %20sM}
+message vnd_ro_fmt {Read-only:          %20s}
+message vnd_geom_fmt {Définir la géométrie à la main: %8s}
+message vnd_bps_fmt {Octets par secteur: %20s}
+message vnd_spt_fmt {Secteurs par piste: %20s}
+message vnd_tpc_fmt {Pistes par cylindre: %19s}
+message vnd_cyl_fmt {Cylindres:          %20s}
+message vnd_path_ask {Chemin du fichier?}
+message vnd_size_ask {Taille (MB)?}
+message vnd_bps_ask {Octets par secteur?}
+message vnd_spt_ask {Secteurs par piste?}
+message vnd_tpc_ask {Pistes par cylindre?}
+message vnd_cyl_ask {Cylindres}
+message cgd_err_menufmt {   DISQUE NON DEFINI!}
+message cgd_menufmt {   cgd%1d %-48s %11uM}
+message cgd_dev_fmt {Dispositif de base: %20s}
+message cgd_enc_fmt {Chiffrage:          %20s}
+message cgd_key_fmt {Taille de la clé:   %20d}
+message cgd_iv_fmt {Algorithme IV:      %20s}
+message cgd_keygen_fmt {La génération des clés: %16s}
+message cgd_verif_fmt {Méthode de vérification: %15s}
+message lvm_disks {Disques à VG:}
+message lvm_menufmt {   %-44s %20sM}
+message lvm_err_menufmt {   VIDER VG!}
+message lvm_disks_fmt {PV's: %34s}
+message lvm_name_fmt {Nom: %35s}
+message lvm_maxlv_fmt {MaxLogicalVolumes:  %20s}
+message lvm_maxpv_fmt {MaxPhysicalVolumes: %20s}
+message lvm_extsiz_fmt {PhysicalExtentSize: %20s}
+message lvm_name_ask {Nom?}
+message lvm_maxlv_ask {MaxLogicalVolumes?}
+message lvm_maxpv_ask {MaxPhysicalVolumes?}
+message lvm_extsiz_ask {PhysicalExtentSize (MB)?}
+message lvmlv_menufmt {      Logique volume %-35s %11uM}
+message lvmlv_name_fmt {Nom: %35s}
+message lvmlv_size_fmt {Taille:   %29dM}
+message lvmlv_ro_fmt {Read-only: %29s}
+message lvmlv_cont_fmt {Contiguë:  %29s}
+message lvmlv_extnum_fmt {LogicalExtentsNumber: %18s}
+message lvmlv_minor_fmt {Nombre mineur: %25s}
+message lvmlv_mirrors_fmt {Miroirs:   %29d}
+message lvmlv_regsiz_fmt {MirrorLogRegionSize:  %18s}
+message lvmlv_pers_fmt {Persistante numéro mineur: %13s}
+message lvmlv_readahsect_fmt {ReadAheadSectors: %22s}
+message lvmlv_stripes_fmt {Rayures:    %28s}
+message lvmlv_stripesiz_fmt {Stripesize: %28s}
+message lvmlv_zero_fmt {Remise à zéro de la KB d'abord: %8s}
+message lvmlv_name_ask {Nom?}
+message lvmlv_size_ask {Taille (MB)?}
+message lvmlv_extnum_ask {LogicalExtentsNumber?}
+message lvmlv_minor_ask {Numéro mineur?}
+message lvmlv_mirrors_ask {Miroirs?}
+message lvmlv_regsiz_ask {MirrorLogRegionSize?}
+message lvmlv_readahsect_ask {ReadAheadSectors?}
+message lvmlv_stripes_ask {Stripes?}
diff --git a/distrib/utils/sysinst/msg.mi.pl b/distrib/utils/sysinst/msg.mi.pl
index 9e58a3a..6b74d96 100644
--- a/distrib/utils/sysinst/msg.mi.pl
+++ b/distrib/utils/sysinst/msg.mi.pl
@@ -928,7 +928,7 @@ message other {inny  }
 message Perform_IPv6_autoconfiguration {Wykonac autokonfiguracje IPv6?}
 message Perform_DHCP_autoconfiguration {Wykonac autkonfiguracje DHCP?}
 message Root_shell {Powloka root'a}
-message Color_scheme {Schemat kolorów}
+message Color_scheme {Kolorystyka}
 message White_on_black {Bia³y na czarnym}
 message Black_on_white {Czarno na bia³ym}
 message White_on_blue {Bia³y na niebieskim}
@@ -988,10 +988,14 @@ message empty {***EMPTY***}
 message timezone {Timezone}
 message change_rootpw {Change root password}
 message enable_binpkg {Enable installation of binary packages}
-message enable_sshd {Enable sshd}
-message enable_ntpd {Enable ntpd}
+message enable_sshd {Umo¿liwiaæ sshd}
+message enable_ntpd {Umo¿liwiaæ ntpd}
 message run_ntpdate {Run ntpdate at boot}
 message enable_mdnsd {Enable mdnsd}
+message enable_xdm {Umo¿liwiaæ XDM}
+message enable_cgd {Umo¿liwiaæ CGD}
+message enable_lvm {Umo¿liwiaæ LVM}
+message enable_raid {Umo¿liwiaæ RAIDframe}
 message configmenu {Configure the additional items as needed.}
 message doneconfig {Finished configuring}
 message Install_pkgin {Install pkgin and update package summary}
@@ -1016,3 +1020,147 @@ message quit_install {Quit without installing pkgsrc} /*TODO*/
 message pkgin_failed 
 {Installation of pkgin failed, possibly because no binary packages  exist.  Please check the package path and try again.}
 message failed {Failed}
+
+message notsupported {Operacja nie jest obs³ugiwana!}
+message askfsmountadv {Montowania lub "raid" lub "cgd" lub "lvm"?}
+message partman {Partycje rozszerzone}
+message editbsdpart {Edytuj partycje BSD}
+message editmbr {Edytowaæ i zapisywaæ MBR}
+message switchgpt {Prze³±cz na GPT}
+message switchmbr {Prze³±cz na MBR}
+message renamedisk {Ustaw nazwê dysku}
+message fmtasraid {Format jak RAID}
+message fmtaslvm {Format jak LVM PV}
+message encrypt {Szyfrowanie}
+message setbootable {Bootable flaga}
+message erase {Bezpieczne kasowanie}
+message undo {Cofanie zmian}
+message unconfig {Zdekonfigurowanie}
+message edit {Edytuj}
+message doumount {Si³a umount}
+message fillzeros {Wype³nij zerami}
+message fillrandom {Wype³nij losowymi danymi}
+message fillcrypto {Wype³nij przez crypto danych}
+message raid0 {0 - brak parzysto¶ci, tylko proste rozk³adanie.}
+message raid1 {1 - Mirroring. Parytet jest lustro.}
+message raid4 {4 - Malowanie z parytetu przechowywanych w ostatniej czê¶ci.}
+message raid5 {5 - Malowanie z parytetu w tych wszystkich elementów.}
+
+message fremove {USUÑ}
+message remove {Usun±æ}
+message add {Dodaæ}
+message auto {auto}
+
+message removepartswarn {To usun±æ wszystkie partycje na dysku. Czy chcesz kontynuowaæ?}
+message saveprompt {Zapisz zmiany przed zakoñczeniem?}
+message cantsave {Zmiany nie mog± byæ zbawieni.}
+message noroot {No partycja zdefiniowana, nie mo¿e kontynuowaæ \n}
+message wannaunblock {Urz±dzenie jest zablokowane. Czy chcesz, aby zmusiæ go odblokowaæ i kontynuowaæ?}
+message wannatry {Czy chcesz spróbowaæ?}
+message create_cgd {Utwórz wolumen kryptograficznych (CGD)}
+message create_cnd {Utwórz wirtualnego obraz dysku (VND)}
+message create_vg {Utwórz grupê woluminów (LVM VG)}
+message create_lv {      Utwórz wolumin logiczny}
+message create_raid {Utwórz oprogramowania RAID}
+message updpmlist {Aktualizuj listê urz±dzeñ}
+message savepm {Zapisz zmiany}
+message pmblocked {ZABLOK.}
+message pmunchanged {BEZ ZMIAN}
+message pmsetboot {BOOT}
+message pmused {U¯YWANE}
+message pmmounted {(zamontowany)}
+message pmunused {(nieu¿ywany)}
+message pmgptdisk {Dysku z GPT}
+
+message finishpm {Zakoñcz partycjonowanie}
+message limitcount {Limit liczby urz±dzeñ zosta³ osi±gniêty!}
+message invaliddev {Nieprawid³owy urz±dzenie!}
+message avdisks {Dostêpne dysków:}
+message nofreedev {Nie mo¿na przydzieliæ wêze³!}
+message partman_header
+{Partition Manager. Wszystkie dyski, partycje oraz itp. tam wy¶wietlane.
+Pocz±tkowo sprawiaj± partycji MBR, a nastêpnie dokonaæ BSD etykietê.
+Je¶li chcesz korzystaæ z RAID, LVM lub CGD, wykonaj nastêpuj±ce kroki:
+1) Tworzenie partycji BSD z potrzebnego typu;
+2) Utwórz RAID / LVM VG / CGD korzystania z tych partycji; 3) Zapisz go;
+4) Tworzenie partycji dla RAID / CGD lub Logical Volumes dla LVM.}
+
+message raid_menufmt {   raid%d (level %1d) on %-34s %11uM}
+message raid_err_menufmt {   EMPTY RAID!}
+message raid_disks_fmt {Dyski: %33s}
+message raid_spares_fmt {Czê¶ci zamienne: %23s}
+message raid_level_fmt {Poziom RAID:     %23d}
+message raid_numrow_fmt {numRow:          %23d}
+message raid_numcol_fmt {numCol:          %23d}
+message raid_numspare_fmt {numSpare:        %23d}
+message raid_sectpersu_fmt {sectPerSU:        %22d}
+message raid_superpar_fmt {SUsPerParityUnit: %22d}
+message raid_superrec_fmt {SUsPerReconUnit:  %22d}
+message raid_nomultidim {Tablice wielowymiarowe nie s± obs³ugiwane!}
+message raid_numrow_ask {numRow?}
+message raid_numcol_ask {numCol?}
+message raid_numspare_ask {numSpare?}
+message raid_sectpersu_ask {sectPerSU?}
+message raid_superpar_ask {SUsPerParityUnit?}
+message raid_superrec_ask {SUsPerReconUnit?}
+message raid_disks {Dyski w RAID:}
+message vnd_err_menufmt {   ¦CIE¯KA NIE ZDEFINIOWANE!}
+message vnd_assgn_menufmt {   vnd%1d na %-51s ASSIGN}
+message vnd_menufmt {   vnd%1d na %-45s %11uM}
+message vnd_path_fmt {¦cie¿ka: %31s}
+message vnd_assgn_fmt {Przypisywanie istnieæ obraz: %11s}
+message vnd_size_fmt {Rozmiar: %30sM}
+message vnd_ro_fmt {Tylko do odczytu:   %20s}
+message vnd_geom_fmt {Ustaw geometriê rêcznie: %15s}
+message vnd_bps_fmt {Bajtów na sektorów: %20s}
+message vnd_spt_fmt {Sektory na ¶cie¿ki: %20s}
+message vnd_tpc_fmt {Utwory na cylinder: %20s}
+message vnd_cyl_fmt {Si³owniki:          %20s}
+message vnd_path_ask {File Path?}
+message vnd_size_ask {Rozmiar (MB)?}
+message vnd_bps_ask {Bajtów na sektor?}
+message vnd_spt_ask {Sektory na ¶cie¿kê?}
+message vnd_tpc_ask {Utwory na cylinder?}
+message vnd_cyl_ask {Cylindry}
+message cgd_err_menufmt {   DISK NIE ZDEFINIOWANE!}
+message cgd_menufmt {   cgd%1d %-48s %11uM}
+message cgd_dev_fmt {Urz±dzenie podstawy: %19s}
+message cgd_enc_fmt {Encyption:           %19s}
+message cgd_key_fmt {Rozmiar klucza:      %19d}
+message cgd_iv_fmt {Algorytm IV: %27s}
+message cgd_keygen_fmt {Generowanie kluczy: %20s}
+message cgd_verif_fmt {Metoda weryfikacji: %20s}
+message lvm_disks {Dyski w VG:}
+message lvm_menufmt {   %-44s %20sM}
+message lvm_err_menufmt {   EMPTY VG!}
+message lvm_disks_fmt {PV's: %34s}
+message lvm_name_fmt {Nazwa: %33s}
+message lvm_maxlv_fmt {MaxLogicalVolumes:  %20s}
+message lvm_maxpv_fmt {MaxPhysicalVolumes: %20s}
+message lvm_extsiz_fmt {PhysicalExtentSize: %20s}
+message lvm_name_ask {Nazwa?}
+message lvm_maxlv_ask {MaxLogicalVolumes?}
+message lvm_maxpv_ask {MaxPhysicalVolumes?}
+message lvm_extsiz_ask {PhysicalExtentSize (MB)?}
+message lvmlv_menufmt {      Wolumin logiczny%-34s %11uM}
+message lvmlv_name_fmt {Nazwa: %33s}
+message lvmlv_size_fmt {Rozmiar: %30dM}
+message lvmlv_ro_fmt {Read-only:       %23s}
+message lvmlv_cont_fmt {S±siaduj±cy:     %23s}
+message lvmlv_extnum_fmt {LogicalExtentsNumber: %18s}
+message lvmlv_minor_fmt {Mniejsza liczba: %23s}
+message lvmlv_mirrors_fmt {Mirrors:     %27d}
+message lvmlv_regsiz_fmt {MirrorLogRegionSize:  %18s}
+message lvmlv_pers_fmt {Trwa³e drobne numer:  %18s}
+message lvmlv_readahsect_fmt {ReadAheadSectors ceny: %17s}
+message lvmlv_stripes_fmt {Stripes:     %27s}
+message lvmlv_stripesiz_fmt {StripeSize:  %27s}
+message lvmlv_zero_fmt {Zerowanie pierwszej KB: %16s}
+message lvmlv_name_ask {Nazwa?}
+message lvmlv_size_ask {Rozmiar (MB)?}
+message lvmlv_extnum_ask {LogicalExtentsNumber?}
+message lvmlv_minor_ask {Mniejsza liczba?}
+message lvmlv_mirrors_ask {Mirrors?}
+message lvmlv_regsiz_ask {MirrorLogRegionSize?}
+message lvmlv_readahsect_ask {ReadAheadSectors?}
+message lvmlv_stripes_ask {Stripes?}
diff --git a/distrib/utils/sysinst/net.c b/distrib/utils/sysinst/net.c
index 90d6b7a..96a9ffb 100644
--- a/distrib/utils/sysinst/net.c
+++ b/distrib/utils/sysinst/net.c
@@ -1003,7 +1003,7 @@ do_ftp_fetch(const char *set_name, struct ftpinfo *f)
 }
 
 
-// TODO: check MSG_netnotup_continueanyway and MSG_netnotup
+// XXX: check MSG_netnotup_continueanyway and MSG_netnotup
 
 int
 get_pkgsrc(void)
diff --git a/distrib/utils/sysinst/partman.c b/distrib/utils/sysinst/partman.c
index c1453cd..61248ab 100644
--- a/distrib/utils/sysinst/partman.c
+++ b/distrib/utils/sysinst/partman.c
@@ -32,60 +32,58 @@
 
 /* partman.c - extended partitioning */
 
+#include <fcntl.h>
 #include <errno.h>
+#include <libgen.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
-#include <fcntl.h>
 #include <util.h>
 
 #include "defs.h"
-#include "md.h"
 #include "msg_defs.h"
 #include "menu_defs.h"
 
+/* XXX: replace all MAX_ defince with depeding on kernel settings vars */
+#define MAX_ENTRIES 96
 
-typedef struct {
-	int retvalue;
-	int dev_num;
-	pm_devs_t *dev_pm;
-	char fullname[SSTRSIZE];
-	enum {PM_DISK_T, PM_PART_T, PM_RAID_T, PM_VND_T, PM_CGD_T} type;
-} part_entry_t;
-
-#define MNTS_MAX 96
-struct {
-    const char *diskdev, *mnt_opts, *fsname;
-    char *pi_mount;
-    int pm_part;
-} mnts[MNTS_MAX];
-
-#define MAX_RAIDS 16 // TODO: replace by true way
+#define MAX_RAID 8
 #define MAX_IN_RAID 48
-struct raids_t {
+typedef struct raids_t {
 	int enabled;
-	pm_devs_t *pm[MAX_IN_RAID];
+	int blocked;
+	int node;
 	char pm_name[MAX_IN_RAID][SSTRSIZE];
 	int pm_part[MAX_IN_RAID];
 	int pm_is_spare[MAX_IN_RAID];
 	int numRow, numCol, numSpare;
-	int sectPerSU, SUsPerParityUnit, SUsPerReconUnit, RAID_level;
-} raids[MAX_RAIDS];
+	int sectPerSU, SUsPerParityUnit, SUsPerReconUnit, raid_level;
+	uint total_size;
+	pm_devs_t *pm[MAX_IN_RAID];
+} raids_t;
+raids_t raids[MAX_RAID];
 
-#define MAX_VNDS 4
-struct vnds_t {
+#define MAX_VND 4
+typedef struct vnds_t {
 	int enabled;
+	int blocked;
+	int node;
 	char filepath[STRSIZE];
 	int size;
 	int readonly;
 	int is_exist;
 	int manual_geom;
 	int secsize, nsectors, ntracks, ncylinders;
-} vnds[MAX_VNDS];
+	int pm_part;    /* Used only for */
+	pm_devs_t *pm;  /* reffering device */
+} vnds_t;
+vnds_t vnds[MAX_VND];
 
-#define MAX_CGDS 4
-struct cgds_t {
+#define MAX_CGD 4
+typedef struct cgds_t {
 	int enabled;
+	int blocked;
+	int node;
 	pm_devs_t *pm;
 	char pm_name[SSTRSIZE];
 	int pm_part;
@@ -94,13 +92,80 @@ struct cgds_t {
 	const char *enc_type;
 	const char *iv_type;
 	int key_size;
-} cgds[MAX_CGDS];
+} cgds_t;
+cgds_t cgds[MAX_CGD];
+
+#define MAX_LVM_VG 16
+#define MAX_LVM_PV 255
+#define MAX_LVM_LV 255
+typedef struct pv_t {
+	pm_devs_t *pm;
+	char pm_name[SSTRSIZE];
+	int pm_part;
+	int metadatasize;
+	int metadatacopies;
+	int labelsector;
+	int setphysicalvolumesize;
+} pv_t;
+typedef struct lv_t {
+	int blocked;
+	int size;
+	char name[SSTRSIZE];
+	int readonly;
+	int contiguous;
+	char extents[SSTRSIZE];
+	int minor;
+	int mirrors;
+	int regionsize;
+	int persistent;
+	int readahead;
+	int stripes;
+	int stripesize;
+	int zero;
+} lv_t;
+typedef struct lvms_t {
+	int enabled;
+	int blocked;
+	char name[SSTRSIZE];
+	int maxlogicalvolumes;
+	int maxphysicalvolumes;
+	int physicalextentsize;
+	uint total_size;
+	pv_t pv[MAX_LVM_PV];
+	lv_t lv[MAX_LVM_LV];
+} lvms_t;
+lvms_t lvms[MAX_LVM_VG];
+
+typedef struct structinfo_t {
+	int max;
+	uint entry_size;
+	uint parent_size;
+	void *entry_first;
+	void *entry_enabled;
+	void *entry_blocked;
+	void *entry_node;
+} structinfo_t;
+structinfo_t raids_t_info, vnds_t_info, cgds_t_info, lvms_t_info, lv_t_info;
+
+typedef struct pm_upddevlist_adv_t {
+	const char *create_msg;
+	int pe_type;
+	structinfo_t *s;
+	int sub_num;
+	struct pm_upddevlist_adv_t *sub;
+} pm_upddevlist_adv_t;
+
+#define MAX_MNTS 48
+struct {
+    char dev[STRSIZE];
+    const char *mnt_opts, *on;
+} mnts[MAX_MNTS];
 
-int manage_newdev;
-int manage_curdev;
-int manage_raid_spare_cur;
+int cursel; /* Number of selected main menu entrie */
+int changed; /* flag indicating that we have unsaved changes */
+int raid_curspare; /* XXX: replace by true way */
 
-enum { /* Raid menu enum */
+enum { /* RAIDframe menu enum */
 	PMR_MENU_DEVS, PMR_MENU_DEVSSPARE, PMR_MENU_RAIDLEVEL, PMR_MENU_NUMROW,
 	PMR_MENU_NUMCOL, PMR_MENU_NUMSPARE,	PMR_MENU_SECTPERSU,	PMR_MENU_SUSPERPARITYUNIT,
 	PMR_MENU_SUSPERRECONUNIT, PMR_MENU_REMOVE, PMR_MENU_END
@@ -117,89 +182,121 @@ enum { /* CGD menu enum */
 	PMC_MENU_KEYGENTYPE, PMC_MENU_VERIFYTYPE, PMC_MENU_REMOVE, PMC_MENU_END
 };
 
-static int partman_manage_edit(int, void (*)(menudesc *, int, void *),
-	int (*)(menudesc *, void *), int (*)(int), void (*)(void *),
-	void *, int, int, int , void *);
-part_entry_t partman_manage_getdev(int);
-static int partman_raid_disk_add(menudesc *, void *);
-static int partman_raid_disk_del(menudesc *, void *);
-static int partman_cgd_disk_set(part_entry_t *);
-static void partman_select(pm_devs_t *);
-static int partman_mountall_sort(const void *, const void *);
-static int partman_mountall(void);
-static int partman_upddevlist(menudesc *, void *);
-static int partman_commit(menudesc *, void *);
-static int partman_submenu(menudesc *, void *);
-static void partman_menufmt(menudesc *, int, void *);
+enum { /* LVM menu enum */
+	PML_MENU_PV, PML_MENU_NAME, PML_MENU_MAXLOGICALVOLUMES,
+	PML_MENU_MAXPHYSICALVOLUMES, PML_MENU_PHYSICALEXTENTSIZE, 
+	PML_MENU_REMOVE, PML_MENU_END
+};
+
+enum { /* LVM submenu (logical volumes) enum */
+	PMLV_MENU_NAME, PMLV_MENU_SIZE, PMLV_MENU_READONLY, PMLV_MENU_CONTIGUOUS,
+	PMLV_MENU_EXTENTS, PMLV_MENU_MINOR, PMLV_MENU_PERSISTENT,
+	PMLV_MENU_MIRRORS, PMLV_MENU_REGIONSIZE, PMLV_MENU_READAHEAD,
+	PMLV_MENU_STRIPES, PMLV_MENU_STRIPESIZE, PMLV_MENU_ZERO, 
+	PMLV_MENU_REMOVE, PMLV_MENU_END
+};
 
+part_entry_t pm_dev_list(int);
+static int pm_raid_disk_add(menudesc *, void *);
+static int pm_raid_disk_del(menudesc *, void *);
+static int pm_cgd_disk_set(cgds_t *, part_entry_t *);
+static int pm_mount(pm_devs_t *, int);
+static int pm_upddevlist(menudesc *, void *);
+static void pm_select(pm_devs_t *);
 
+/* Universal menu for RAID/VND/CGD/LVM entry edit */
 static int
-partman_manage_edit(int menu_entries_count, void (*menu_fmt)(menudesc *, int, void *),
-	int (*action)(menudesc *, void *), int (*check_fun)(int),
-	void (*entry_init)(void *),	void* entry_init_arg,
-	int dev_num, int max, int entry_size, void *entry_enabled)
+pm_edit(int menu_entries_count, void (*menu_fmt)(menudesc *, int, void *),
+	int (*action)(menudesc *, void *), int (*check_fun)(void *),
+	void (*entry_init)(void *, void *),	void *entry_init_arg,
+	void *dev_ptr, int dev_ptr_delta, structinfo_t *s)
 {
-	int i, retvalue = 0, ok = 0;
+	int i, ok = 0;
 
-	if (dev_num < 0) {
+	if (dev_ptr == NULL) {
 		/* We should create new device */
-		for (i = 0; i < max && !ok; i++)
-			if (*(int*)((char*)entry_enabled + entry_size * i) != 1) {
-				manage_curdev = i;
-				entry_init(entry_init_arg);
-				*(int*)((char*)entry_enabled + entry_size * i) = 1;
+		for (i = 0; i < s->max && !ok; i++)
+			if (*(int*)((char*)s->entry_enabled + dev_ptr_delta + s->entry_size * i) == 0) {
+				dev_ptr = (char*)s->entry_first + dev_ptr_delta + s->entry_size * i;
+				entry_init(dev_ptr, entry_init_arg);
 				ok = 1;
 			}
 		if (!ok) {
-			msg_prompt_win("Limit for the devices count was reached!", -1, 18, 0, 0, NULL, NULL, 0);
+			/* We do not have free device slots */
+			process_menu(MENU_ok, deconst(MSG_limitcount));
 			return -1;
 		}
-	} else {
-		/* ... or edit existent */
-		if (*(int*)((char*)entry_enabled + entry_size * dev_num) == 0) {
-			if (logfp)
-				fprintf(logfp, "partman_manage_edit: invalid drive\n");
-				msg_prompt_win("Invalid device!", -1, 18, 0, 0, NULL, NULL, 0);
-			return -2;
-		}
-		manage_curdev = dev_num;
 	}
 
 	menu_ent menu_entries[menu_entries_count];
 	for (i = 0; i < menu_entries_count - 1; i++)
 		menu_entries[i] = (menu_ent) {NULL, OPT_NOMENU, 0, action};
-	menu_entries[i] = (menu_ent) {"REMOVE", OPT_NOMENU, OPT_EXIT, action};
+	menu_entries[i] = (menu_ent) {MSG_fremove, OPT_NOMENU, OPT_EXIT, action};
 
 	int menu_no = -1;
 	menu_no = new_menu(NULL, menu_entries, menu_entries_count,
 		-1, -1, 0, 40, MC_NOCLEAR | MC_SCROLL,
 		NULL, menu_fmt, NULL, NULL, MSG_DONE);
 	
-	process_menu(menu_no, &retvalue);
+	process_menu(menu_no, dev_ptr);
 	free_menu(menu_no);
-	if (check_fun != NULL)
-		check_fun(manage_curdev);
 
-	return retvalue;
+	return check_fun(dev_ptr);
 }
 
-part_entry_t
-partman_manage_getdev(int fstype)
+static void
+pm_getdevstring(char *buf, int len, pm_devs_t *pm_cur, int num)
 {
-	pm_devs_t *pm_i;
-	int dev_num = -1, num_devs;
 	int i;
+
+	if (pm_cur->isspecial)
+		snprintf(buf, len, "%s", pm_cur->diskdev);
+	else if (num + 'a' < 'a' || num + 'a' > 'a' + MAXPARTITIONS)
+		snprintf(buf, len, "%sd", pm_cur->diskdev);
+	else if (pm_cur->gpt) {
+		for (i = 0; i < MAX_WEDGES; i++)
+			if (wedges[i].pm == pm_cur &&
+				wedges[i].ptn == num)
+				snprintf(buf, len, "dk%d", i); // XXX: xxx
+	} else
+		snprintf(buf, len, "%s%c", pm_cur->diskdev, num + 'a');
+
+	return;
+}
+
+/* Show filtered partitions menu */
+part_entry_t
+pm_dev_list(int type)
+{
+	int dev_num = -1, num_devs = 0;
+	int i, ok;
 	int menu_no;
 	menu_ent menu_entries[MAX_DISKS*MAXPARTITIONS];
 	part_entry_t disk_entries[MAX_DISKS*MAXPARTITIONS];
+	pm_devs_t *pm_i;
 
-	for (pm_i = pm_head->next, num_devs = 0; pm_i != NULL; pm_i = pm_i->next)
+	SLIST_FOREACH(pm_i, &pm_head, l)
 		for (i = 0; i < MAXPARTITIONS; i++) {
-			if (pm_i->bsdlabel[i].pi_fstype == fstype) {
-				disk_entries[num_devs].dev_pm = pm_i;
-				disk_entries[num_devs].dev_num = 'a' + i;
-				snprintf(disk_entries[num_devs].fullname, SSTRSIZE, "%s%c",
-						pm_i->diskdev, 'a' + i);
+			ok = 0;
+			switch (type) {
+				case PM_RAID_T:
+					if (pm_i->bsdlabel[i].pi_fstype == FS_RAID)
+						ok = 1;
+					break;
+				case PM_CGD_T:
+					if (pm_i->bsdlabel[i].pi_fstype == FS_CGD)
+						ok = 1;
+					break;
+				case PM_LVM_T:
+					if (pm_i->bsdlabel[i].lvmpv)
+						ok = 1;
+					break;
+			}
+			if (ok && pm_partusage(pm_i, i, 0) == 0) {
+				disk_entries[num_devs].dev_ptr = pm_i;
+				disk_entries[num_devs].dev_num = i;
+				pm_getdevstring(disk_entries[num_devs].fullname, SSTRSIZE, pm_i, i);
+
 				menu_entries[num_devs] = (struct menu_ent) {
 					.opt_name = disk_entries[num_devs].fullname,
 					.opt_action = set_menu_select,
@@ -210,9 +307,9 @@ partman_manage_getdev(int fstype)
 			}
 		}
 
-	menu_no = new_menu("Available disks:",
-		menu_entries, num_devs, -1, -1, (num_devs+1<3)?3:num_devs+1, 13, MC_SCROLL | MC_NOCLEAR,
-		NULL, NULL , NULL, NULL, NULL);
+	menu_no = new_menu(MSG_avdisks,
+		menu_entries, num_devs, -1, -1, (num_devs+1<3)?3:num_devs+1, 13,
+		MC_SCROLL | MC_NOCLEAR, NULL, NULL, NULL, NULL, NULL);
 	if (menu_no == -1)
 		return (part_entry_t) { .retvalue = -1, };
 	process_menu(menu_no, &dev_num);
@@ -225,83 +322,125 @@ partman_manage_getdev(int fstype)
 	return disk_entries[dev_num];
 }
 
-/*** RAIDs ***/
-
-static void
-partman_raid_menufmt(menudesc *m, int opt, void *arg)
+/* Get unused raid*, cgd* or vnd* device */
+static int
+pm_manage_getfreenode(void *node, const char *d, structinfo_t *s)
 {
-	int i, num, ok = 0;
-	
-	num = ((part_entry_t *)arg)[opt].dev_num;
+	int i, ii, ok;
+	char buf[SSTRSIZE];
+	pm_devs_t *pm_i;
 
-	if (raids[num].enabled != 0) {
-		wprintw(m->mw, "   RAID%d - ", raids[num].RAID_level);
-		for (i = 0; i < MAX_IN_RAID; i++)
-			if (raids[num].pm[i] != NULL) {
-				wprintw(m->mw, "%s ", raids[num].pm_name[i]);
-				ok = 1;
+	*(int*)node = -1;
+	for (i = 0; i < s->max; i++) {
+		ok = 1;
+		/* Check that node is not already reserved */
+		for (ii = 0; ii < s->max; ii++)
+			if (*(int*)((char*)s->entry_node + s->entry_size * ii) == i) {
+				ok = 0;
+				break;
 			}
-		if (!ok)
-			wprintw(m->mw, "no components");
+		if (! ok)
+			continue;
+		/* Check that node is not in the device list */
+		snprintf(buf, SSTRSIZE, "%s%d", d, i);
+		SLIST_FOREACH(pm_i, &pm_head, l)
+			if (! strcmp(pm_i->diskdev, buf)) {
+				ok = 0;
+				break;
+			}
+		if (ok) {
+			*(int*)node = i;
+			return i;
+		}
 	}
+	process_menu(MENU_ok, deconst(MSG_nofreedev));
+	return -1;
+}
+
+/***
+RAIDs
+***/
+
+static void
+pm_raid_menufmt(menudesc *m, int opt, void *arg)
+{
+	int i, ok = 0;
+	char buf[STRSIZE]; buf[0] = '\0';
+	raids_t *dev_ptr = ((part_entry_t *)arg)[opt].dev_ptr;
+
+	if (dev_ptr->enabled == 0)
+		return;
+	for (i = 0; i < MAX_IN_RAID; i++)
+		if (dev_ptr->pm[i] != NULL) {
+			strncat(buf, dev_ptr->pm_name[i], STRSIZE);
+			strncat(buf, " ", STRSIZE);
+			ok = 1;
+		}
+	if (ok)
+		wprintw(m->mw, msg_string(MSG_raid_menufmt), dev_ptr->node,
+			dev_ptr->raid_level, buf, dev_ptr->total_size);
+	else
+		wprintw(m->mw, "%s", msg_string(MSG_raid_err_menufmt));
 	return;
 }
 
 static void
-partman_raid_edit_menufmt(menudesc *m, int opt, void *arg)
+pm_raid_edit_menufmt(menudesc *m, int opt, void *arg)
 {
 	int i;
-	char buf[STRSIZE];
-	buf[0] = '\0';
+	char buf[STRSIZE]; buf[0] = '\0';
+	raids_t *dev_ptr = arg;
 
-	switch (opt){
+	switch (opt) {
 		case PMR_MENU_DEVS:
 			for (i = 0; i < MAX_IN_RAID; i++)
-				if (raids[manage_curdev].pm[i] != NULL && raids[manage_curdev].pm_is_spare[i] == 0)
-					snprintf(buf, STRSIZE, "%s %s", buf, raids[manage_curdev].pm_name[i]);
-			wprintw(m->mw, "Disks: %33s", buf);
+				if (dev_ptr->pm[i] != NULL && dev_ptr->pm_is_spare[i] == 0)
+					snprintf(buf, STRSIZE, "%s %s", buf, dev_ptr->pm_name[i]);
+			wprintw(m->mw, msg_string(MSG_raid_disks_fmt), buf);
 			break;
 		case PMR_MENU_DEVSSPARE:
 			for (i = 0; i < MAX_IN_RAID; i++)
-				if (raids[manage_curdev].pm[i] != NULL && raids[manage_curdev].pm_is_spare[i] != 0)
-					snprintf(buf, STRSIZE, "%s %s", buf, raids[manage_curdev].pm_name[i]);
-			wprintw(m->mw, "Spares: %32s", buf);
+				if (dev_ptr->pm[i] != NULL && dev_ptr->pm_is_spare[i] != 0)
+					snprintf(buf, STRSIZE, "%s %s", buf, dev_ptr->pm_name[i]);
+			wprintw(m->mw, msg_string(MSG_raid_spares_fmt), buf);
 			break;
 		case PMR_MENU_RAIDLEVEL:
-			wprintw(m->mw, "RAID level:       %22d", raids[manage_curdev].RAID_level);
+			wprintw(m->mw, msg_string(MSG_raid_level_fmt), dev_ptr->raid_level);
 			break;
 		case PMR_MENU_NUMROW:
-			wprintw(m->mw, "numRow:           %22d", raids[manage_curdev].numRow);
+			wprintw(m->mw, msg_string(MSG_raid_numrow_fmt), dev_ptr->numRow);
 			break;
 		case PMR_MENU_NUMCOL:
-			wprintw(m->mw, "numCol:           %22d", raids[manage_curdev].numCol);
+			wprintw(m->mw, msg_string(MSG_raid_numcol_fmt), dev_ptr->numCol);
 			break;
 		case PMR_MENU_NUMSPARE:
-			wprintw(m->mw, "numSpare:         %22d", raids[manage_curdev].numSpare);
+			wprintw(m->mw, msg_string(MSG_raid_numspare_fmt), dev_ptr->numSpare);
 			break;
 		case PMR_MENU_SECTPERSU:
-			wprintw(m->mw, "sectPerSU:        %22d", raids[manage_curdev].sectPerSU);
+			wprintw(m->mw, msg_string(MSG_raid_sectpersu_fmt), dev_ptr->sectPerSU);
 			break;
 		case PMR_MENU_SUSPERPARITYUNIT:
-			wprintw(m->mw, "SUsPerParityUnit: %22d", raids[manage_curdev].SUsPerParityUnit);
+			wprintw(m->mw, msg_string(MSG_raid_superpar_fmt), dev_ptr->SUsPerParityUnit);
 			break;
 		case PMR_MENU_SUSPERRECONUNIT:
-			wprintw(m->mw, "SUsPerReconUnit:  %22d", raids[manage_curdev].SUsPerReconUnit);
+			wprintw(m->mw, msg_string(MSG_raid_superrec_fmt), dev_ptr->SUsPerReconUnit);
 			break;
 	}
 	return;
 }
 
 static int
-partman_raid_set_value(menudesc *m, void *arg)
+pm_raid_set_value(menudesc *m, void *arg)
 {
-	char buf[SSTRSIZE];
-	const char *msg_to_show = NULL;
 	int retvalue = -1;
 	int *out_var = NULL;
+	char buf[SSTRSIZE];
+	const char *msg_to_show = NULL;
+	raids_t *dev_ptr = arg;
+
 	static menu_ent menuent_disk_adddel[] = {
-	    {"Add", OPT_NOMENU, OPT_EXIT, partman_raid_disk_add}, 
-	    {"Remove", OPT_NOMENU, OPT_EXIT, partman_raid_disk_del}
+	    {MSG_add, OPT_NOMENU, OPT_EXIT, pm_raid_disk_add}, 
+	    {MSG_remove, OPT_NOMENU, OPT_EXIT, pm_raid_disk_del}
 	};
 	static int menu_disk_adddel = -1;
 	if (menu_disk_adddel == -1) {
@@ -311,47 +450,46 @@ partman_raid_set_value(menudesc *m, void *arg)
 	
 	switch (m->cursel) {
 		case PMR_MENU_DEVS:
-			manage_raid_spare_cur = 0;
-			process_menu(menu_disk_adddel, NULL);
+			raid_curspare = 0;
+			process_menu(menu_disk_adddel, dev_ptr);
 			return 0;
 		case PMR_MENU_DEVSSPARE:
-			manage_raid_spare_cur = 1;
-			process_menu(menu_disk_adddel, NULL);
+			raid_curspare = 1;
+			process_menu(menu_disk_adddel, dev_ptr);
 			return 0;
 		case PMR_MENU_RAIDLEVEL:
 			process_menu(MENU_raidlevel, &retvalue);
-			if (retvalue > 0)
-				raids[manage_curdev].RAID_level = retvalue;
+			if (retvalue >= 0)
+				dev_ptr->raid_level = retvalue;
 			return 0;
 		case PMR_MENU_NUMROW:
-			msg_prompt_win("Multi-dimensional arrays are NOT supported!",
-							-1, 18, 0, 0, NULL, NULL, 0);
+			process_menu(MENU_ok, deconst(MSG_raid_nomultidim));
 			return 0;
-			msg_to_show = "numRow?";
-			out_var = &(raids[manage_curdev].numRow);
+			msg_to_show = MSG_raid_numrow_ask;
+			out_var = &(dev_ptr->numRow);
 			break;
 		case PMR_MENU_NUMCOL:
-			msg_to_show = "numCol?";
-			out_var = &(raids[manage_curdev].numCol);
+			msg_to_show = MSG_raid_numcol_ask;
+			out_var = &(dev_ptr->numCol);
 			break;
 		case PMR_MENU_NUMSPARE:
-			msg_to_show = "numSpare?";
-			out_var = &(raids[manage_curdev].numSpare);
+			msg_to_show = MSG_raid_numspare_ask;
+			out_var = &(dev_ptr->numSpare);
 			break;
 		case PMR_MENU_SECTPERSU:
-			msg_to_show = "sectPerSU?";
-			out_var = &(raids[manage_curdev].sectPerSU);
+			msg_to_show = MSG_raid_sectpersu_ask;
+			out_var = &(dev_ptr->sectPerSU);
 			break;
 		case PMR_MENU_SUSPERPARITYUNIT:
-			msg_to_show = "SUsPerParityUnit?";
-			out_var = &(raids[manage_curdev].SUsPerParityUnit);
+			msg_to_show = MSG_raid_superpar_ask;
+			out_var = &(dev_ptr->SUsPerParityUnit);
 			break;
 		case PMR_MENU_SUSPERRECONUNIT:
-			msg_to_show = "SUsPerReconUnit?";
-			out_var = &(raids[manage_curdev].SUsPerReconUnit);
+			msg_to_show = MSG_raid_superrec_ask;
+			out_var = &(dev_ptr->SUsPerReconUnit);
 			break;
 		case PMR_MENU_REMOVE:
-			raids[manage_curdev].enabled = 0;
+			dev_ptr->enabled = 0;
 			return 0;
 	}
 	if (out_var == NULL || msg_to_show == NULL)
@@ -364,11 +502,13 @@ partman_raid_set_value(menudesc *m, void *arg)
 }
 
 static void
-partman_raid_new_init(void* none)
+pm_raid_init(void *arg, void *none)
 {
-	memset(&(raids[manage_curdev]), 0, sizeof raids[manage_curdev]);
-	raids[manage_curdev] = (struct raids_t) {
+	raids_t *dev_ptr = arg;
+	memset(dev_ptr, 0, sizeof(*dev_ptr));
+	*dev_ptr = (struct raids_t) {
 		.enabled = 1,
+		.blocked = 0,
 		.sectPerSU = 32,
 		.SUsPerParityUnit = 1,
 		.SUsPerReconUnit = 1,
@@ -377,59 +517,86 @@ partman_raid_new_init(void* none)
 }
 
 static int
-partman_raid_check(int dev_num)
+pm_raid_check(void *arg)
 {
-	int ok = 0, i;
+	int i, dev_num = 0, min_size = 0, cur_size = 0;
+	raids_t *dev_ptr = arg;
+
+	if (dev_ptr->blocked)
+		return 0;
 	for (i = 0; i < MAX_IN_RAID; i++)
-		if (raids[dev_num].pm[i] != NULL && 
-				raids[dev_num].pm_is_spare[i] != 1) {
-			ok = 1;
-			break;
+		if (dev_ptr->pm[i] != NULL) {
+			cur_size = dev_ptr->pm[i]->bsdlabel[dev_ptr->pm_part[i]].pi_size /
+						(MEG / dev_ptr->pm[i]->sectorsize);
+			if (cur_size < min_size || dev_num == 0)
+				min_size = cur_size;
+			if (!dev_ptr->pm_is_spare[i])
+				dev_num++;
 		}
-	if (! ok)
-		raids[manage_curdev].enabled = 0;
-	return raids[manage_curdev].enabled;
+	/* Calculate summ of available space */
+	if (dev_num > 0) {
+		switch (dev_ptr->raid_level) {
+			case 0:
+				dev_ptr->total_size = min_size * dev_num;
+				break;
+			case 1:
+				dev_ptr->total_size = min_size;
+				break;
+			case 4:
+			case 5:
+				dev_ptr->total_size = min_size * (dev_num - 1);
+				break;
+		}
+		pm_manage_getfreenode(&(dev_ptr->node), "raid", &raids_t_info);
+		if (dev_ptr->node < 0)
+			dev_ptr->enabled = 0;
+	}
+	else
+		dev_ptr->enabled = 0;
+	return dev_ptr->enabled;
 }
 
 static int
-partman_raid_disk_add(menudesc *m, void *arg)
+pm_raid_disk_add(menudesc *m, void *arg)
 {
 	int i;
-	part_entry_t disk_entries = partman_manage_getdev(FS_RAID);
-	if (disk_entries.retvalue < 0)
-		return disk_entries.retvalue;
+	raids_t *dev_ptr = arg;
+	part_entry_t disk_entrie = pm_dev_list(PM_RAID_T);
+	if (disk_entrie.retvalue < 0)
+		return disk_entrie.retvalue;
 
 	for (i = 0; i < MAX_IN_RAID; i++)
-		if (raids[manage_curdev].pm[i] == NULL) {
-			raids[manage_curdev].pm[i] = disk_entries.dev_pm;
-			raids[manage_curdev].pm_part[i] = disk_entries.dev_num;
-			raids[manage_curdev].pm_is_spare[i] = manage_raid_spare_cur;
-			strncpy(raids[manage_curdev].pm_name[i], disk_entries.fullname, SSTRSIZE);
-			if (manage_raid_spare_cur)
-				raids[manage_curdev].numSpare++;
+		if (dev_ptr->pm[i] == NULL) {
+			dev_ptr->pm[i] = disk_entrie.dev_ptr;
+			dev_ptr->pm_part[i] = disk_entrie.dev_num;
+			dev_ptr->pm_is_spare[i] = raid_curspare;
+			strlcpy(dev_ptr->pm_name[i], disk_entrie.fullname, SSTRSIZE);
+			if (raid_curspare)
+				dev_ptr->numSpare++;
 			else
-				raids[manage_curdev].numCol++;
-			raids[manage_curdev].numRow = 1;
+				dev_ptr->numCol++;
+			dev_ptr->numRow = 1;
 			break;
 		}
 	return 0;
 }
 
 static int
-partman_raid_disk_del(menudesc *m, void *arg)
+pm_raid_disk_del(menudesc *m, void *arg)
 {
 	int retvalue = -1, num_devs = 0;
 	int i, pm_cur;
 	int menu_no;
+	raids_t *dev_ptr = arg;
 	menu_ent menu_entries[MAX_IN_RAID];
 	part_entry_t submenu_args[MAX_IN_RAID];
 
 	for (i = 0; i < MAX_IN_RAID; i++) {
-		if (raids[manage_curdev].pm[i] == NULL ||
-			raids[manage_curdev].pm_is_spare[i] != manage_raid_spare_cur)
+		if (dev_ptr->pm[i] == NULL ||
+			dev_ptr->pm_is_spare[i] != raid_curspare)
 			continue;
 		menu_entries[num_devs] = (struct menu_ent) {
-			.opt_name = raids[manage_curdev].pm_name[i],
+			.opt_name = dev_ptr->pm_name[i],
 			.opt_action = set_menu_select,
 			.opt_menu = OPT_NOMENU,
 			.opt_flags = OPT_EXIT,
@@ -438,7 +605,7 @@ partman_raid_disk_del(menudesc *m, void *arg)
 		num_devs++;
 	}
 
-	menu_no = new_menu("Disks in RAID:",
+	menu_no = new_menu(MSG_raid_disks,
 		menu_entries, num_devs, -1, -1, (num_devs+1<3)?3:num_devs+1, 13,
 		MC_SCROLL | MC_NOCLEAR, NULL, NULL, NULL, NULL, NULL);
 	if (menu_no == -1)
@@ -451,46 +618,29 @@ partman_raid_disk_del(menudesc *m, void *arg)
 
 	pm_cur = submenu_args[retvalue].dev_num;
 
-	if (raids[manage_curdev].pm_is_spare[pm_cur])
-		raids[manage_curdev].numSpare--;
+	if (dev_ptr->pm_is_spare[pm_cur])
+		dev_ptr->numSpare--;
 	else
-		raids[manage_curdev].numCol--;
-	raids[manage_curdev].numRow = (raids[manage_curdev].numCol)?1:0;
-	raids[manage_curdev].pm[pm_cur] = NULL;
+		dev_ptr->numCol--;
+	dev_ptr->numRow = (dev_ptr->numCol)?1:0;
+	dev_ptr->pm[pm_cur] = NULL;
 
 	return 0;
 }
 
 static int
-partman_raid_edit(menudesc *m, void *arg)
-{
-	((part_entry_t *)arg)[0].retvalue = m->cursel + 1;
-
-	return partman_manage_edit(PMR_MENU_END, partman_raid_edit_menufmt,
-		partman_raid_set_value,	partman_raid_check, partman_raid_new_init,
-		NULL, ((part_entry_t *)arg)[m->cursel].dev_num, MAX_RAIDS,
-		sizeof raids[0], &(raids[0].enabled));
-}
-
-static int
-partman_raid_commit(void)
+pm_raid_commit(void)
 {
-	int i, ii, raid_devnum;
+	int i, ii;
 	FILE *f;
 	char f_name[STRSIZE];
 
-	for (raid_devnum = 0, i = 0; raid_devnum < MAX_RAIDS && i < MAX_RAIDS;
-			raid_devnum++, i++) {
-		if (! partman_raid_check(i))
+	for (i = 0; i < MAX_RAID; i++) {
+		if (! pm_raid_check(&raids[i]))
 			continue;
 
-		/* Trying to detect free raid device (yes, ugly way) */
-		while (run_program(RUN_SILENT | RUN_ERROR_OK, "raidctl -G raid%d",
-				raid_devnum) == 0)
-			raid_devnum++;
-
 		/* Generating configure file for our raid */
-		snprintf(f_name, SSTRSIZE, "/tmp/raid.%d.conf", raid_devnum);
+		snprintf(f_name, SSTRSIZE, "/tmp/raid.%d.conf", raids[i].node);
 		f = fopen(f_name, "w");
 		if (f == NULL) {
 			endwin();
@@ -517,7 +667,7 @@ partman_raid_commit(void)
 
 		scripting_fprintf(f, "\nSTART layout\n%d %d %d %d\n", raids[i].sectPerSU,
 						raids[i].SUsPerParityUnit, raids[i].SUsPerReconUnit,
-						raids[i].RAID_level);
+						raids[i].raid_level);
 
 		scripting_fprintf(f, "\nSTART queue\nfifo 100\n\n");
 		scripting_fprintf(NULL, "EOF\n");
@@ -526,141 +676,163 @@ partman_raid_commit(void)
 
 		/* Raid initialization */
 		if (
-			run_program(RUN_DISPLAY, "raidctl -C %s raid%d",
-							f_name, raid_devnum) == 0 &&
-			run_program(RUN_DISPLAY, "raidctl -I %d raid%d",
-							rand(), raid_devnum) == 0 &&
-			run_program(RUN_DISPLAY, "raidctl -vi raid%d",
-							raid_devnum) == 0
-			)
-			raids[i].enabled = 0; /* RAID creation done, remove it from list to 
+			run_program(RUN_DISPLAY | RUN_PROGRESS, "raidctl -C %s raid%d",
+							f_name, raids[i].node) == 0 &&
+			run_program(RUN_DISPLAY | RUN_PROGRESS, "raidctl -I %d raid%d",
+							rand(), raids[i].node) == 0 &&
+			run_program(RUN_DISPLAY | RUN_PROGRESS, "raidctl -vi raid%d",
+							raids[i].node) == 0 &&
+			run_program(RUN_DISPLAY | RUN_PROGRESS, "raidctl -v -A yes raid%d",
+							raids[i].node) == 0
+			) {
+			raids[i].blocked = 1; /* RAID creation done, remove it from list to 
 									 prevent it's repeated reinitialization */
+			for (ii = 0; ii < MAX_IN_RAID; ii++)
+				if (raids[i].pm[ii] != NULL)
+					raids[i].pm[ii]->blocked++;
+		}
 	}
 	return 0;
 }
 
-/*** VND ***/
+/***
+VND
+***/
 
 static void
-partman_vnd_menufmt(menudesc *m, int opt, void *arg)
+pm_vnd_menufmt(menudesc *m, int opt, void *arg)
 {
-	int num = ((part_entry_t *)arg)[opt].dev_num;
-
-	if (vnds[num].enabled != 0) {
-		if (strlen(vnds[num].filepath) < 1)
-			wprintw(m->mw, "   PATH NOT DEFINED!");
-		else
-			wprintw(m->mw, "   %s (%dMB)", vnds[num].filepath, vnds[num].size);
-	}
+	vnds_t *dev_ptr = ((part_entry_t *)arg)[opt].dev_ptr;
+
+	if (dev_ptr->enabled == 0)
+		return;
+	if (strlen(dev_ptr->filepath) < 1)
+		wprintw(m->mw, "%s", msg_string(MSG_vnd_err_menufmt));
+	else if (dev_ptr->is_exist)
+		wprintw(m->mw, msg_string(MSG_vnd_assgn_menufmt),
+			dev_ptr->node, dev_ptr->filepath);
+	else 
+		wprintw(m->mw, msg_string(MSG_vnd_menufmt),
+			dev_ptr->node, dev_ptr->filepath, dev_ptr->size);
 	return;
 }
 
 static void
-partman_vnd_edit_menufmt(menudesc *m, int opt, void *arg)
+pm_vnd_edit_menufmt(menudesc *m, int opt, void *arg)
 {
+	vnds_t *dev_ptr = arg;
 	char buf[SSTRSIZE];
 	strcpy(buf, "-");
 
-	switch (opt){
+	switch (opt) {
 		case PMV_MENU_FILEPATH:
-			wprintw(m->mw, "File path: %29s", vnds[manage_curdev].filepath);
+			wprintw(m->mw, msg_string(MSG_vnd_path_fmt), dev_ptr->filepath);
 			break;
 		case PMV_MENU_EXIST:
-			wprintw(m->mw, "Assign exist image: %20s", vnds[manage_curdev].is_exist?"yes":"no");
+			wprintw(m->mw, msg_string(MSG_vnd_assgn_fmt),
+				dev_ptr->is_exist? msg_string(MSG_Yes) : msg_string(MSG_No));
 			break;
 		case PMV_MENU_SIZE:
-			if (!vnds[manage_curdev].is_exist)
-				snprintf(buf, SSTRSIZE, "%d", vnds[manage_curdev].size);
-			wprintw(m->mw, "Size (MB):        %22s", buf);
+			if (!dev_ptr->is_exist)
+				snprintf(buf, SSTRSIZE, "%d", dev_ptr->size);
+			wprintw(m->mw, msg_string(MSG_vnd_size_fmt), buf);
 			break;
 		case PMV_MENU_RO:
-			wprintw(m->mw, "Read-only:        %22s", vnds[manage_curdev].readonly?"yes":"no");
+			wprintw(m->mw, msg_string(MSG_vnd_ro_fmt),
+				dev_ptr->readonly? msg_string(MSG_Yes) : msg_string(MSG_No));
 			break;
 		case PMV_MENU_MGEOM:
-			if (!vnds[manage_curdev].is_exist)
-				snprintf(buf, SSTRSIZE, "%s", vnds[manage_curdev].manual_geom?"yes":"no");
-			wprintw(m->mw, "Set geometry by hand: %18s", buf);
+			if (!dev_ptr->is_exist)
+				snprintf(buf, SSTRSIZE, "%s",
+					dev_ptr->manual_geom? msg_string(MSG_Yes) : msg_string(MSG_No));
+			wprintw(m->mw, msg_string(MSG_vnd_geom_fmt), buf);
 			break;
 		case PMV_MENU_SECSIZE:
-			if (vnds[manage_curdev].manual_geom && !vnds[manage_curdev].is_exist)
-				snprintf(buf, SSTRSIZE, "%d", vnds[manage_curdev].secsize);
-			wprintw(m->mw, "Bytes per Sector:     %18s", buf);
+			if (dev_ptr->manual_geom && !dev_ptr->is_exist)
+				snprintf(buf, SSTRSIZE, "%d", dev_ptr->secsize);
+			wprintw(m->mw, msg_string(MSG_vnd_bps_fmt), buf);
 			break;
 		case PMV_MENU_NSECTORS:
-			if (vnds[manage_curdev].manual_geom && !vnds[manage_curdev].is_exist)
-				snprintf(buf, SSTRSIZE, "%d", vnds[manage_curdev].nsectors);
-			wprintw(m->mw, "Sectors per Track:    %18s", buf);
+			if (dev_ptr->manual_geom && !dev_ptr->is_exist)
+				snprintf(buf, SSTRSIZE, "%d", dev_ptr->nsectors);
+			wprintw(m->mw, msg_string(MSG_vnd_spt_fmt), buf);
 			break;
 		case PMV_MENU_NTRACKS:
-			if (vnds[manage_curdev].manual_geom && !vnds[manage_curdev].is_exist)
-				snprintf(buf, SSTRSIZE, "%d", vnds[manage_curdev].ntracks);
-			wprintw(m->mw, "Tracks per Cylinder:  %18s", buf);
+			if (dev_ptr->manual_geom && !dev_ptr->is_exist)
+				snprintf(buf, SSTRSIZE, "%d", dev_ptr->ntracks);
+			wprintw(m->mw, msg_string(MSG_vnd_tpc_fmt), buf);
 			break;
 		case PMV_MENU_NCYLINDERS:
-			if (vnds[manage_curdev].manual_geom && !vnds[manage_curdev].is_exist)
-				snprintf(buf, SSTRSIZE, "%d", vnds[manage_curdev].ncylinders);
-			wprintw(m->mw, "Cylinders:        %22s", buf);
+			if (dev_ptr->manual_geom && !dev_ptr->is_exist)
+				snprintf(buf, SSTRSIZE, "%d", dev_ptr->ncylinders);
+			wprintw(m->mw, msg_string(MSG_vnd_cyl_fmt), buf);
 			break;
-
 	}
 	return;
 }
 
 static int
-partman_vnd_set_value(menudesc *m, void *arg)
+pm_vnd_set_value(menudesc *m, void *arg)
 {
-	char buf[SSTRSIZE];
+	vnds_t *dev_ptr = arg;
+	char buf[STRSIZE];
 	const char *msg_to_show = NULL;
 	int *out_var = NULL;
 	
 	switch (m->cursel) {
 		case PMV_MENU_FILEPATH:
-			msg_prompt_win("File path?", -1, 18, 0, 0, vnds[manage_curdev].filepath,
-				vnds[manage_curdev].filepath, STRSIZE);
+			msg_prompt_win(MSG_vnd_path_ask, -1, 18, 0, 0, dev_ptr->filepath,
+				dev_ptr->filepath, STRSIZE);
+			if (dev_ptr->filepath[0] != '/') {
+				strlcpy(buf, dev_ptr->filepath, MOUNTLEN);
+				snprintf(dev_ptr->filepath, MOUNTLEN, "/%s", buf);
+			}
+			if (dev_ptr->filepath[strlen(dev_ptr->filepath) - 1] == '/')
+				dev_ptr->filepath[strlen(dev_ptr->filepath) - 1] = '\0';
 			return 0;
 		case PMV_MENU_EXIST:
-			vnds[manage_curdev].is_exist = !vnds[manage_curdev].is_exist;
+			dev_ptr->is_exist = !dev_ptr->is_exist;
 			return 0;
 		case PMV_MENU_SIZE:
-			if (vnds[manage_curdev].is_exist)
+			if (dev_ptr->is_exist)
 				return 0;
-			msg_to_show = "Size (MB)";
-			out_var = &(vnds[manage_curdev].size);
+			msg_to_show = MSG_vnd_size_ask;
+			out_var = &(dev_ptr->size);
 			break;
 		case PMV_MENU_RO:
-			vnds[manage_curdev].readonly = !vnds[manage_curdev].readonly;
+			dev_ptr->readonly = !dev_ptr->readonly;
 			return 0;
 		case PMV_MENU_MGEOM:
-			if (vnds[manage_curdev].is_exist)
+			if (dev_ptr->is_exist)
 				return 0;
-			vnds[manage_curdev].manual_geom = !vnds[manage_curdev].manual_geom;
+			dev_ptr->manual_geom = !dev_ptr->manual_geom;
 			return 0;
 		case PMV_MENU_SECSIZE:
-			if (!vnds[manage_curdev].manual_geom || vnds[manage_curdev].is_exist)
+			if (!dev_ptr->manual_geom || dev_ptr->is_exist)
 				return 0;
-			msg_to_show = "Bytes per Sector";
-			out_var = &(vnds[manage_curdev].secsize);
+			msg_to_show = MSG_vnd_bps_ask;
+			out_var = &(dev_ptr->secsize);
 			break;
 		case PMV_MENU_NSECTORS:
-			if (!vnds[manage_curdev].manual_geom || vnds[manage_curdev].is_exist)
+			if (!dev_ptr->manual_geom || dev_ptr->is_exist)
 				return 0;
-			msg_to_show = "Sectors per Track";
-			out_var = &(vnds[manage_curdev].nsectors);
+			msg_to_show = MSG_vnd_spt_ask;
+			out_var = &(dev_ptr->nsectors);
 			break;
 		case PMV_MENU_NTRACKS:
-			if (!vnds[manage_curdev].manual_geom || vnds[manage_curdev].is_exist)
+			if (!dev_ptr->manual_geom || dev_ptr->is_exist)
 				return 0;
-			msg_to_show = "Tracks per Cylinder";
-			out_var = &(vnds[manage_curdev].ntracks);
+			msg_to_show = MSG_vnd_tpc_ask;
+			out_var = &(dev_ptr->ntracks);
 			break;
 		case PMV_MENU_NCYLINDERS:
-			if (!vnds[manage_curdev].manual_geom || vnds[manage_curdev].is_exist)
+			if (!dev_ptr->manual_geom || dev_ptr->is_exist)
 				return 0;
-			msg_to_show = "Cylinders";
-			out_var = &(vnds[manage_curdev].ncylinders);
+			msg_to_show = MSG_vnd_cyl_ask;
+			out_var = &(dev_ptr->ncylinders);
 			break;
 		case PMV_MENU_REMOVE:
-			vnds[manage_curdev].enabled = 0;
+			dev_ptr->enabled = 0;
 			return 0;
 	}
 	if (out_var == NULL || msg_to_show == NULL)
@@ -673,11 +845,13 @@ partman_vnd_set_value(menudesc *m, void *arg)
 }
 
 static void
-partman_vnd_new_init(void * none)
+pm_vnd_init(void *arg, void *none)
 {
-	memset(&(vnds[manage_curdev]), 0, sizeof vnds[manage_curdev]);
-	vnds[manage_curdev] = (struct vnds_t) {
+	vnds_t *dev_ptr = arg;
+	memset(dev_ptr, 0, sizeof(*dev_ptr));
+	*dev_ptr = (struct vnds_t) {
 		.enabled = 1,
+		.blocked = 0,
 		.filepath[0] = '\0',
 		.is_exist = 0,
 		.size = 1024,
@@ -692,159 +866,200 @@ partman_vnd_new_init(void * none)
 }
 
 static int
-partman_vnd_check(int dev_num)
+pm_vnd_check(void *arg)
 {
-	if (strlen(vnds[dev_num].filepath) < 1 ||
-			vnds[dev_num].size < 1)
-		vnds[dev_num].enabled = 0;
-	return vnds[dev_num].enabled;
+	vnds_t *dev_ptr = arg;
+
+	if (dev_ptr->blocked)
+		return 0;
+	if (strlen(dev_ptr->filepath) < 1 ||
+			dev_ptr->size < 1)
+		dev_ptr->enabled = 0;
+	else {
+		pm_manage_getfreenode(&(dev_ptr->node), "vnd", &vnds_t_info);
+		if (dev_ptr->node < 0)
+			dev_ptr->enabled = 0;
+	}
+	return dev_ptr->enabled;
 }
 
+/* XXX: vnconfig always return 0? */
 static int
-partman_vnd_edit(menudesc *m, void *arg)
+pm_vnd_commit(void)
 {
-	((part_entry_t *)arg)[0].retvalue = m->cursel + 1;
+	int i, ii, error, part_suit = -1;
+	char r_o[3], buf[MOUNTLEN+3], resultpath[STRSIZE]; 
+	pm_devs_t *pm_i, *pm_suit = NULL;
 
-	return partman_manage_edit(PMV_MENU_END, partman_vnd_edit_menufmt,
-		partman_vnd_set_value, partman_vnd_check, partman_vnd_new_init,
-		NULL, ((part_entry_t *)arg)[m->cursel].dev_num, MAX_VNDS,
-		sizeof vnds[0], &(vnds[0].enabled));
-}
-
-/* TODO: should use only unallocated devices */
-/* TODO: vnconfig always return 0? */
-static int
-partman_vnd_commit(void)
-{
-	int i, not_ok;
-	char r_o[3];
+	for (i = 0; i < MAX_VND; i++) {
+		error = 0;
+		if (! pm_vnd_check(&vnds[i]))
+			continue;
 
-	for (i = 0; i < MAX_VNDS; i++) {
-		not_ok = 0;
-		if (! partman_vnd_check(i))
+		/* Trying to assign target device */
+		SLIST_FOREACH(pm_i, &pm_head, l)
+			for (ii = 0; ii < 6; ii++) {
+				strcpy(buf, pm_i->bsdlabel[ii].pi_mount);
+				if (buf[strlen(buf)-1] != '/')
+					sprintf(buf,"%s/", buf);
+				printf("%s\n",buf);
+				if (strstr(vnds[i].filepath, buf) == vnds[i].filepath)
+					if (part_suit < 0 || pm_suit == NULL ||
+						strlen(buf) > strlen(pm_suit->bsdlabel[part_suit].pi_mount)) {
+						part_suit = ii;
+						pm_suit = pm_i;
+					}
+			}
+		if (part_suit < 0 || pm_suit == NULL || 
+			pm_suit->bsdlabel[part_suit].mnt_opts == NULL ||
+			! (pm_suit->bsdlabel[part_suit].pi_flags & PIF_MOUNT))
 			continue;
+		
+		/* Mounting assigned partition and try to get real file path*/
+		if (pm_mount(pm_suit, part_suit) != 0)
+			continue;
+		snprintf(resultpath, STRSIZE, "%s/%s",
+			pm_suit->bsdlabel[part_suit].mounted,
+			&(vnds[i].filepath[strlen(pm_suit->bsdlabel[part_suit].pi_mount)]));
+
 		strcpy(r_o, vnds[i].readonly?"-r":"");
 		/* If this is a new image */
-		if (!vnds[i].is_exist)
-			not_ok += run_program(RUN_DISPLAY,
+		if (!vnds[i].is_exist) {
+			run_program(RUN_DISPLAY | RUN_PROGRESS, "mkdir -p %s ", dirname(resultpath));
+			error += run_program(RUN_DISPLAY | RUN_PROGRESS,
 						"dd if=/dev/zero of=%s bs=1m count=%d progress=100 msgfmt=human",
-						target_expand(vnds[i].filepath), vnds[i].size);
-		if (not_ok)
+						resultpath, vnds[i].size);
+		}
+		if (error)
 			continue;
-
 		/* If this is a new image with manual geometry */
 		if (!vnds[i].is_exist && vnds[i].manual_geom)
-			not_ok += run_program(RUN_DISPLAY,
-						"vnconfig %s vnd%d %s %d %d %d %d", r_o, i,
-						target_expand(vnds[i].filepath), vnds[i].secsize,
-						vnds[i].nsectors, vnds[i].ntracks,	vnds[i].ncylinders);
+			error += run_program(RUN_DISPLAY | RUN_PROGRESS,
+						"vnconfig %s vnd%d %s %d %d %d %d", r_o, vnds[i].node,
+						resultpath, vnds[i].secsize, vnds[i].nsectors,
+						vnds[i].ntracks, vnds[i].ncylinders);
 		/* If this is a existent image or image without manual geometry */
 		else
-			not_ok += run_program(RUN_DISPLAY, "vnconfig %s vnd%d %s",
-						r_o, i, target_expand(vnds[i].filepath));
-
-		if (! not_ok)
-			vnds[i].enabled = 0;
+			error += run_program(RUN_DISPLAY | RUN_PROGRESS, "vnconfig %s vnd%d %s",
+						r_o, vnds[i].node, resultpath);
+
+		if (! error) {
+			vnds[i].blocked = 1;
+			vnds[i].pm_part = part_suit;
+			vnds[i].pm = pm_suit;
+			vnds[i].pm->blocked++;
+		}
 	}
 	return 0;
 }
 
-/*** CGD ***/
+/***
+CGD
+***/
 
 static void
-partman_cgd_menufmt(menudesc *m, int opt, void *arg)
+pm_cgd_menufmt(menudesc *m, int opt, void *arg)
 {
-	int num = ((part_entry_t *)arg)[opt].dev_num;
-
-	if (cgds[num].enabled != 0) {
-		if (cgds[num].pm == NULL)
-			wprintw(m->mw, "   DISK NOT DEFINED!");
-		else
-			wprintw(m->mw, "   %s%c (%s-%d)", cgds[num].pm->diskdev,
-				cgds[num].pm_part, cgds[num].enc_type, cgds[num].key_size);
+	cgds_t *dev_ptr = ((part_entry_t *)arg)[opt].dev_ptr;
+	char desc[STRSIZE];
+
+	if (dev_ptr->enabled == 0)
+		return;
+	if (dev_ptr->pm == NULL)
+		wprintw(m->mw, "%s", msg_string(MSG_cgd_err_menufmt));
+	else {
+		snprintf(desc, STRSIZE, "(%s-%d) on %s", dev_ptr->enc_type,
+			dev_ptr->key_size, dev_ptr->pm_name);
+		wprintw(m->mw, msg_string(MSG_cgd_menufmt), dev_ptr->node, desc,
+			dev_ptr->pm->bsdlabel[dev_ptr->pm_part].pi_size /
+							(MEG / dev_ptr->pm->sectorsize));
 	}
 	return;
 }
 
 static void
-partman_cgd_edit_menufmt(menudesc *m, int opt, void *arg)
+pm_cgd_edit_menufmt(menudesc *m, int opt, void *arg)
 {
-	switch (opt){
+	cgds_t *dev_ptr = arg;
+	switch (opt) {
 		case PMC_MENU_DEV:
-			wprintw(m->mw, "Base device:    %24s", cgds[manage_curdev].pm_name);
+			wprintw(m->mw, msg_string(MSG_cgd_dev_fmt), dev_ptr->pm_name);
 			break;
 		case PMC_MENU_ENCTYPE:
-			wprintw(m->mw, "Encyption:      %24s", cgds[manage_curdev].enc_type);
+			wprintw(m->mw, msg_string(MSG_cgd_enc_fmt), dev_ptr->enc_type);
 			break;
 		case PMC_MENU_KEYSIZE:
-			wprintw(m->mw, "Key size:       %24d", cgds[manage_curdev].key_size);
+			wprintw(m->mw, msg_string(MSG_cgd_key_fmt), dev_ptr->key_size);
 			break;
 		case PMC_MENU_IVTYPE:
-			wprintw(m->mw, "IV algorithm:   %24s", cgds[manage_curdev].iv_type);
+			wprintw(m->mw, msg_string(MSG_cgd_iv_fmt), dev_ptr->iv_type);
 			break;
 		case PMC_MENU_KEYGENTYPE:
-			wprintw(m->mw, "Key generation: %24s", cgds[manage_curdev].keygen_type);
+			wprintw(m->mw, msg_string(MSG_cgd_keygen_fmt), dev_ptr->keygen_type);
 			break;
 		case PMC_MENU_VERIFYTYPE:
-			wprintw(m->mw, "Verification method:   %17s", cgds[manage_curdev].verify_type);
+			wprintw(m->mw, msg_string(MSG_cgd_verif_fmt), dev_ptr->verify_type);
 			break;
 	}
 	return;
 }
 
 static int
-partman_cgd_set_value(menudesc *m, void *arg)
+pm_cgd_set_value(menudesc *m, void *arg)
 {
 	char *retstring;
+	cgds_t *dev_ptr = arg;
 
 	switch (m->cursel) {
 		case PMC_MENU_DEV:
-			partman_cgd_disk_set(NULL);
+			pm_cgd_disk_set(dev_ptr, NULL);
 			return 0;
 		case PMC_MENU_ENCTYPE:
 			process_menu(MENU_cgd_enctype, &retstring);
-			cgds[manage_curdev].enc_type = retstring;
+			dev_ptr->enc_type = retstring;
 			if (! strcmp(retstring, "blowfish-cbc"))
-				cgds[manage_curdev].key_size = 128;
+				dev_ptr->key_size = 128;
 			if (! strcmp(retstring, "3des-cbc"))
-				cgds[manage_curdev].key_size = 192;
+				dev_ptr->key_size = 192;
 			return 0;
 		case PMC_MENU_KEYSIZE:
-			if (! strcmp(cgds[manage_curdev].enc_type, "aes-cbc"))
-				cgds[manage_curdev].key_size +=
-					(cgds[manage_curdev].key_size < 256)? 64 : -128;
-			if (! strcmp(cgds[manage_curdev].enc_type, "blowfish-cbc"))
-				cgds[manage_curdev].key_size = 128;
-			if (! strcmp(cgds[manage_curdev].enc_type, "3des-cbc"))
-				cgds[manage_curdev].key_size = 192;
+			if (! strcmp(dev_ptr->enc_type, "aes-cbc"))
+				dev_ptr->key_size +=
+					(dev_ptr->key_size < 256)? 64 : -128;
+			if (! strcmp(dev_ptr->enc_type, "blowfish-cbc"))
+				dev_ptr->key_size = 128;
+			if (! strcmp(dev_ptr->enc_type, "3des-cbc"))
+				dev_ptr->key_size = 192;
 			return 0;
 		case PMC_MENU_IVTYPE:
 			process_menu(MENU_cgd_ivtype, &retstring);
-			cgds[manage_curdev].iv_type = retstring;
+			dev_ptr->iv_type = retstring;
 			return 0;
 		case PMC_MENU_KEYGENTYPE:
 			process_menu(MENU_cgd_keygentype, &retstring);
-			cgds[manage_curdev].keygen_type = retstring;
+			dev_ptr->keygen_type = retstring;
 			return 0;
 		case PMC_MENU_VERIFYTYPE:
 			process_menu(MENU_cgd_verifytype, &retstring);
-			cgds[manage_curdev].verify_type = retstring;
+			dev_ptr->verify_type = retstring;
 			return 0;
 		case PMC_MENU_REMOVE:
-			cgds[manage_curdev].enabled = 0;
+			dev_ptr->enabled = 0;
 			return 0;
 	}
 	return -1;
 }
 
 static void
-partman_cgd_new_init(void *assign_pm)
+pm_cgd_init(void *arg1, void *arg2)
 {
-	part_entry_t disk_entrie;
+	cgds_t *dev_ptr = arg1;
+	part_entry_t *disk_entrie = arg2;
 
-	memset(&(cgds[manage_curdev]), 0, sizeof cgds[manage_curdev]);
-	cgds[manage_curdev] = (struct cgds_t) {
+	memset(dev_ptr, 0, sizeof(*dev_ptr));
+	*dev_ptr = (struct cgds_t) {
 		.enabled = 1,
+		.blocked = 0,
 		.pm = NULL,
 		.pm_name[0] = '\0',
 		.pm_part = 0,
@@ -854,26 +1069,32 @@ partman_cgd_new_init(void *assign_pm)
 		.iv_type = "encblkno1",
 		.key_size = 192,
 	};
-	if (assign_pm != NULL) {
-			disk_entrie.dev_pm = assign_pm;
-			disk_entrie.dev_num = 'a' + PART_E;
-			snprintf(disk_entrie.fullname, SSTRSIZE, "%s%c",
-				pm->diskdev, 'a' + PART_E);
-		partman_cgd_disk_set(&disk_entrie);
+	if (disk_entrie != NULL) {
+		pm_getdevstring(disk_entrie->fullname, SSTRSIZE,
+			disk_entrie->dev_ptr, disk_entrie->dev_num);
+		pm_cgd_disk_set(dev_ptr, disk_entrie);
 	}
 	return;
 }
 
 static int
-partman_cgd_check(int dev_num)
+pm_cgd_check(void *arg)
 {
-	if (cgds[manage_curdev].pm == NULL)
-		cgds[manage_curdev].enabled = 0;
-	return cgds[manage_curdev].enabled;
+	cgds_t *dev_ptr = arg;
+
+	if (dev_ptr->blocked)
+		return 0;
+	if (dev_ptr->pm == NULL)
+		dev_ptr->enabled = 0;
+	else
+		pm_manage_getfreenode(&(dev_ptr->node), "cgd", &cgds_t_info);
+		if (dev_ptr->node < 0)
+			dev_ptr->enabled = 0;
+	return dev_ptr->enabled;
 }
 
 static int
-partman_cgd_disk_set(part_entry_t *disk_entrie)
+pm_cgd_disk_set(cgds_t *dev_ptr, part_entry_t *disk_entrie)
 {
 	int alloc_disk_entrie = 0;
 	if (disk_entrie == NULL) {
@@ -881,15 +1102,15 @@ partman_cgd_disk_set(part_entry_t *disk_entrie)
 		disk_entrie = malloc (sizeof(part_entry_t));
 		if (disk_entrie == NULL)
 			return -2;
-		*disk_entrie = partman_manage_getdev(FS_CGD);
+		*disk_entrie = pm_dev_list(PM_CGD_T);
 		if (disk_entrie->retvalue < 0) {
 			free(disk_entrie);
 			return -1;
 		}
 	}
-	cgds[manage_curdev].pm = disk_entrie->dev_pm;
-	cgds[manage_curdev].pm_part = disk_entrie->dev_num;
-	strncpy(cgds[manage_curdev].pm_name, disk_entrie->fullname, SSTRSIZE);
+	dev_ptr->pm = disk_entrie->dev_ptr;
+	dev_ptr->pm_part = disk_entrie->dev_num;
+	strlcpy(dev_ptr->pm_name, disk_entrie->fullname, SSTRSIZE);
 
 	if (alloc_disk_entrie)
 		free(disk_entrie);
@@ -897,466 +1118,1652 @@ partman_cgd_disk_set(part_entry_t *disk_entrie)
 }
 
 int
-partman_cgd_edit_adddisk(int cursel, pm_devs_t *assign_pm)
-{
-	if (assign_pm != NULL)
-		cursel = -1;
-	return partman_manage_edit(PMC_MENU_END, partman_cgd_edit_menufmt,
-		partman_cgd_set_value, partman_cgd_check, partman_cgd_new_init,
-		assign_pm, cursel, MAX_CGDS, sizeof cgds[0], &(cgds[0].enabled));
-}
-
-static int
-partman_cgd_edit(menudesc *m, void *arg)
+pm_cgd_edit(void *dev_ptr, part_entry_t *disk_entrie)
 {
-	((part_entry_t *)arg)[0].retvalue = m->cursel + 1;
-	return partman_cgd_edit_adddisk(((part_entry_t *)arg)[m->cursel].dev_num, NULL);
+	if (disk_entrie != NULL)
+		dev_ptr = NULL;
+	return pm_edit(PMC_MENU_END, pm_cgd_edit_menufmt,
+		pm_cgd_set_value, pm_cgd_check, pm_cgd_init,
+		disk_entrie, dev_ptr, 0, &cgds_t_info);
 }
 
-/* TODO: should use only unallocated devices */
 static int
-partman_cgd_commit(void)
+pm_cgd_commit(void)
 {
-	int i;
-	for (i = 0; i < MAX_CGDS; i++) {
-		if (! partman_cgd_check(i))
+	int i, error = 0;
+	for (i = 0; i < MAX_CGD; i++) {
+		if (! pm_cgd_check(&cgds[i]))
 			continue;
-		if (run_program(RUN_DISPLAY, "cgdconfig -g -i %s -k %s -o /tmp/%s %s %d",
-			cgds[i].iv_type, cgds[i].keygen_type, cgds[i].pm_name,
-			cgds[i].enc_type, cgds[i].key_size) != 0)
+		if (run_program(RUN_DISPLAY | RUN_PROGRESS,
+			"cgdconfig -g -i %s -k %s -o /tmp/cgd.%d.conf %s %d",
+			cgds[i].iv_type, cgds[i].keygen_type, cgds[i].node,
+			cgds[i].enc_type, cgds[i].key_size) != 0) {
+			error++;
 			continue;
-		if (run_program(RUN_DISPLAY, "cgdconfig -V re-enter cgd%d /dev/%s /tmp/%s",
-			i, cgds[i].pm_name, cgds[i].pm_name) != 0)
+		}
+		if (run_program(RUN_DISPLAY | RUN_PROGRESS,
+			"cgdconfig -V re-enter cgd%d /dev/%s /tmp/cgd.%d.conf",
+			cgds[i].node, cgds[i].pm_name, cgds[i].node) != 0) {
+			error++;
 			continue;
-		cgds[i].enabled = 0;
+		}
+		cgds[i].pm->blocked++;
+		cgds[i].blocked = 1;
 	}
-
-	return 0;
+	return error;
 }
 
-/*** LVM ***/
+/***
+LVM
+***/
 
+/* Add lvm logical volumes to pm list */
+/* XXX: rewrite */
 static int
-partman_lvm_edit(menudesc *m, void *arg)
+pm_lvm_find(void)
 {
-	((part_entry_t *)arg)[0].retvalue = m->cursel + 1;
+	int i, ii, already_found;
+	char dev[STRSIZE];
+	pm_devs_t *pm_i;
 
+	for (i = 0; i < MAX_LVM_VG; i++) {
+		if (! lvms[i].blocked)
+			continue;
+		for (ii = 0; ii < MAX_LVM_LV; ii++) {
+			if (! lvms[i].lv[ii].blocked || lvms[i].lv[ii].size < 1)
+				continue;
+			snprintf(dev, STRSIZE, "%s/%s", lvms[i].name, lvms[i].lv[ii].name);
+			already_found = 0;
+			SLIST_FOREACH(pm_i, &pm_head, l)
+				if (!already_found && strcmp(pm_i->diskdev, dev) == 0) {
+					pm_i->found = 1;
+					already_found = 1;
+				}
+			if (already_found)
+				/* We already added this device, skipping */
+				continue;
+			pm_new->found = 1;
+			pm_new->isspecial = 1;
+			pm_new->refdev = &lvms[i].lv[ii];
+			pm_new->sectorsize = 1;
+			pm_new->dlcylsize = MEG;
+			pm_new->bsdlabel[0].pi_size = MEG * lvms[i].lv[ii].size;
+			strlcpy(pm_new->diskdev, dev, SSTRSIZE);
+			strlcpy(pm_new->diskdev_descr, dev, STRSIZE);
+
+			if (SLIST_EMPTY(&pm_head))
+				 SLIST_INSERT_HEAD(&pm_head, pm_new, l);
+			else
+				 SLIST_INSERT_AFTER(pm_i, pm_new, l);
+			pm_new = malloc(sizeof (pm_devs_t));
+			memset(pm_new, 0, sizeof *pm_new);
+		}
+	}
 	return 0;
-//	return partman_manage_edit(PML_MENU_END, partman_lvm_edit_menufmt,
-//		partman_lvm_set_value,	partman_lvm_check, partman_lvm_new_init,
-//		NULL, ((part_entry_t *)arg)[m->cursel].dev_num, MAX_LVMS,
-//		sizeof lvms[0], &(lvms[0].enabled));
 }
 
-/*** Partman generic functions ***/
+static int
+pm_lvm_disk_add(menudesc *m, void *arg)
+{
+	int i;
+	lvms_t *dev_ptr = arg;
+	part_entry_t disk_entrie = pm_dev_list(PM_LVM_T);
+	if (disk_entrie.retvalue < 0)
+		return disk_entrie.retvalue;
+
+	for (i = 0; i < MAX_LVM_PV; i++)
+		if (dev_ptr->pv[i].pm == NULL) {
+			dev_ptr->pv[i].pm = disk_entrie.dev_ptr;
+			dev_ptr->pv[i].pm_part = disk_entrie.dev_num;
+			strlcpy(dev_ptr->pv[i].pm_name, disk_entrie.fullname, SSTRSIZE);
+			break;
+		}
+	return 0;
+}
 
-int
-partman_unconfigure(void)
+static int
+pm_lvm_disk_del(menudesc *m, void *arg)
 {
-	// TODO: rewrite
-	run_program(RUN_SILENT | RUN_ERROR_OK, "cgdconfig -u %s", pm->diskdev);
-	run_program(RUN_SILENT | RUN_ERROR_OK, "vnconfig -u %s", pm->diskdev);
-	run_program(RUN_SILENT | RUN_ERROR_OK, "raidctl -u %s", pm->diskdev);
-	run_program(RUN_SILENT | RUN_ERROR_OK, "umount /dev/%s*", pm->diskdev);
+	int i, retvalue = -1, num_devs = 0;
+	int menu_no;
+	lvms_t *dev_ptr = arg;
+	menu_ent menu_entries[MAX_LVM_PV];
+	part_entry_t submenu_args[MAX_LVM_PV];
+
+	for (i = 0; i < MAX_LVM_PV; i++) {
+		if (dev_ptr->pv[i].pm == NULL)
+			continue;
+		menu_entries[num_devs] = (struct menu_ent) {
+			.opt_name = dev_ptr->pv[i].pm_name,
+			.opt_action = set_menu_select,
+			.opt_menu = OPT_NOMENU,
+			.opt_flags = OPT_EXIT,
+		};
+		submenu_args[num_devs].dev_num = i;
+		num_devs++;
+	}
+
+	menu_no = new_menu(MSG_lvm_disks,
+		menu_entries, num_devs, -1, -1, (num_devs+1<3)?3:num_devs+1, 13,
+		MC_SCROLL | MC_NOCLEAR, NULL, NULL, NULL, NULL, NULL);
+	if (menu_no == -1)
+		return -1;
+	process_menu(menu_no, &retvalue);
+	free_menu(menu_no);
+
+	if (retvalue < 0 || retvalue >= num_devs)
+		return -1;
+
+	dev_ptr->pv[submenu_args[retvalue].dev_num].pm = NULL;
+
 	return 0;
 }
 
 static void
-partman_select(pm_devs_t *pm_devs_in)
+pm_lvm_menufmt(menudesc *m, int opt, void *arg)
 {
-	pm = pm_devs_in;
-	if (logfp)
-		(void)fprintf(logfp,"Partman device: %s\n", pm->diskdev);
+	int i, ok = 0, used_size = 0;
+	char buf1[STRSIZE]; buf1[0] = '\0';
+	char buf2[STRSIZE]; buf2[0] = '\0';
+	lvms_t *dev_ptr = ((part_entry_t *)arg)[opt].dev_ptr;
+
+	if (dev_ptr->enabled == 0)
+		return;
+	snprintf(buf1, STRSIZE, "VG '%s' on ", dev_ptr->name);
+	for (i = 0; i < MAX_LVM_PV; i++)
+		if (dev_ptr->pv[i].pm != NULL) {
+			strncat(buf1, dev_ptr->pv[i].pm_name, STRSIZE);
+			strncat(buf1, " ", STRSIZE);
+			ok = 1;
+		}
+	for (i = 0; i < MAX_LVM_LV; i++)
+		used_size += dev_ptr->lv[i].size;
+	if (ok) {
+		snprintf(buf2, STRSIZE, "%d/%u",
+			dev_ptr->total_size - used_size, dev_ptr->total_size);
+		wprintw(m->mw, msg_string(MSG_lvm_menufmt), buf1, buf2);
+	} else
+		wprintw(m->mw, "%s", msg_string(MSG_lvm_err_menufmt));
 	return;
-
 }
 
-static int
-partman_mountall_sort(const void *a, const void *b)
+static void
+pm_lvm_edit_menufmt(menudesc *m, int opt, void *arg)
 {
-	return strcmp(mnts[*(const int *)a].pi_mount,
-		      mnts[*(const int *)b].pi_mount);
+	int i;
+	char buf[STRSIZE];
+	lvms_t *dev_ptr = arg;
+	strlcpy(buf, msg_string(MSG_auto), STRSIZE);
+
+	switch (opt) {
+		case PML_MENU_PV:
+			buf[0] = '\0';
+			for (i = 0; i < MAX_LVM_PV; i++)
+				if (dev_ptr->pv[i].pm != NULL)
+					snprintf(buf, STRSIZE, "%s %s", buf, dev_ptr->pv[i].pm_name);
+			wprintw(m->mw, msg_string(MSG_lvm_disks_fmt), buf);
+			break;
+		case PML_MENU_NAME:
+			wprintw(m->mw, msg_string(MSG_lvm_name_fmt), dev_ptr->name);
+			break;
+		case PML_MENU_MAXLOGICALVOLUMES:
+			if (dev_ptr->maxlogicalvolumes > 0)
+				snprintf(buf, STRSIZE, "%d", dev_ptr->maxlogicalvolumes);
+			wprintw(m->mw, msg_string(MSG_lvm_maxlv_fmt), buf);
+			break;
+		case PML_MENU_MAXPHYSICALVOLUMES:
+			if (dev_ptr->maxphysicalvolumes > 0)
+				snprintf(buf, STRSIZE, "%d", dev_ptr->maxphysicalvolumes);
+			wprintw(m->mw, msg_string(MSG_lvm_maxpv_fmt), buf);
+			break;
+		case PML_MENU_PHYSICALEXTENTSIZE:
+			if (dev_ptr->physicalextentsize > 0)
+				snprintf(buf, STRSIZE, "%dM", dev_ptr->physicalextentsize);
+			wprintw(m->mw, msg_string(MSG_lvm_extsiz_fmt), buf);
+			break;
+	}
+	return;
 }
 
 static int
-partman_mountall(void)
+pm_lvm_set_value(menudesc *m, void *arg)
 {
-	pm_devs_t *pm_i;
-	int num_devs = 0;
-	int i, ii, error, ok;
-	char diskdev_with_root[SSTRSIZE];
-	diskdev_with_root[0] = '\0';
+	char buf[STRSIZE];
+	const char *msg_to_show = NULL;
+	int *out_var = NULL;
+	lvms_t *dev_ptr = arg;
 
-	int mnts_order[MNTS_MAX]; // TODO: rewrite
-	for (pm_i = pm_head->next, num_devs = 0; pm_i != NULL; pm_i = pm_i->next) {
-		ok = 0;
-		for (i = 0; i < MAXPARTITIONS; i++) {
-			if (pm_i->bsdlabel[i].pi_flags & PIF_MOUNT &&
-					pm_i->bsdlabel[i].mnt_opts != NULL) {
-				mnts[num_devs].pm_part  = i;
-				mnts[num_devs].diskdev  = pm_i->diskdev;
-				mnts[num_devs].mnt_opts = pm_i->bsdlabel[i].mnt_opts;
-				mnts[num_devs].fsname   = pm_i->bsdlabel[i].fsname;
-				mnts[num_devs].pi_mount = pm_i->bsdlabel[i].pi_mount;
-				if (strcmp(pm_i->bsdlabel[i].pi_mount, "/") == 0)
-					strlcpy(diskdev_with_root, pm_i->bsdlabel[i].pi_mount, 
-						sizeof diskdev_with_root);
-				num_devs++;
-				ok = 1;
-			}
-		}
-		if (ok)
-			md_pre_mount();
-	}
-	if (strlen(diskdev_with_root) == 0) {
-		msg_display("No root partition defined, cannot continue\n"); // TODO: localize
-		process_menu(MENU_ok, NULL);
-		return -1;
+	static menu_ent menuent_disk_adddel[] = {
+	    {MSG_add, OPT_NOMENU, OPT_EXIT, pm_lvm_disk_add}, 
+	    {MSG_remove, OPT_NOMENU, OPT_EXIT, pm_lvm_disk_del}
+	};
+	static int menu_disk_adddel = -1;
+	if (menu_disk_adddel == -1) {
+		menu_disk_adddel = new_menu(NULL, menuent_disk_adddel, nelem(menuent_disk_adddel),
+			-1, -1, 0, 10, MC_NOCLEAR, NULL, NULL, NULL, NULL, NULL);
 	}
-	for (i = 0; i < num_devs; i++)
-		mnts_order[i] = i;
-	qsort(mnts_order, num_devs, sizeof mnts_order[0], partman_mountall_sort);
 
-	for (i = 0; i < num_devs; i++) {
-		ii = mnts_order[i];
-		make_target_dir(mnts[ii].pi_mount);
-		error = target_mount(mnts[ii].mnt_opts, mnts[ii].diskdev, mnts[ii].pm_part, mnts[ii].pi_mount);
-		if (error) {
-			return error;
-		}
+	switch (m->cursel) {
+		case PML_MENU_PV:
+			process_menu(menu_disk_adddel, arg);
+			return 0;
+		case PML_MENU_NAME:
+			msg_prompt_win(MSG_lvm_name_ask, -1, 18, 0, 0, dev_ptr->name, dev_ptr->name, SSTRSIZE);
+			return 0;
+		case PML_MENU_MAXLOGICALVOLUMES:
+			msg_to_show = MSG_lvm_maxlv_ask;
+			out_var = &(dev_ptr->maxlogicalvolumes);			
+			break;
+		case PML_MENU_MAXPHYSICALVOLUMES:
+			msg_to_show = MSG_lvm_maxpv_ask;
+			out_var = &(dev_ptr->maxphysicalvolumes);
+			break;
+		case PML_MENU_PHYSICALEXTENTSIZE:
+			msg_to_show = MSG_lvm_extsiz_ask;
+			out_var = &(dev_ptr->physicalextentsize);
+			break;
+		case PML_MENU_REMOVE:
+			dev_ptr->enabled = 0;
+			return 0;
 	}
-	/* Use disk with / as a default if the user has the sets on a local disk */
-	strlcpy(localfs_dev, diskdev_with_root, sizeof localfs_dev);
+	if (out_var == NULL || msg_to_show == NULL)
+		return -1;
+	snprintf(buf, SSTRSIZE, "%d", *out_var);
+	msg_prompt_win(msg_to_show, -1, 18, 0, 0, buf, buf, SSTRSIZE);
+	if (atoi(buf) >= 0)
+		*out_var = atoi(buf);
 	return 0;
 }
 
 static void
-partman_mountmenu_menufmt(menudesc *m, int opt, void *arg)
+pm_lvm_init(void *arg, void* none)
 {
-	int num = ((part_entry_t *)arg)[opt].dev_num;
-
-	if (pm->bsdlabel[num].pi_flags & PIF_MOUNT && pm->bsdlabel[num].mnt_opts != NULL)
-		wprintw(m->mw, "%s%c at %s", pm->diskdev, 'a' + num, pm->bsdlabel[num].pi_mount);
+	lvms_t *dev_ptr = arg;
 
+	memset(dev_ptr, 0, sizeof *dev_ptr);
+	*dev_ptr = (struct lvms_t) {
+		.enabled = 1,
+		.blocked = 0,
+		.maxlogicalvolumes = MAX_LVM_PV,
+		.maxphysicalvolumes = MAX_LVM_LV,
+		.physicalextentsize = -1,
+	};
+	sprintf(dev_ptr->name, "vg%.2d", rand()%100);
 	return;
 }
 
 static int
-partman_mount(menudesc *m, void *arg)
+pm_lvm_check(void *arg)
 {
-	int num = ((part_entry_t *)arg)[m->cursel].dev_num;
+	int i, ok = 0;
+	lvms_t *dev_ptr = arg;
+	dev_ptr->total_size = 0;
 
-	if (pm->bsdlabel[num].pi_flags & PIF_MOUNT && pm->bsdlabel[num].mnt_opts != NULL)
-		return target_mount(pm->bsdlabel[num].mnt_opts, pm->diskdev, num,
-					pm->bsdlabel[num].pi_mount);
-	return -1;
+	for (i = 0; i < MAX_LVM_PV; i++)
+		if (dev_ptr->pv[i].pm != NULL) {
+			ok = 1;
+			dev_ptr->total_size += dev_ptr->pv[i].pm->
+						bsdlabel[dev_ptr->pv[i].pm_part].pi_size /
+						(MEG / dev_ptr->pv[i].pm->sectorsize);
+		}
+	if (! ok)
+		dev_ptr->enabled = 0;
+	return dev_ptr->enabled;
 }
 
-int // TODO: eeee
-partman_mountmenu(void)
+static void
+pm_lvmlv_menufmt(menudesc *m, int opt, void *arg)
 {
-	int i, num_devs = 0;
-	int menu_no;
-	menu_ent menu_entries[MAXPARTITIONS];
-	part_entry_t args[MAXPARTITIONS];
-
-	for (i = 0; i < MAXPARTITIONS; i++) {
-		if (pm->bsdlabel[i].pi_flags & PIF_MOUNT &&
-				pm->bsdlabel[i].mnt_opts != NULL) {
-			menu_entries[num_devs] = (menu_ent) {
-				.opt_name = NULL,
-				.opt_action = partman_mount,
-				.opt_menu = OPT_NOMENU,
-				.opt_flags = OPT_EXIT,
-			};
-			args[num_devs].dev_num = i;
-			num_devs++;
-		}
+	char buf[STRSIZE];
+	lv_t *dev_ptr = ((part_entry_t *)arg)[opt].dev_ptr;
+
+	if (dev_ptr->size > 0) {
+		snprintf(buf, STRSIZE, "'%s'", dev_ptr->name);
+		wprintw(m->mw, msg_string(MSG_lvmlv_menufmt), buf, dev_ptr->size);
 	}
-	menu_no = new_menu(NULL, menu_entries, num_devs, 50, 5, num_devs+3, 0,
-		MC_ALWAYS_SCROLL | MC_NOCLEAR, NULL, partman_mountmenu_menufmt,
-		NULL, NULL, NULL);
-	if (menu_no == -1)
-		return -1;
-	process_menu(menu_no, &args);
-	free_menu(menu_no);
-	return 0;
+	return;
 }
 
-int
-partman_shred(char *dev, int shredtype)
+static void
+pm_lvmlv_edit_menufmt(menudesc *m, int opt, void *arg)
 {
-	int error = 0;
-	switch(shredtype) {
-		case SHRED_NONE:
-			return 0;
-		case SHRED_ZEROS:
-			error += run_program(RUN_DISPLAY | RUN_PROGRESS,
-				"dd of=/dev/r%sd if=/dev/zero bs=1m progress=100 msgfmt=human", dev);
-			return error; 
-		case SHRED_RANDOM:
-			error += run_program(RUN_DISPLAY | RUN_PROGRESS,
-				"dd of=/dev/r%sd if=/dev/urandom bs=1m progress=100 msgfmt=human", dev);
-			return error;
-		case SHRED_CRYPTO:
-			error += run_program(RUN_DISPLAY | RUN_PROGRESS,
-				"sh -c 'cgdconfig -s cgd0 /dev/%sd aes-cbc 128 < /dev/urandom'",
-				dev);
-			if (! error) {
-				error += run_program(RUN_DISPLAY | RUN_PROGRESS,
-					"dd of=/dev/rcgd0d if=/dev/urandom bs=1m progress=100 msgfmt=human");
-				error += run_program(RUN_DISPLAY | RUN_PROGRESS,
-					"cgdconfig -u cgd0");
-			}
-			return error;
-	}
-	return -1;
-}
+
+	lv_t *dev_ptr = arg;
+	char buf[STRSIZE];
+	strlcpy(buf, msg_string(MSG_auto), STRSIZE);
+
+	switch (opt) {
+		case PMLV_MENU_NAME:
+			wprintw(m->mw, msg_string(MSG_lvmlv_name_fmt), dev_ptr->name);
+			break;
+		case PMLV_MENU_SIZE:
+			wprintw(m->mw, msg_string(MSG_lvmlv_size_fmt), dev_ptr->size);
+			break;
+		case PMLV_MENU_READONLY:
+			wprintw(m->mw, msg_string(MSG_lvmlv_ro_fmt),
+				dev_ptr->readonly? msg_string(MSG_Yes) : msg_string(MSG_No));
+			break;
+		case PMLV_MENU_CONTIGUOUS:
+			wprintw(m->mw, msg_string(MSG_lvmlv_cont_fmt),
+				dev_ptr->contiguous? msg_string(MSG_Yes) : msg_string(MSG_No));
+			break;
+		case PMLV_MENU_EXTENTS:
+			wprintw(m->mw, msg_string(MSG_lvmlv_extnum_fmt),
+				(strlen(dev_ptr->extents) > 0)? dev_ptr->extents : msg_string(MSG_auto));
+			break;
+		case PMLV_MENU_MINOR:
+			if (dev_ptr->minor > 0)
+				snprintf(buf, STRSIZE, "%dK", dev_ptr->minor);
+			wprintw(m->mw, msg_string(MSG_lvmlv_minor_fmt), buf);
+			break;
+		case PMLV_MENU_MIRRORS:
+			wprintw(m->mw, msg_string(MSG_lvmlv_mirrors_fmt), dev_ptr->mirrors);
+			break;
+		case PMLV_MENU_REGIONSIZE:
+			if (dev_ptr->regionsize > 0)
+				snprintf(buf, STRSIZE, "%dM", dev_ptr->regionsize);
+			wprintw(m->mw, msg_string(MSG_lvmlv_regsiz_fmt), buf);
+			break;
+		case PMLV_MENU_PERSISTENT:
+			wprintw(m->mw, msg_string(MSG_lvmlv_pers_fmt),
+				dev_ptr->persistent ? msg_string(MSG_Yes) : msg_string(MSG_No));
+			break;
+		case PMLV_MENU_READAHEAD:
+			if (dev_ptr->readahead > 0)
+				snprintf(buf, STRSIZE, "%d", dev_ptr->readahead);
+			wprintw(m->mw, msg_string(MSG_lvmlv_readahsect_fmt), buf);
+			break;
+		case PMLV_MENU_STRIPES:
+			if (dev_ptr->stripes > 0)
+				snprintf(buf, STRSIZE, "%d", dev_ptr->stripes);
+			wprintw(m->mw, msg_string(MSG_lvmlv_stripes_fmt), buf);
+			break;
+		case PMLV_MENU_STRIPESIZE:
+			if (dev_ptr->stripesize > 0)
+				snprintf(buf, STRSIZE, "%dK", dev_ptr->stripesize);
+			wprintw(m->mw, msg_string(MSG_lvmlv_stripesiz_fmt), buf);
+			break;
+		case PMLV_MENU_ZERO:
+			wprintw(m->mw, msg_string(MSG_lvmlv_zero_fmt),
+				dev_ptr->zero? msg_string(MSG_Yes) : msg_string(MSG_No));
+			break;
+	}
+	return;
+}
 
 static int
-partman_commit(menudesc *m, void *arg)
+pm_lvmlv_set_value(menudesc *m, void *arg)
+{
+	char buf[STRSIZE];
+	const char *msg_to_show = NULL;
+	int *out_var = NULL;
+	lv_t *dev_ptr = arg;
+
+	switch (m->cursel) {
+		case PMLV_MENU_NAME:
+			msg_prompt_win(MSG_lvmlv_name_ask, -1, 18, 0, 0, dev_ptr->name, dev_ptr->name,
+				SSTRSIZE);
+			return 0;
+		case PMLV_MENU_SIZE:
+			msg_to_show = MSG_lvmlv_size_ask;
+			out_var = &(dev_ptr->size);
+			break;
+		case PMLV_MENU_READONLY:
+			dev_ptr->readonly = !dev_ptr->readonly;
+			return 0;
+		case PMLV_MENU_CONTIGUOUS:
+			dev_ptr->contiguous = !dev_ptr->contiguous;
+			return 0;
+		case PMLV_MENU_EXTENTS:
+			msg_prompt_win(MSG_lvmlv_extnum_ask, -1, 18, 0, 0,
+				dev_ptr->extents, dev_ptr->extents, SSTRSIZE);
+			return 0;
+		case PMLV_MENU_MINOR:
+			msg_to_show = MSG_lvmlv_minor_ask;
+			out_var = &(dev_ptr->minor);
+			break;
+		case PMLV_MENU_MIRRORS:
+			msg_to_show = MSG_lvmlv_mirrors_ask;
+			out_var = &(dev_ptr->mirrors);
+			break;
+		case PMLV_MENU_REGIONSIZE:
+			msg_to_show = MSG_lvmlv_regsiz_ask;
+			out_var = &(dev_ptr->regionsize);
+			break;
+		case PMLV_MENU_PERSISTENT:
+			dev_ptr->persistent = !dev_ptr->persistent;
+			return 0;
+		case PMLV_MENU_READAHEAD:
+			msg_to_show = MSG_lvmlv_readahsect_ask;
+			out_var = &(dev_ptr->readahead);
+			break;
+		case PMLV_MENU_STRIPES:
+			msg_to_show = MSG_lvmlv_stripes_ask;
+			out_var = &(dev_ptr->stripes);
+			break;
+		case PMLV_MENU_STRIPESIZE:
+			if (dev_ptr->stripesize << 1 > 512)
+				dev_ptr->stripesize = 4;	
+			else
+				dev_ptr->stripesize <<= 1;
+			return 0;
+		case PMLV_MENU_ZERO:
+			dev_ptr->zero = !dev_ptr->zero;
+			return 0;
+		case PMLV_MENU_REMOVE:
+			dev_ptr->size = 0;
+			return 0;
+	}
+	if (out_var == NULL || msg_to_show == NULL)
+		return -1;
+	snprintf(buf, SSTRSIZE, "%d", *out_var);
+	msg_prompt_win(msg_to_show, -1, 18, 0, 0, buf, buf, SSTRSIZE);
+	if (atoi(buf) >= 0)
+		*out_var = atoi(buf);
+	return 0;
+}
+
+static void
+pm_lvmlv_init(void *arg, void *none)
+{
+	lv_t *dev_ptr = arg;
+	memset(dev_ptr, 0, sizeof *(dev_ptr));
+	*dev_ptr = (struct lv_t) {
+		.blocked = 0,
+		.size = 1024,
+		.stripesize = 64,
+	};
+	sprintf (dev_ptr->name, "lvol%.2d", rand()%100);
+	return;
+}
+
+static int
+pm_lvmlv_check(void *arg)
+{
+	lv_t *dev_ptr = arg;
+	if (dev_ptr->size > 0 && strlen(dev_ptr->name) > 0)
+		return 1;
+	else {
+		dev_ptr->size = 0;
+		return 0;
+	}
+}
+
+static int
+pm_lvm_commit(void)
+{
+	int i, ii, error;
+	uint used_size = 0;
+	char params[STRSIZE*3];
+	char devs[STRSIZE*3];
+
+	for (i = 0; i < MAX_LVM_VG; i++) {
+		/* Stage 0: checks */
+		if (! pm_lvm_check(&lvms[i]))
+			continue;
+		for (ii = 0; ii < MAX_LVM_LV; ii++)
+			used_size += lvms[i].lv[ii].size;
+		if (used_size > lvms[i].total_size)
+			continue;
+
+		params[0] = '\0';
+		devs[0] = '\0';
+		error = 0;
+		/* Stage 1: creating Physical Volumes (PV's) */
+		for (ii = 0; ii < MAX_LVM_PV && ! error; ii++)
+			if (lvms[i].pv[ii].pm != NULL) {
+				run_program(RUN_SILENT | RUN_ERROR_OK, 
+										"lvm pvremove -ffy /dev/r%s",
+										(char*)lvms[i].pv[ii].pm_name);
+				error += run_program(RUN_DISPLAY | RUN_PROGRESS,
+										"lvm pvcreate -ffy /dev/r%s",
+										(char*)lvms[i].pv[ii].pm_name);
+				if (error)
+					break;
+				snprintf(devs, STRSIZE*3, "%s /dev/r%s", devs, (char*)lvms[i].pv[ii].pm_name);
+			}
+		if (error)
+			continue;
+		/* Stage 2: creating Volume Groups (VG's) */
+		if (lvms[i].maxlogicalvolumes > 0)
+			snprintf(params, STRSIZE*3, "%s -l %d", params, lvms[i].maxlogicalvolumes);
+		if (lvms[i].maxphysicalvolumes > 0)
+			snprintf(params, STRSIZE*3, "%s -p %d", params, lvms[i].maxphysicalvolumes);
+		if (lvms[i].physicalextentsize > 0)
+			snprintf(params, STRSIZE*3, "%s -s %d", params, lvms[i].physicalextentsize);
+		error += run_program(RUN_DISPLAY | RUN_PROGRESS, "lvm vgcreate %s %s %s",
+							params, lvms[i].name, devs);
+		if (error)
+			continue;
+		/* Stage 3: creating Logical Volumes (LV's) */
+		for (ii = 0; ii < MAX_LVM_LV; ii++) {
+			if (lvms[i].lv[ii].size <= 0)
+				continue;
+
+			params[0] = '\0';
+			snprintf(params, STRSIZE*3, "%s -C %c", params, lvms[i].lv[ii].contiguous?'y':'n');
+			snprintf(params, STRSIZE*3, "%s -M %c", params, lvms[i].lv[ii].persistent?'y':'n');
+			snprintf(params, STRSIZE*3, "%s -p %s", params, lvms[i].lv[ii].readonly?"r":"rw");
+			snprintf(params, STRSIZE*3, "%s -Z %c", params, lvms[i].lv[ii].zero?'y':'n');
+			if (strlen(lvms[i].lv[ii].name) > 0)
+				snprintf(params, STRSIZE*3, "%s -n %s", params, lvms[i].lv[ii].name);
+			if (strlen(lvms[i].lv[ii].extents) > 0)
+				snprintf(params, STRSIZE*3, "%s -l %s", params, lvms[i].lv[ii].extents);
+			if (lvms[i].lv[ii].minor > 0)
+				snprintf(params, STRSIZE*3, "%s --minor %d", params, lvms[i].lv[ii].minor);
+			if (lvms[i].lv[ii].mirrors > 0) {
+				snprintf(params, STRSIZE*3, "%s -m %d", params, lvms[i].lv[ii].mirrors);
+				if (lvms[i].lv[ii].regionsize > 0)
+					snprintf(params, STRSIZE*3, "%s -R %d", params, lvms[i].lv[ii].regionsize);
+			}
+			if (lvms[i].lv[ii].readahead > 0)
+				snprintf(params, STRSIZE*3, "%s -r %d", params, lvms[i].lv[ii].readahead);
+			if (lvms[i].lv[ii].stripes > 0) {
+				snprintf(params, STRSIZE*3, "%s -i %d", params, lvms[i].lv[ii].stripes);
+				if (lvms[i].lv[ii].stripesize > 0)
+					snprintf(params, STRSIZE*3, "%s -I %d", params, lvms[i].lv[ii].stripesize);
+			}
+			snprintf(params, STRSIZE*3, "%s -L %uM", params, lvms[i].lv[ii].size);
+			error += run_program(RUN_DISPLAY | RUN_PROGRESS, "lvm lvcreate %s %s",
+									params, lvms[i].name);
+		}
+		if (! error) {
+			lvms[i].blocked = 1;
+			for (ii = 0; ii < MAX_LVM_PV; ii++)
+				if (lvms[i].pv[ii].pm != NULL)
+					lvms[i].pv[ii].pm->blocked++;
+			for (ii = 0; ii < MAX_LVM_LV; ii++)
+				if (lvms[i].lv[ii].size > 0)
+					lvms[i].lv[ii].blocked = 1;
+		}
+	}
+
+	return 0;
+}
+
+/***
+GPT
+***/
+
+int
+pm_gpt_convert(pm_devs_t *pm_cur)
+{
+	int i, error = 0;
+
+	msg_display(MSG_removepartswarn);
+	process_menu(MENU_noyes, NULL);
+	if (! yesno)
+		return -1;
+
+	if (! pm_cur->gpt)
+		error = run_program(RUN_DISPLAY | RUN_PROGRESS, "gpt create -f %s", 
+				pm_cur->diskdev);
+	else {
+		error = run_program(RUN_DISPLAY | RUN_PROGRESS, "gpt destroy %s", 
+				pm_cur->diskdev);
+		for (i = 0; i < MAX_WEDGES; i++)
+			if (wedges[i].pm == pm_cur)
+				wedges[i].pm = NULL;
+	}
+	if (!error) {
+		pm_cur->gpt = !pm_cur->gpt;
+		pm_select(pm_cur);
+		label_read();
+	}
+	return error;
+}
+
+static int
+pm_wedge_getfree(void)
+{
+	int i;
+	for (i = 0; i < MAX_WEDGES; i++)
+		if (! wedges[i].allocated && wedges[i].pm == NULL)
+			return i;
+	return -1;
+}
+
+void
+pm_wedges_fill(pm_devs_t *pm_cur)
+{
+	int i, current;
+
+	for (i = 0; i < MAX_WEDGES; i++)
+		if (wedges[i].pm == pm_cur)
+			wedges[i].pm = NULL;
+
+	for (i = 0; i < MAXPARTITIONS && i < MAX_WEDGES; i++)
+		if (pm_cur->bsdlabel[i].pi_fstype != FS_UNUSED) {
+			current = pm_wedge_getfree();
+			if (current < 0) {
+				process_menu(MENU_ok, deconst(MSG_limitcount));
+				return;
+			}
+			wedges[current].pm = pm_cur;
+			wedges[current].ptn = i;
+		}
+	return;
+}
+
+static int
+pm_wedge_create(int num, pm_devs_t **pm_dk)
+{
+	int i, ii, hackerr, error;
+	partinfo *p = &(wedges[num].pm->bsdlabel[wedges[num].ptn]);
+
+	if (num > MAX_WEDGES)
+		return -1;
+
+	/* There is no ability to use requied dkX device, so that's hack */
+	for (i = 0; i < num; i++)
+		if (! wedges[i].allocated) {
+			hackerr = 1;
+			for (ii = 0; hackerr && ii < 3; ii++)
+				hackerr = run_program(RUN_SILENT | RUN_ERROR_OK,
+					"dkctl %s addwedge HACK%d %d %d unused",
+					wedges[num].pm->diskdev,
+					rand()%33, rand()%33, 0);
+			wedges[i].todel = 1;
+		}
+	
+	run_program(RUN_SILENT | RUN_ERROR_OK,
+					"dkctl %s listwedges", wedges[num].pm->diskdev);
+
+	error = run_program(RUN_DISPLAY | RUN_PROGRESS,
+			"dkctl %s addwedge dk%d %u %u %s",
+			wedges[num].pm->diskdev,
+			num,
+			p->pi_offset,
+			p->pi_size,
+			getfstypename(p->pi_fstype));
+	if (!error) {
+		wedges[num].allocated = 1;
+		wedges[num].pm->blocked++;
+		if (pm_dk != NULL) {
+			*pm_dk = malloc(sizeof(pm_devs_t));
+			memset(*pm_dk, 0, sizeof **pm_dk);
+			memcpy(&(*pm_dk)->bsdlabel[0], p, sizeof (*pm_dk)->bsdlabel[0]);
+			(*pm_dk)->found = -1;
+			(*pm_dk)->isspecial = 1;
+			(*pm_dk)->sectorsize = 512; /* XXX: xxx */
+			(*pm_dk)->dlcylsize = MEG;
+			(*pm_dk)->refdev = wedges[num].pm;
+			snprintf((*pm_dk)->diskdev, SSTRSIZE, "dk%d", num);
+			snprintf((*pm_dk)->diskdev_descr, STRSIZE, "   %s (%s)",
+				(*pm_dk)->diskdev, getfstypename(p->pi_fstype));
+		}
+	} else
+		if (logfp)
+			fprintf(logfp, "Cannot create wedge dk%d for %s.\n",
+				num, wedges[num].pm->diskdev);
+
+	/* Hack, see above */
+	for (i = 0; i < num; i ++)
+		if (! wedges[i].allocated && wedges[i].todel) {
+			hackerr = run_program(RUN_SILENT | RUN_ERROR_OK,
+				"dkctl %s delwedge dk%d", wedges[num].pm->diskdev, i);
+			wedges[i].todel = 0;
+		}
+
+	return error;
+}
+
+static int
+pm_gpt_commit(void)
+{
+	uint i, error;
+	pm_devs_t *pm_i, *pm_dk = NULL;
+	char fstype[STRSIZE]; fstype[0] = '\0';
+	partinfo *p;
+
+	SLIST_FOREACH(pm_i, &pm_head, l)
+		if (pm_i->gpt && pm_i->unsaved)
+			run_program(RUN_DISPLAY | RUN_PROGRESS,
+				"gpt remove -a %s",
+				pm_i->diskdev);
+
+	for (i = 0; i < MAX_WEDGES; i++) {
+		if (wedges[i].pm == NULL ||
+			! wedges[i].pm->unsaved ||
+			wedges[i].ptn < 0)
+			continue;
+		error = 0;
+		p = &(wedges[i].pm->bsdlabel[wedges[i].ptn]);
+		if (wedges[i].pm->gpt) {
+			if (get_gptfs_by_id(p->pi_fstype) != NULL)
+				snprintf(fstype, STRSIZE, "-t %s", get_gptfs_by_id(p->pi_fstype));
+			error += run_program(RUN_DISPLAY | RUN_PROGRESS,
+				"gpt add -i %u -b %u -s %u %s %s",
+				wedges[i].ptn + 1,
+				p->pi_offset, p->pi_size,
+				fstype, wedges[i].pm->diskdev);
+		}
+		
+		if (error || wedges[i].allocated) {
+			if (logfp && error)
+				fprintf(logfp, "Cannot create GPT partition #%d on %s\n",
+					i, wedges[i].pm->diskdev);
+			continue;
+		}
+
+		error += pm_wedge_create(i, &pm_dk);
+		if (pm_dk != NULL) {
+			/* Create filesystem on wedge and add it to list */
+			pm_select(pm_dk);
+			make_filesystems();
+			SLIST_INSERT_AFTER(wedges[i].pm, pm_dk, l);
+			memset(p, 0, sizeof *p);
+			if (error)
+				return -1;
+		}
+	}
+
+	SLIST_FOREACH(pm_i, &pm_head, l)
+		if (pm_i->gpt && pm_i->unsaved)
+			pm_i->unsaved = 0;
+
+	return 0;
+}
+
+/***
+Partman generic functions 
+***/
+
+int
+pm_getrefdev(pm_devs_t *pm_cur)
+{
+	int i, ii, dev_num, num_devs, num_devs_s;
+	char dev[SSTRSIZE]; dev[0] = '\0';
+
+	pm_cur->refdev = NULL;
+	if (! strncmp(pm_cur->diskdev, "cgd", 3)) {
+		dev_num = pm_cur->diskdev[3] - '0';
+		for (i = 0; i < MAX_CGD; i++)
+			if (cgds[i].blocked && cgds[i].node == dev_num) {
+				pm_cur->refdev = &cgds[i];
+
+				snprintf(pm_cur->diskdev_descr, STRSIZE, "%s (%s, %s-%d)",
+					pm_cur->diskdev_descr, cgds[i].pm_name,
+					cgds[i].enc_type, cgds[i].key_size);
+				break;
+			}
+ 	} else if (! strncmp(pm_cur->diskdev, "vnd", 3)) {
+ 		dev_num = pm_cur->diskdev[3] - '0';
+ 		for (i = 0; i < MAX_VND; i++)
+			if (vnds[i].blocked && vnds[i].node == dev_num) {
+				pm_cur->refdev = &vnds[i];
+				pm_getdevstring(dev, SSTRSIZE, vnds[i].pm, vnds[i].pm_part);
+				snprintf(pm_cur->diskdev_descr, STRSIZE, "%s (%s, %s)",
+					pm_cur->diskdev_descr, dev, vnds[i].filepath);
+				break;
+			}
+	} else if (! strncmp(pm_cur->diskdev, "raid", 4)) {
+		dev_num = pm_cur->diskdev[4] - '0';
+ 		for (i = 0; i < MAX_RAID; i++)
+			if (raids[i].blocked && raids[i].node == dev_num) {
+				pm_cur->refdev = &raids[i];
+				num_devs = 0; num_devs_s = 0;
+				for (ii = 0; ii < MAX_IN_RAID; ii++)
+					if (raids[i].pm[ii] != NULL) {
+						if(raids[i].pm_is_spare[ii])
+							num_devs_s++;
+						else
+							num_devs++;
+					}
+				snprintf(pm_cur->diskdev_descr, STRSIZE,
+					"%s (lvl %d, %d disks, %d spare)", pm_cur->diskdev_descr,
+					raids[i].raid_level, num_devs, num_devs_s);
+				break;
+			}
+	} else
+		return -1;
+	return 0;
+}
+
+/* Detect that partition is in use */
+int
+pm_partusage(pm_devs_t *pm_cur, int part_num, int do_del)
+{
+	int i, ii, retvalue = 0;
+
+	if (part_num < 0) {
+		/* Check all partitions on device */
+		for (i = 0; i < MAXPARTITIONS; i++)
+			retvalue += pm_partusage(pm_cur, i, do_del);
+		return retvalue;
+	}
+
+	for (i = 0; i < MAX_CGD; i++)
+		if (cgds[i].enabled &&
+			cgds[i].pm == pm_cur &&
+			cgds[i].pm_part == part_num) {
+			if (do_del) {
+				cgds[i].pm = NULL;
+				strcpy(cgds[i].pm_name, "");
+			}
+			return 1;
+		}
+	for (i = 0; i < MAX_RAID; i++)
+		for (ii = 0; ii < MAX_IN_RAID; ii++)
+			if (raids[i].enabled &&
+				raids[i].pm[ii] == pm_cur &&
+				raids[i].pm_part[ii] == part_num) {
+					if (do_del)
+						raids[i].pm[ii] = NULL;
+					return 1;
+			}
+	for (i = 0; i < MAX_LVM_VG; i++)
+		for (ii = 0; ii < MAX_LVM_PV; ii++)
+			if (lvms[i].enabled &&
+				lvms[i].pv[ii].pm == pm_cur &&
+				lvms[i].pv[ii].pm_part == part_num) {
+					if (do_del)
+						lvms[i].pv[ii].pm = NULL;
+					return 1;
+			}
+
+	return 0;
+}
+
+/* Cleanup removed devices */
+static int
+pm_clean(void)
+{
+	int count = 0;
+	pm_devs_t *pm_i;
+
+	SLIST_FOREACH(pm_i, &pm_head, l)
+		if (! pm_i->found) {
+			count++;
+			SLIST_REMOVE(&pm_head, pm_i, pm_devs_t, l);
+			free(pm_i);
+		}
+	return count;
+}
+
+void 
+pm_make_bsd_partitions(pm_devs_t *pm_cur)
+{
+	int i;
+	partinfo baklabel[MAXPARTITIONS];
+	memcpy(baklabel, &pm_cur->bsdlabel, sizeof baklabel);
+
+	pm_cur->unsaved = 1;
+	layoutkind = LY_SETNEW;
+	md_make_bsd_partitions();
+	pm_cur->bootable = (pm_cur->bsdlabel[pm_cur->rootpart].pi_flags & PIF_MOUNT) ?
+		1 : 0;
+	for (i = 0; i < MAXPARTITIONS; i++)
+		if (pm_cur->bsdlabel[i].pi_fstype != baklabel[i].pi_fstype ||
+				pm_cur->bsdlabel[i].lvmpv != baklabel[i].lvmpv)
+			pm_partusage(pm_cur, i, 1);
+}
+
+void
+pm_setfstype(pm_devs_t *pm_cur, int part_num, int fstype)
+{
+	pm_cur->bsdlabel[part_num].pi_mount[0] = '\0';
+	pm_cur->bsdlabel[part_num].pi_flags = 0;
+	pm_cur->bsdlabel[part_num].lvmpv = 0;
+	pm_cur->bsdlabel[part_num].pi_fstype = fstype;
+	return;	
+}
+
+static void
+pm_select(pm_devs_t *pm_devs_in)
+{
+	pm = pm_devs_in;
+	if (logfp)
+		(void)fprintf(logfp, "Partman device: %s\n", pm->diskdev);
+	return;
+}
+
+void
+pm_rename(pm_devs_t *pm_cur)
+{
+	pm_select(pm_cur);
+	msg_prompt_win(MSG_packname, -1, 18, 0, 0, pm_cur->bsddiskname,
+		pm_cur->bsddiskname, sizeof pm_cur->bsddiskname);
+	(void) savenewlabel(pm_cur->bsdlabel, MAXPARTITIONS);
+	return;
+}
+
+int
+pm_editpart(int part_num)
+{
+	partinfo backup = pm->bsdlabel[part_num];
+
+	edit_ptn(&(struct menudesc){.cursel = part_num}, NULL);
+	if (checkoverlap(pm->bsdlabel, MAXPARTITIONS, PART_D, PART_C)) {
+		msg_display_add(MSG_cantsave);
+		process_menu(MENU_ok, NULL);
+		pm->bsdlabel[part_num] = backup;
+		return -1;
+	}
+	pm->unsaved = 1;
+	return 0;
+}
+
+/* Safe erase of disk */
+int
+pm_shred(pm_devs_t *pm_cur, int part, int shredtype)
+{
+	int error = -1;
+	char dev[SSTRSIZE];
+
+	pm_getdevstring(dev, SSTRSIZE, pm_cur, part);
+	switch(shredtype) {
+		case SHRED_ZEROS:
+			error += run_program(RUN_DISPLAY | RUN_PROGRESS,
+				"dd of=/dev/%s if=/dev/zero bs=1m progress=100 msgfmt=human",
+				dev);
+			break;
+		case SHRED_RANDOM:
+			error += run_program(RUN_DISPLAY | RUN_PROGRESS,
+				"dd of=/dev/r%s if=/dev/urandom bs=1m progress=100 msgfmt=human",
+				dev);
+			break;
+		case SHRED_CRYPTO:
+			error += run_program(RUN_DISPLAY | RUN_PROGRESS,
+				"sh -c 'cgdconfig -s cgd0 /dev/%s aes-cbc 128 < /dev/urandom'",
+				dev); /* XXX: cgd0?! */
+			if (! error) {
+				error += run_program(RUN_DISPLAY | RUN_PROGRESS,
+					"dd of=/dev/rcgd0d if=/dev/urandom bs=1m progress=100 msgfmt=human");
+				error += run_program(RUN_DISPLAY | RUN_PROGRESS,
+					"cgdconfig -u cgd0");
+			}
+			break;
+		default:
+			return -1;
+	}
+	pm_partusage(pm_cur, -1, 1);
+	memset(&pm_cur->oldlabel, 0, sizeof pm_cur->oldlabel);
+	memset(&pm_cur->bsdlabel, 0, sizeof pm_cur->bsdlabel);
+	return error;
+}
+
+static int
+pm_mountall_sort(const void *a, const void *b)
+{
+	return strcmp(mnts[*(const int *)a].on, mnts[*(const int *)b].on);
+}
+
+/* Mount all available partitions */
+static int
+pm_mountall(void)
+{
+	int num_devs = 0;
+	int mnts_order[MAX_MNTS];
+	int i, ii, error, ok;
+	char dev[SSTRSIZE]; dev[0] = '\0';
+	pm_devs_t *pm_i;
+	
+	localfs_dev[0] = '\0';
+	memset(&mnts, 0, sizeof mnts);
+
+	SLIST_FOREACH(pm_i, &pm_head, l) {
+		ok = 0;
+		for (i = 0; i < MAXPARTITIONS; i++) {
+			if (!(pm_i->bsdlabel[i].pi_flags & PIF_MOUNT && 
+					pm_i->bsdlabel[i].mnt_opts != NULL))
+				continue;
+			mnts[num_devs].mnt_opts = pm_i->bsdlabel[i].mnt_opts;
+			if (pm_i->bsdlabel[i].mounted != NULL &&
+					strlen(pm_i->bsdlabel[i].mounted) > 0) {
+				/* Device is already mounted. So, doing mount_null */
+				strlcpy(mnts[num_devs].dev, pm_i->bsdlabel[i].mounted, MOUNTLEN);
+				mnts[num_devs].mnt_opts = "-t null";
+			} else {
+				pm_getdevstring(dev, SSTRSIZE, pm_i, i);
+				snprintf(mnts[num_devs].dev, STRSIZE, "/dev/%s", dev);
+			}
+			mnts[num_devs].on = pm_i->bsdlabel[i].pi_mount;
+			if (strcmp(pm_i->bsdlabel[i].pi_mount, "/") == 0) {
+				if (pm_i->isspecial)
+					pm_i->bootable = 1;
+				/* Use disk with / as a default if the user has 
+				the sets on a local disk */
+				strlcpy(localfs_dev, pm_i->diskdev, SSTRSIZE);
+			}
+			num_devs++;
+			ok = 1;
+		}
+		if (ok)
+			md_pre_mount();
+	}
+	if (strlen(localfs_dev) < 1) {
+		msg_display(MSG_noroot);
+		process_menu(MENU_ok, NULL);
+		return -1;
+	}
+	for (i = 0; i < num_devs; i++)
+		mnts_order[i] = i;
+	qsort(mnts_order, num_devs, sizeof mnts_order[0], pm_mountall_sort);
+
+	for (i = 0; i < num_devs; i++) {
+		ii = mnts_order[i];
+		make_target_dir(mnts[ii].on);
+		error = target_mount_do(mnts[ii].mnt_opts, mnts[ii].dev, mnts[ii].on);
+		if (error)
+			return error;
+	}
+	return 0;
+}
+
+/* Mount partition bypassing ordinary order */
+static int
+pm_mount(pm_devs_t *pm_cur, int part_num)
+{
+	int error = 0;
+	char buf[MOUNTLEN];
+
+	if (strlen(pm_cur->bsdlabel[part_num].mounted) > 0)
+		return 0;
+
+	snprintf(buf, MOUNTLEN, "/tmp/%s%c", pm_cur->diskdev, part_num + 'a');
+	if (! dir_exists_p(buf))
+		run_program(RUN_DISPLAY | RUN_PROGRESS, "/bin/mkdir -p %s", buf);
+	if (pm_cur->bsdlabel[part_num].pi_flags & PIF_MOUNT &&
+		pm_cur->bsdlabel[part_num].mnt_opts != NULL &&
+		strlen(pm_cur->bsdlabel[part_num].mounted) < 1)
+		error += run_program(RUN_DISPLAY | RUN_PROGRESS, "/sbin/mount %s /dev/%s%c %s",
+				pm_cur->bsdlabel[part_num].mnt_opts,
+				pm_cur->diskdev, part_num + 'a', buf);
+
+	if (error)
+		pm_cur->bsdlabel[part_num].mounted[0] = '\0';
+	else {
+		strlcpy(pm_cur->bsdlabel[part_num].mounted, buf, MOUNTLEN);
+		pm_cur->blocked++;
+	}
+	return error;
+}
+
+void
+pm_umount(pm_devs_t *pm_cur, int part_num)
+{
+	char buf[SSTRSIZE]; buf[0] = '\0';
+	pm_getdevstring(buf, SSTRSIZE, pm_cur, part_num);
+
+	if (run_program(RUN_DISPLAY | RUN_PROGRESS,
+			"umount -f /dev/%s", buf) == 0) {
+		pm_cur->bsdlabel[part_num].mounted[0] = '\0';
+		if (pm_cur->blocked > 0)
+			pm_cur->blocked--;
+	}
+	return;
+}
+
+int
+pm_unconfigure(pm_devs_t *pm_cur)
+{
+	int i, error = 0, num = 0;
+	if (! strncmp(pm_cur->diskdev, "cgd", 3)) {
+ 		error = run_program(RUN_DISPLAY | RUN_PROGRESS, "cgdconfig -u %s", pm_cur->diskdev);
+ 		if (! error && pm_cur->refdev != NULL) {
+			((cgds_t*)pm_cur->refdev)->pm->blocked--;
+			((cgds_t*)pm_cur->refdev)->blocked = 0;
+ 		}
+ 	} else if (! strncmp(pm_cur->diskdev, "vnd", 3)) {
+		error = run_program(RUN_DISPLAY | RUN_PROGRESS, "vnconfig -u %s", pm_cur->diskdev);
+ 		if (! error && pm_cur->refdev != NULL) {
+			((vnds_t*)pm_cur->refdev)->pm->blocked--;
+			((vnds_t*)pm_cur->refdev)->blocked = 0;
+ 		}
+	} else if (! strncmp(pm_cur->diskdev, "raid", 4)) {
+		error = run_program(RUN_DISPLAY | RUN_PROGRESS, "raidctl -u %s", pm_cur->diskdev);
+		if (! error && pm_cur->refdev != NULL) {
+			((raids_t*)pm_cur->refdev)->blocked = 0;
+			for (i = 0; i < MAX_IN_RAID; i++)
+				if (((raids_t*)pm_cur->refdev)->pm[i] != NULL)
+					((raids_t*)pm_cur->refdev)->pm[i]->blocked--;
+		}
+	} else if (! strncmp(pm_cur->diskdev, "dk", 2)) {
+		if (pm_cur->refdev == NULL)
+			return -2;
+		error = run_program(RUN_DISPLAY | RUN_PROGRESS, "dkctl %s delwedge %s",
+			((pm_devs_t*)pm_cur->refdev)->diskdev, pm_cur->diskdev);
+		if (! error) {
+			if (pm_cur->refdev != NULL && ((pm_devs_t*)pm_cur->refdev)->blocked > 0)
+				((pm_devs_t*)pm_cur->refdev)->blocked--;
+			sscanf(pm_cur->diskdev, "dk%d", &num);
+			if (num >= 0 && num < MAX_WEDGES)
+				wedges[num].allocated = 0;
+		}
+	} /* XXX: lvm */
+	else
+		error = run_program(RUN_DISPLAY | RUN_PROGRESS, "eject -t disk /dev/%sd",
+			pm_cur->diskdev);
+	if (!error)
+		pm_cur->found = 0;
+	return error;
+}
+
+/* Last checks before leaving partition manager */
+static int
+pm_lastcheck(void)
+{
+	int error = 0;
+	FILE *file_tmp = fopen(concat_paths(targetroot_mnt, "/etc/fstab"), "r");
+	if (file_tmp == NULL)
+		error = 1;
+	else
+		fclose(file_tmp);
+	return error;
+}
+
+/* Is there some unsaved changes? */
+static int
+pm_needsave(void)
+{
+	pm_devs_t *pm_i;
+	SLIST_FOREACH(pm_i, &pm_head, l)
+		if (pm_i->unsaved) {
+			/* Oops, we have unsaved changes */
+			changed = 1;
+			msg_display(MSG_saveprompt);
+			process_menu(MENU_yesno, NULL);
+			return (yesno);
+		}
+	return 0;
+}
+
+/* Write all changes to disk */
+static int
+pm_commit(menudesc *m, void *arg)
 {
 	int retcode;
 	pm_devs_t *pm_i;
-	((part_entry_t *)arg)[0].retvalue = m->cursel + 1;
+	if (m != NULL && arg != NULL)
+		((part_entry_t *)arg)[0].retvalue = m->cursel + 1;
+
+	pm_gpt_commit();
 
-	for (pm_i = pm_head->next; pm_i != NULL; pm_i = pm_i->next) {
-		if (! pm_i->changed)
+	SLIST_FOREACH(pm_i, &pm_head, l) {
+		if (! pm_i->unsaved)
 			continue;
-		partman_select(pm_i);
-		if (
-				md_pre_disklabel() != 0  || /* Write partition table */
+		pm_select(pm_i);
+
+		if (pm_i->isspecial) {
+			if (make_filesystems() != 0) {
+				if (logfp)
+					fprintf(logfp, "Special disk %s preparing error\n", pm_i->diskdev);
+				continue;
+			}
+			pm_i->unsaved = 0;
+		} else if (! pm_i->gpt) {
+			savenewlabel(pm_i->bsdlabel, MAXPARTITIONS);
+			if (
 				write_disklabel() != 0   || /* Write slices table (disklabel) */
 				md_post_disklabel() != 0 || /* Enable swap and check badblock */
-				make_filesystems()          /* Create filesystems by newfs */
-			) { /* If something fails... */
-			if (logfp)
-				fprintf(logfp, "Disk preparing error\n");
-			return -1;
-		} else
-			pm_i->changed = 0;
-		/* Write bootsector if needed */
-		if (pm_i->bootable && md_post_newfs() != 0)
-			return -1;
+				make_filesystems() != 0     /* Create filesystems by newfs */
+			) {
+				/* Oops, something failed... */
+				if (logfp)
+					fprintf(logfp, "Disk %s preparing error\n", pm_i->diskdev);
+				continue;
+			}
+			pm_i->unsaved = 0;
+		}
 	}
+
 	/* Call all functions that may create new devices */
-	if ((retcode = partman_raid_commit()) != 0) {
+	if ((retcode = pm_raid_commit()) != 0) {
 		if (logfp)
-			fprintf(logfp, "Raid configuring error #%d\n", retcode);
+			fprintf(logfp, "RAIDframe configuring error #%d\n", retcode);
 		return -1;
 	}
-	if ((retcode = partman_vnd_commit()) != 0) {
+	if ((retcode = pm_vnd_commit()) != 0) {
 		if (logfp)
 			fprintf(logfp, "VND configuring error #%d\n", retcode);
 		return -1;
 	}
-	if ((retcode = partman_cgd_commit()) != 0) {
+	if ((retcode = pm_cgd_commit()) != 0) {
 		if (logfp)
 			fprintf(logfp, "CGD configuring error #%d\n", retcode);
 		return -1;
 	}
-	partman_upddevlist(m, arg);
+	if ((retcode = pm_lvm_commit()) != 0) {
+		if (logfp)
+			fprintf(logfp, "LVM configuring error #%d\n", retcode);
+		return -1;
+	}
+	if (m != NULL && arg != NULL)
+		pm_upddevlist(m, arg);
 	if (logfp)
 		fflush (logfp);
     return 0;
 }
 
 static int
-partman_submenu(menudesc *m, void *arg)
+pm_savebootsector(void)
 {
-	pm_devs_t *pm_i = ((part_entry_t *)arg)[m->cursel].dev_pm;;
-	int we_need_updlist = 0;
-	((part_entry_t *)arg)[0].retvalue = m->cursel + 1;
+	pm_devs_t *pm_i;
+	SLIST_FOREACH(pm_i, &pm_head, l)
+		if (pm_i->bootable) {
+			if (! strncmp("raid", pm_i->diskdev, 4))
+				if (run_program(RUN_DISPLAY | RUN_PROGRESS,
+					"raidctl -v -A root %s", pm_i->diskdev) != 0) {
+					if (logfp)
+						fprintf(logfp, "Error writting RAID bootsector to %s\n",
+							pm_i->diskdev);
+					continue;
+				}
+			if (pm_i->gpt && ! pm_i->isspecial) {
+				if (pm_i->rootpart < 0 ||
+					run_program(RUN_DISPLAY | RUN_PROGRESS,
+					"gpt biosboot -i %d %s",
+					pm_i->rootpart + 1, pm_i->diskdev) != 0) {
+			 		if (logfp)
+						fprintf(logfp, "Error writting GPT bootsector to %s\n",
+							pm_i->diskdev);
+					continue;
+				}
+			} else {
+				pm_select(pm_i);
+			 	if (check_partitions() == 0 || md_post_newfs() != 0) {
+		 			if (logfp)
+						fprintf(logfp, "Error writting bootsector to %s\n",
+							pm_i->diskdev);
+					continue;
+				}
+			}
+		}
+	return 0;
+}
 
-	if (pm_i == NULL) 
-		return -1;
-	partman_select(pm_i);
+/* Function for 'Enter'-menu */
+static int
+pm_submenu(menudesc *m, void *arg)
+{
+	int part_num = -1;
+	pm_devs_t *pm_cur = NULL;
+	((part_entry_t *)arg)[0].retvalue = m->cursel + 1;
 
-	process_menu(MENU_pmentry, &we_need_updlist);
-	if (we_need_updlist)
-		partman_upddevlist(m, arg);
+	switch (((part_entry_t *)arg)[m->cursel].type) {
+		case PM_DISK_T:
+		case PM_WEDGE_T:
+		case PM_PART_T:
+		case PM_SPEC_T:
+			if (((part_entry_t *)arg)[m->cursel].dev_ptr != NULL) {
+				pm_cur = ((part_entry_t *)arg)[m->cursel].dev_ptr;
+				if (pm_cur->blocked) {
+					msg_display(MSG_wannaunblock);
+					process_menu(MENU_noyes, NULL);
+					if (!yesno)
+						return -2;
+					pm_cur->blocked = 0;
+				}
+				pm_select(pm_cur);
+			}
+		default:
+			break;
+	}
 
+	switch (((part_entry_t *)arg)[m->cursel].type) {
+		case PM_DISK_T:
+			if (pm_cur == NULL) 
+				return -1;
+			if (pm_cur->gpt) {
+				process_menu(MENU_pmgptentry, &part_num);
+				pm_wedges_fill(pm_cur);
+			} else
+				process_menu(MENU_pmdiskentry, &part_num);
+			break;
+		case PM_WEDGE_T:
+		case PM_PART_T:
+			if (pm_cur == NULL) 
+				return -1;
+			part_num = ((part_entry_t *)arg)[m->cursel].dev_num;
+			process_menu(MENU_pmpartentry, &part_num);
+			if (pm_cur->gpt)
+				pm_wedges_fill(pm_cur);
+			break;
+		case PM_SPEC_T:
+			if (pm_cur == NULL) 
+				return -1;
+			part_num = 0;
+			process_menu(MENU_pmpartentry, &part_num);
+			break;
+		case PM_RAID_T:
+			return pm_edit(PMR_MENU_END, pm_raid_edit_menufmt,
+				pm_raid_set_value, pm_raid_check, pm_raid_init,
+				NULL, ((part_entry_t *)arg)[m->cursel].dev_ptr, 0, &raids_t_info);
+		case PM_VND_T:
+			return pm_edit(PMV_MENU_END, pm_vnd_edit_menufmt,
+				pm_vnd_set_value, pm_vnd_check, pm_vnd_init,
+				NULL, ((part_entry_t *)arg)[m->cursel].dev_ptr, 0, &vnds_t_info);
+		case PM_CGD_T:
+			return pm_cgd_edit(((part_entry_t *)arg)[m->cursel].dev_ptr,
+				NULL);
+		case PM_LVM_T:
+			return pm_edit(PML_MENU_END, pm_lvm_edit_menufmt,
+				pm_lvm_set_value, pm_lvm_check, pm_lvm_init,
+				NULL, ((part_entry_t *)arg)[m->cursel].dev_ptr, 0, &lvms_t_info);
+		case PM_LVMLV_T:
+			return pm_edit(PMLV_MENU_END, pm_lvmlv_edit_menufmt,
+				pm_lvmlv_set_value, pm_lvmlv_check, pm_lvmlv_init,
+				NULL, ((part_entry_t *)arg)[m->cursel].dev_ptr,
+				((part_entry_t *)arg)[m->cursel].dev_ptr_delta, &lv_t_info);
+	}
 	return 0;
 }
 
+/* Functions that generate menu entries text */
 static void
-partman_menufmt(menudesc *m, int opt, void *arg)
+pm_menufmt(menudesc *m, int opt, void *arg)
 {
 	const char *dev_status = "";
+	char buf[STRSIZE];
 	int part_num = ((part_entry_t *)arg)[opt].dev_num;
-	pm_devs_t *pm_i = ((part_entry_t *)arg)[opt].dev_pm;
+	pm_devs_t *pm_cur = ((part_entry_t *)arg)[opt].dev_ptr;
 
 	switch (((part_entry_t *)arg)[opt].type) {
 		case PM_DISK_T:
-			if (! pm_i->changed)
-				dev_status = "UNCHANGED";
-			else if (pm_i->bootable)
-				dev_status = "BOOT";
+			if (pm_cur->blocked)
+				dev_status = msg_string(MSG_pmblocked);
+			else if (! pm_cur->unsaved)
+				dev_status = msg_string(MSG_pmunchanged);
+			else if (pm_cur->bootable)
+				dev_status = msg_string(MSG_pmsetboot);
 			else
-				dev_status = "USED";
-			wprintw(m->mw, "%-33s Name:%-20s %9s", pm_i->diskdev_descr, pm_i->bsddiskname, dev_status);
+				dev_status = msg_string(MSG_pmused);
+			wprintw(m->mw, "%-33.33s %-22.22s %12.12s",
+				pm_cur->diskdev_descr,
+				(pm_cur->gpt) ?
+					msg_string(MSG_pmgptdisk) :
+					pm_cur->bsddiskname,
+				dev_status);
+			break;
+		case PM_WEDGE_T:
+			part_num = ((part_entry_t *)arg)[opt].wedge_num;
+			snprintf(buf, STRSIZE, "dk%d: %s",
+				part_num,
+				wedges[part_num].pm->bsdlabel[wedges[part_num].ptn].pi_mount);
+			wprintw(m->mw, "   %-30.30s %-22.22s %11uM",
+				buf,
+				(wedges[part_num].pm->bsdlabel[wedges[part_num].ptn].lvmpv) ? 
+					"lvm pv" :
+					getfslabelname(wedges[part_num].pm->bsdlabel[wedges[part_num].
+						ptn].pi_fstype),
+				wedges[part_num].pm->bsdlabel[wedges[part_num].ptn].pi_size /
+					(MEG / pm_cur->sectorsize));
 			break;
 		case PM_PART_T:
-			wprintw(m->mw, "   part %c: %-22s %-22s %11uM",
+			snprintf(buf, STRSIZE, "%s%c: %s %s",
+				pm_cur->diskdev,
 				'a' + part_num,
-				pm_i->bsdlabel[part_num].pi_mount,
-				fstype_name(pm_i->bsdlabel[part_num].pi_fstype),
-				pm_i->bsdlabel[part_num].pi_size / (MEG / pm_i->sectorsize));
+				pm_cur->bsdlabel[part_num].pi_mount,
+				(strlen(pm_cur->bsdlabel[part_num].mounted) > 0) ? msg_string(MSG_pmmounted) : 
+					(part_num == PART_B ||
+						strlen (pm_cur->bsdlabel[part_num].pi_mount ) < 1 ||
+						pm_cur->bsdlabel[part_num].pi_flags & PIF_MOUNT) ?
+						"" : msg_string(MSG_pmunused));
+			wprintw(m->mw, "   %-30.30s %-22.22s %11uM",
+				buf,
+				(pm_cur->bsdlabel[part_num].lvmpv) ? 
+					"lvm pv" :
+					getfslabelname(pm_cur->bsdlabel[part_num].pi_fstype),
+				pm_cur->bsdlabel[part_num].pi_size / (MEG / pm_cur->sectorsize));
+			break;
+		case PM_SPEC_T:
+			snprintf(buf, STRSIZE, "%s: %s",
+				pm_cur->diskdev_descr, pm_cur->bsdlabel[0].pi_mount);
+			wprintw(m->mw, "%-33.33s %-22.22s %11uM", buf,
+				getfslabelname(pm_cur->bsdlabel[0].pi_fstype),
+				pm_cur->bsdlabel[0].pi_size / (MEG / pm_cur->sectorsize));
 			break;
 		case PM_RAID_T:
-			partman_raid_menufmt(m, opt, arg);
+			pm_raid_menufmt(m, opt, arg);
 			break;
 		case PM_VND_T:
-			partman_vnd_menufmt(m, opt, arg);
+			pm_vnd_menufmt(m, opt, arg);
 			break;
 		case PM_CGD_T:
-			partman_cgd_menufmt(m, opt, arg);
+			pm_cgd_menufmt(m, opt, arg);
 			break;
+		case PM_LVM_T:
+			pm_lvm_menufmt(m, opt, arg);
+			break;
+		case PM_LVMLV_T:
+			pm_lvmlv_menufmt(m, opt, arg);
+			break;
+	}
+	return;
+}
+
+/* Submenu for RAID/LVM/CGD/VND */
+static void
+pm_upddevlist_adv(menudesc *m, void *arg, int *i,
+	pm_upddevlist_adv_t *d)
+{
+	int ii;
+	if (d->create_msg != NULL) {
+		/* We want to have menu entrie that create new device */
+		((part_entry_t *)arg)[*i].type = d->pe_type;
+		((part_entry_t *)arg)[*i].dev_ptr = NULL;
+		((part_entry_t *)arg)[*i].dev_ptr_delta = d->s->parent_size * d->sub_num;
+		m->opts[(*i)++] = (struct menu_ent) {
+			.opt_name = d->create_msg,
+			.opt_action = pm_submenu,
+		};
+	}
+	for (ii = 0; ii < d->s->max; ii++) {
+		if (d->s->entry_enabled == NULL ||
+			d->s->entry_blocked == NULL ||
+			*(int*)((char*)d->s->entry_enabled + d->s->entry_size * ii +
+				d->s->parent_size * d->sub_num) == 0 ||
+			*(int*)((char*)d->s->entry_blocked + d->s->entry_size * ii +
+				d->s->parent_size * d->sub_num) != 0)
+			continue;
+		/* We have a entry for displaying */
+		changed = 1;
+		m->opts[*i] = (struct menu_ent) {
+			.opt_name = NULL,
+			.opt_action = pm_submenu,
+		};
+		((part_entry_t *)arg)[*i].type = d->pe_type;
+		((part_entry_t *)arg)[*i].dev_ptr = (char*)d->s->entry_first +
+			d->s->entry_size * ii + d->s->parent_size * d->sub_num;
+		(*i)++;
+		/* We should to show submenu for current entry */
+		if (d->sub != NULL) {
+			d->sub->sub_num = ii;
+			pm_upddevlist_adv(m, arg, i, d->sub);
+		}
 	}
 	return;
 }
 
+/* Update partman main menu with devices list */
 static int
-partman_upddevlist(menudesc *m, void *arg)
+pm_upddevlist(menudesc *m, void *arg)
 {
 	int i = 0, ii;
 	pm_devs_t *pm_i;
 	if (arg != NULL)
 		((part_entry_t *)arg)[0].retvalue = m->cursel + 1;
 
+	changed = 0;
+	/* Mark all devicec as not found */
+	SLIST_FOREACH(pm_i, &pm_head, l)
+		if (pm_i->found > 0)
+			pm_i->found = 0;
+	/* Detect all present devices */
 	find_disks("partman");
+	pm_lvm_find();
+	pm_clean();
 
-	if (m != NULL && arg != NULL) {
-		for (pm_i = pm_head->next, i = 0; pm_i != NULL;
-				pm_i = pm_i->next, i++) {
-			m->opts[i].opt_name = NULL;
-			m->opts[i].opt_action = partman_submenu;
-			((part_entry_t *)arg)[i].dev_pm = pm_i;
-			((part_entry_t *)arg)[i].dev_num = -1;
+	if (m == NULL || arg == NULL)
+		return -1;
+
+	SLIST_FOREACH(pm_i, &pm_head, l) {
+		m->opts[i].opt_name = NULL;
+		m->opts[i].opt_action = pm_submenu;
+		((part_entry_t *)arg)[i].dev_ptr = pm_i;
+		((part_entry_t *)arg)[i].dev_num = -1;
+		if (pm_i->isspecial)
+			((part_entry_t *)arg)[i].type = PM_SPEC_T;
+		else {
 			((part_entry_t *)arg)[i].type = PM_DISK_T;
-			for (ii = 0; ii < MAXPARTITIONS; ii++) {
-				if ((pm_i->bsdlabel[ii].pi_flags & PIF_MOUNT &&
-						pm_i->bsdlabel[ii].pi_fstype != FS_UNUSED) ||
-						pm_i->bsdlabel[ii].pi_fstype == FS_RAID ||
-						pm_i->bsdlabel[ii].pi_fstype == FS_CGD) {
-					i++;
-					m->opts[i].opt_name = NULL;
-					m->opts[i].opt_action = partman_submenu;
-					((part_entry_t *)arg)[i].dev_pm = pm_i;
-					((part_entry_t *)arg)[i].dev_num = ii;
-					((part_entry_t *)arg)[i].type = PM_PART_T;
-				}
+			if (pm_i->gpt) {
+				pm_wedges_fill(pm_i);
+				for (ii = 0; ii < MAX_WEDGES; ii++)
+					if (wedges[ii].pm == pm_i) {
+						i++;
+						m->opts[i].opt_name = NULL;
+						m->opts[i].opt_action = pm_submenu;
+						((part_entry_t *)arg)[i].dev_ptr = pm_i;
+						((part_entry_t *)arg)[i].dev_num = wedges[ii].ptn;
+						((part_entry_t *)arg)[i].wedge_num = ii;
+						((part_entry_t *)arg)[i].type = PM_WEDGE_T;
+					}
+			} else {
+				for (ii = 0; ii < MAXPARTITIONS; ii++)
+					if (pm_i->bsdlabel[ii].pi_fstype != FS_UNUSED) {
+						i++;
+						m->opts[i].opt_name = NULL;
+						m->opts[i].opt_action = pm_submenu;
+						((part_entry_t *)arg)[i].dev_ptr = pm_i;
+						((part_entry_t *)arg)[i].dev_num = ii;
+						((part_entry_t *)arg)[i].type = PM_PART_T;
+					}
 			}
 		}
-		((part_entry_t *)arg)[i].dev_num = -1;
-		m->opts[i++] = (struct menu_ent) {
-			.opt_name = "Create cryptographic volume (CGD)",
-			.opt_action = partman_cgd_edit,
-		};
-		for (ii = 0; ii < MAX_CGDS; ii++) {
-			if (cgds[ii].enabled == 0)
-				continue;
-			m->opts[i] = (struct menu_ent) {
-				.opt_name = NULL,
-				.opt_action = partman_cgd_edit,
-			};
-			((part_entry_t *)arg)[i].dev_num = ii;
-			((part_entry_t *)arg)[i].type = PM_CGD_T;
-			i++;
-		}
-		((part_entry_t *)arg)[i].dev_num = -1;
-		m->opts[i++] = (struct menu_ent) {
-			.opt_name = "Create virtual disk image (VND)",
-			.opt_action = partman_vnd_edit,
-		};
-		for (ii = 0; ii < MAX_VNDS; ii++) {
-			if (vnds[ii].enabled == 0)
-				continue;
-			m->opts[i] = (struct menu_ent) {
-				.opt_name = NULL,
-				.opt_action = partman_vnd_edit,
-			};
-			((part_entry_t *)arg)[i].dev_num = ii;
-			((part_entry_t *)arg)[i].type = PM_VND_T;
-			i++;
-		}
-		((part_entry_t *)arg)[i].dev_num = -1;
-		m->opts[i++] = (struct menu_ent) {
-			.opt_name = "Create logical volume (LVM) [WIP]",
-			.opt_action = partman_lvm_edit,
-		};
-		((part_entry_t *)arg)[i].dev_num = -1;
-		m->opts[i++] = (struct menu_ent) {
-			.opt_name = "Create software RAID",
-			.opt_action = partman_raid_edit,
-		};
-		for (ii = 0; ii < MAX_RAIDS; ii++) {
-			if (raids[ii].enabled == 0)
-				continue;
-			m->opts[i] = (struct menu_ent) {
-				.opt_name = NULL,
-				.opt_action = partman_raid_edit,
-			};
-			((part_entry_t *)arg)[i].dev_num = ii;
-			((part_entry_t *)arg)[i].type = PM_RAID_T;
-			i++;
-		}
-		m->opts[i++] = (struct menu_ent) {
-			.opt_name = "Update devices list",
-			.opt_action = partman_upddevlist,
-		};
-		m->opts[i  ] = (struct menu_ent) {
-			.opt_name = "Save changes",
-			.opt_action = partman_commit,
-		};
-		for (ii = 0; ii <= i; ii++) {
-			m->opts[ii].opt_menu = OPT_NOMENU;
-			m->opts[ii].opt_flags = OPT_EXIT;
-		}
+		i++;
+	}
+	pm_upddevlist_adv(m, arg, &i,
+		&(pm_upddevlist_adv_t) {MSG_create_cgd, PM_CGD_T, &cgds_t_info, 0, NULL});
+	pm_upddevlist_adv(m, arg, &i,
+		&(pm_upddevlist_adv_t) {MSG_create_cnd, PM_VND_T, &vnds_t_info, 0, NULL});
+	pm_upddevlist_adv(m, arg, &i,
+		&(pm_upddevlist_adv_t) {MSG_create_vg, PM_LVM_T, &lvms_t_info, 0,
+		&(pm_upddevlist_adv_t) {MSG_create_lv, PM_LVMLV_T, &lv_t_info, 0, NULL}});
+	pm_upddevlist_adv(m, arg, &i,
+		&(pm_upddevlist_adv_t) {MSG_create_raid, PM_RAID_T, &raids_t_info, 0, NULL});
+
+	m->opts[i++] = (struct menu_ent) {
+		.opt_name = MSG_updpmlist,
+		.opt_action = pm_upddevlist,
+	};
+	m->opts[i  ] = (struct menu_ent) {
+		.opt_name = MSG_savepm,
+		.opt_action = pm_commit,
+	};
+	for (ii = 0; ii <= i; ii++) {
+		m->opts[ii].opt_menu = OPT_NOMENU;
+		m->opts[ii].opt_flags = OPT_EXIT;
 	}
+
+	if (((part_entry_t *)arg)[0].retvalue >= 0)
+		m->cursel = ((part_entry_t *)arg)[0].retvalue - 1;
 	return i;
 }
 
-// TODO: switch to langfiles
+static void
+pm_menuin(menudesc *m, void *arg)
+{
+	if (cursel > m->numopts)
+		m->cursel = m->numopts;
+	else if (cursel < 0)
+		m->cursel = 0;
+	else
+		m->cursel = cursel;
+}
+
+static void
+pm_menuout(menudesc *m, void *arg)
+{
+	cursel = m->cursel;
+}
+
+/* Main partman function */
 int
 partman(void)
 {
-	int menu_no;
-	int menu_num_entries;
-	menu_ent menu_entries[MAX_DISKS+6];
-	part_entry_t args[MAX_DISKS];
+	int menu_no, menu_num_entries;
+	static int firstrun = 1;
+	menu_ent menu_entries[MAX_ENTRIES+6];
+	part_entry_t args[MAX_ENTRIES];
+
+	if (firstrun) {
+		raids_t_info = (structinfo_t) {
+			.max = MAX_RAID,
+			.entry_size = sizeof raids[0],
+			.entry_first = &raids[0],
+			.entry_enabled = &(raids[0].enabled),
+			.entry_blocked = &(raids[0].blocked),
+			.entry_node = &(raids[0].node),
+		};
+		vnds_t_info = (structinfo_t) {
+			.max = MAX_VND,
+			.entry_size = sizeof vnds[0],
+			.entry_first = &vnds[0],
+			.entry_enabled = &(vnds[0].enabled),
+			.entry_blocked = &(vnds[0].blocked),
+			.entry_node = &(vnds[0].node),
+		};
+		cgds_t_info = (structinfo_t) {
+			.max = MAX_CGD,
+			.entry_size = sizeof cgds[0],
+			.entry_first = &cgds[0],
+			.entry_enabled = &(cgds[0].enabled),
+			.entry_blocked = &(cgds[0].blocked),
+			.entry_node = &(cgds[0].node),
+		};
+		lvms_t_info = (structinfo_t) {
+			.max = MAX_LVM_VG,
+			.entry_size = sizeof lvms[0],
+			.entry_first = &lvms[0],
+			.entry_enabled = &(lvms[0].enabled),
+			.entry_blocked = &(lvms[0].blocked),
+			.entry_node = NULL,
+		};
+		lv_t_info = (structinfo_t) {
+			.max = MAX_LVM_LV,
+			.entry_size = sizeof lvms[0].lv[0], 
+			.entry_first = &lvms[0].lv[0],
+			.entry_enabled = &(lvms[0].lv[0].size),
+			.entry_blocked = &(lvms[0].lv[0].blocked),
+			.parent_size = sizeof lvms[0],
+		};
+
+		memset(&raids, 0, sizeof raids);
+		memset(&cgds, 0, sizeof cgds);
+		memset(&vnds, 0, sizeof vnds);
+		memset(&lvms, 0, sizeof lvms);
+		cursel = 0;
+		changed = 0;
+		firstrun = 0;
+	}
 
 	do {
-		clear();
-		refresh();
-		menu_num_entries = partman_upddevlist(&((menudesc) {.opts = menu_entries}), args);
-		menu_no = new_menu("Partition manager. All disks, partitions, LVM, RAID displayed there.\nAt first add drive, then prepare partitions and go.",
-			menu_entries, menu_num_entries+1, 1, 1, 0, 0,
+		menu_num_entries = pm_upddevlist(&(menudesc){.opts = menu_entries}, args);
+		menu_no = new_menu(MSG_partman_header,
+			menu_entries, menu_num_entries+1, 1, 1, 0, 75, /* Fixed width */
 			MC_ALWAYS_SCROLL | MC_NOBOX | MC_NOCLEAR,
-			NULL, partman_menufmt, NULL, NULL, "Finish partitioning");
+			pm_menuin, pm_menufmt, pm_menuout, NULL, MSG_finishpm);
 		if (menu_no == -1)
 			args[0].retvalue = -1;
 		else {
 			args[0].retvalue = 0;
+			clear();
+			refresh();
 			process_menu(menu_no, &args);
 			free_menu(menu_no);
 		}
 
-		// TODO: check_partitions()
-		/* Check that fstab on target device is readable - if so then we can go */
 		if (args[0].retvalue == 0) {
-			unwind_mounts();
-			if (partman_mountall() != 0 ||
-				make_fstab() != 0) {
-					msg_display("Do you want to try?");
+			if (pm_needsave())
+				pm_commit(NULL, NULL);
+			if (pm_mountall() != 0 ||
+				make_fstab() != 0 ||
+				pm_lastcheck() != 0 ||
+				pm_savebootsector() != 0) {
+					msg_display(MSG_wannatry);
 					process_menu(MENU_yesno, NULL);
 					args[0].retvalue = (yesno) ? 1:-1;
-			} else {
-				FILE *file_tmp = fopen(concat_paths(targetroot_mnt, "/etc/fstab"), "r");
-				if (file_tmp == NULL)
-					args[0].retvalue = -1;
-				else
-					fclose(file_tmp);
 			}
 		}
 	} while (args[0].retvalue > 0);
diff --git a/distrib/utils/sysinst/savenewlabel.c b/distrib/utils/sysinst/savenewlabel.c
index a711ded..7a30466 100644
--- a/distrib/utils/sysinst/savenewlabel.c
+++ b/distrib/utils/sysinst/savenewlabel.c
@@ -55,7 +55,7 @@ __RCSID("$NetBSD: savenewlabel.c,v 1.12 2012/01/05 22:18:36 christos Exp $");
 
 int
 /*ARGSUSED*/
-savenewlabel(partinfo *lp, int nparts) /* TODO: what does lp there? */
+savenewlabel(partinfo *lp, int nparts)
 {
 	FILE *f;
 	char *f_name = malloc(STRSIZE * sizeof(char));
@@ -63,11 +63,17 @@ savenewlabel(partinfo *lp, int nparts) /* TODO: what does lp there? */
 	pm_devs_t *pm_i;
 
 	/* Check names collision */
-	for (pm_i = pm_head->next; partman_go && pm_i != NULL; pm_i = pm_i->next)
-		while (pm_i != pm && !strcmp(pm_i->bsddiskname, pm->bsddiskname))
-			pm->bsddiskname[strlen(pm->bsddiskname)-1] = rand() % ('z' - 'a') + 'a';
+	if (partman_go)
+		SLIST_FOREACH(pm_i, &pm_head, l)
+			for (i = 'a'; pm_i != pm && i < 'z' &&
+					! strcmp(pm_i->bsddiskname, pm->bsddiskname); i++) {
+				if (strlen(pm_i->bsddiskname) > 0)
+					pm_i->bsddiskname[strlen(pm_i->bsddiskname)-1] = i;
+				else
+					snprintf(pm_i->bsddiskname, DISKNAME_SIZE, "disk %c", i);
+			}
 
-	snprintf(f_name, STRSIZE, "/tmp/disktab.%s", pm->bsddiskname); // TODO: test
+	snprintf(f_name, STRSIZE, "/tmp/disktab.%s", pm->bsddiskname);
 
 	/*
 	  N.B. disklabels only support up to 2TB (32-bit field for sectors).
@@ -102,15 +108,15 @@ savenewlabel(partinfo *lp, int nparts) /* TODO: what does lp there? */
 	}
 	for (i = 0; i < nparts; i++) {
 		scripting_fprintf(f, "\t:p%c#%" PRIu32 ":o%c#%" PRIu32
-		    ":t%c=%s:", 'a'+i, (uint32_t)pm->bsdlabel[i].pi_size,
-		    'a'+i, (uint32_t)pm->bsdlabel[i].pi_offset, 'a'+i,
-		    getfslabelname(pm->bsdlabel[i].pi_fstype));
-		if (PI_ISBSDFS(&pm->bsdlabel[i]))
+		    ":t%c=%s:", 'a'+i, (uint32_t)lp[i].pi_size,
+		    'a'+i, (uint32_t)lp[i].pi_offset, 'a'+i,
+		    getfslabelname(lp[i].pi_fstype));
+		if (PI_ISBSDFS(&lp[i]))
 			scripting_fprintf (f, "b%c#%" PRIu32 ":f%c#%" PRIu32
 			    ":", 'a'+i,
-			    (uint32_t)(pm->bsdlabel[i].pi_fsize *
-			    pm->bsdlabel[i].pi_frag),
-			    'a'+i, (uint32_t)pm->bsdlabel[i].pi_fsize);
+			    (uint32_t)(lp[i].pi_fsize *
+			    lp[i].pi_frag),
+			    'a'+i, (uint32_t)lp[i].pi_fsize);
 	
 		if (i < nparts - 1)
 			scripting_fprintf(f, "\\\n");
diff --git a/distrib/utils/sysinst/target.c b/distrib/utils/sysinst/target.c
index 6b8aeb7..811ef1a 100644
--- a/distrib/utils/sysinst/target.c
+++ b/distrib/utils/sysinst/target.c
@@ -395,7 +395,7 @@ target_fopen(const char *filename, const char *type)
  * NB: does not prefix mount-from, which probably breaks nullfs mounts.
  */
 int
-target_mount(const char *opts, const char *from, int ptn, const char *on)
+target_mount_do(const char *opts, const char *from, const char *on)
 {
 	struct unwind_mount *m;
 	int error;
@@ -414,8 +414,8 @@ target_mount(const char *opts, const char *from, int ptn, const char *on)
 	backtowin();
 #endif
 
-	error = run_program(0, "/sbin/mount %s /dev/%s%c %s%s",
-			opts, from, 'a' + ptn, target_prefix(), on);
+	error = run_program(0, "/sbin/mount %s %s %s%s",
+			opts, from, target_prefix(), on);
 	if (error) {
 		free(m);
 		return error;
@@ -425,6 +425,19 @@ target_mount(const char *opts, const char *from, int ptn, const char *on)
 	return 0;
 }
 
+int
+target_mount(const char *opts, const char *from, int ptn, const char *on)
+{
+	int error;
+	char *frompath;
+	asprintf (&frompath, "/dev/%s%c", from, (ptn < 0)? 0 : 'a' + ptn);
+	if (frompath == 0)
+		return (ENOMEM);
+	error = target_mount_do(opts, frompath, on);
+	free(frompath);
+	return error;
+}
+
 /*
  * unwind the mount stack, unmounting mounted filesystems.
  * For now, ignore any errors in unmount. 
diff --git a/distrib/utils/sysinst/upgrade.c b/distrib/utils/sysinst/upgrade.c
index ba8a862..9bf303d 100644
--- a/distrib/utils/sysinst/upgrade.c
+++ b/distrib/utils/sysinst/upgrade.c
@@ -55,6 +55,7 @@ void
 do_upgrade(void)
 {
 	int retcode = 0;
+	partman_go = 0;
 
 	msg_display(MSG_upgradeusure);
 	process_menu(MENU_noyes, NULL);
diff --git a/distrib/utils/sysinst/util.c b/distrib/utils/sysinst/util.c
index d1df210..17adc80 100644
--- a/distrib/utils/sysinst/util.c
+++ b/distrib/utils/sysinst/util.c
@@ -1606,7 +1606,7 @@ ext_dir_for_set(const char *set_name) {
 }
 
 void
-do_coloring (unsigned int fg, unsigned int bg) {
+do_coloring(unsigned int fg, unsigned int bg) {
 	if (bg > COLOR_WHITE)
 		bg = COLOR_BLUE;
 	if (fg > COLOR_WHITE)
