1*cdd2d676SSascha Wildner /*
2*cdd2d676SSascha Wildner  * Copyright (c)2004 The DragonFly Project.  All rights reserved.
3*cdd2d676SSascha Wildner  *
4*cdd2d676SSascha Wildner  * Redistribution and use in source and binary forms, with or without
5*cdd2d676SSascha Wildner  * modification, are permitted provided that the following conditions
6*cdd2d676SSascha Wildner  * are met:
7*cdd2d676SSascha Wildner  *
8*cdd2d676SSascha Wildner  *   Redistributions of source code must retain the above copyright
9*cdd2d676SSascha Wildner  *   notice, this list of conditions and the following disclaimer.
10*cdd2d676SSascha Wildner  *
11*cdd2d676SSascha Wildner  *   Redistributions in binary form must reproduce the above copyright
12*cdd2d676SSascha Wildner  *   notice, this list of conditions and the following disclaimer in
13*cdd2d676SSascha Wildner  *   the documentation and/or other materials provided with the
14*cdd2d676SSascha Wildner  *   distribution.
15*cdd2d676SSascha Wildner  *
16*cdd2d676SSascha Wildner  *   Neither the name of the DragonFly Project nor the names of its
17*cdd2d676SSascha Wildner  *   contributors may be used to endorse or promote products derived
18*cdd2d676SSascha Wildner  *   from this software without specific prior written permission.
19*cdd2d676SSascha Wildner  *
20*cdd2d676SSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21*cdd2d676SSascha Wildner  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*cdd2d676SSascha Wildner  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*cdd2d676SSascha Wildner  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24*cdd2d676SSascha Wildner  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25*cdd2d676SSascha Wildner  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26*cdd2d676SSascha Wildner  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27*cdd2d676SSascha Wildner  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28*cdd2d676SSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29*cdd2d676SSascha Wildner  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30*cdd2d676SSascha Wildner  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31*cdd2d676SSascha Wildner  * OF THE POSSIBILITY OF SUCH DAMAGE.
32*cdd2d676SSascha Wildner  */
33*cdd2d676SSascha Wildner 
34*cdd2d676SSascha Wildner /*
35*cdd2d676SSascha Wildner  * fn_subpart.c
36*cdd2d676SSascha Wildner  * Installer Function : Create Subpartitions.
37*cdd2d676SSascha Wildner  * $Id: fn_subpart.c,v 1.50 2005/04/07 20:22:40 cpressey Exp $
38*cdd2d676SSascha Wildner  */
39*cdd2d676SSascha Wildner 
40*cdd2d676SSascha Wildner #include <stdio.h>
41*cdd2d676SSascha Wildner #include <stdlib.h>
42*cdd2d676SSascha Wildner #include <string.h>
43*cdd2d676SSascha Wildner 
44*cdd2d676SSascha Wildner #ifdef ENABLE_NLS
45*cdd2d676SSascha Wildner #include <libintl.h>
46*cdd2d676SSascha Wildner #define _(String) gettext (String)
47*cdd2d676SSascha Wildner #else
48*cdd2d676SSascha Wildner #define _(String) (String)
49*cdd2d676SSascha Wildner #endif
50*cdd2d676SSascha Wildner 
51*cdd2d676SSascha Wildner #include "libaura/mem.h"
52*cdd2d676SSascha Wildner #include "libaura/buffer.h"
53*cdd2d676SSascha Wildner #include "libaura/dict.h"
54*cdd2d676SSascha Wildner #include "libaura/fspred.h"
55*cdd2d676SSascha Wildner 
56*cdd2d676SSascha Wildner #include "libdfui/dfui.h"
57*cdd2d676SSascha Wildner #include "libdfui/dump.h"
58*cdd2d676SSascha Wildner #include "libdfui/system.h"
59*cdd2d676SSascha Wildner 
60*cdd2d676SSascha Wildner #include "libinstaller/commands.h"
61*cdd2d676SSascha Wildner #include "libinstaller/diskutil.h"
62*cdd2d676SSascha Wildner #include "libinstaller/functions.h"
63*cdd2d676SSascha Wildner #include "libinstaller/uiutil.h"
64*cdd2d676SSascha Wildner 
65*cdd2d676SSascha Wildner #include "fn.h"
66*cdd2d676SSascha Wildner #include "flow.h"
67*cdd2d676SSascha Wildner #include "pathnames.h"
68*cdd2d676SSascha Wildner 
69*cdd2d676SSascha Wildner static int	create_subpartitions(struct i_fn_args *);
70*cdd2d676SSascha Wildner static long	default_capacity(struct storage *, int);
71*cdd2d676SSascha Wildner static int	check_capacity(struct i_fn_args *);
72*cdd2d676SSascha Wildner static int	check_subpartition_selections(struct dfui_response *, struct i_fn_args *);
73*cdd2d676SSascha Wildner static void	save_subpartition_selections(struct dfui_response *, struct i_fn_args *);
74*cdd2d676SSascha Wildner static void	populate_create_subpartitions_form(struct dfui_form *, struct i_fn_args *);
75*cdd2d676SSascha Wildner static int	warn_subpartition_selections(struct i_fn_args *);
76*cdd2d676SSascha Wildner static struct dfui_form *make_create_subpartitions_form(struct i_fn_args *);
77*cdd2d676SSascha Wildner static int	show_create_subpartitions_form(struct dfui_form *, struct i_fn_args *);
78*cdd2d676SSascha Wildner 
79*cdd2d676SSascha Wildner static const char *def_mountpt[7]  = {"/", "swap", "/var", "/tmp", "/usr", "/home", NULL};
80*cdd2d676SSascha Wildner static int expert = 0;
81*cdd2d676SSascha Wildner 
82*cdd2d676SSascha Wildner /*
83*cdd2d676SSascha Wildner  * Given a set of subpartitions-to-be in the selected slice,
84*cdd2d676SSascha Wildner  * create them.
85*cdd2d676SSascha Wildner  */
86*cdd2d676SSascha Wildner static int
87*cdd2d676SSascha Wildner create_subpartitions(struct i_fn_args *a)
88*cdd2d676SSascha Wildner {
89*cdd2d676SSascha Wildner 	struct subpartition *sp;
90*cdd2d676SSascha Wildner 	struct commands *cmds;
91*cdd2d676SSascha Wildner 	int result = 0;
92*cdd2d676SSascha Wildner 	int copied_original = 0;
93*cdd2d676SSascha Wildner 	int num_partitions;
94*cdd2d676SSascha Wildner 
95*cdd2d676SSascha Wildner 	cmds = commands_new();
96*cdd2d676SSascha Wildner 	if (!is_file("%sinstall.disklabel.%s",
97*cdd2d676SSascha Wildner 	    a->tmp,
98*cdd2d676SSascha Wildner 	    slice_get_device_name(storage_get_selected_slice(a->s)))) {
99*cdd2d676SSascha Wildner 		/*
100*cdd2d676SSascha Wildner 		 * Get a copy of the 'virgin' disklabel.
101*cdd2d676SSascha Wildner 		 * XXX It might make more sense for this to
102*cdd2d676SSascha Wildner 		 * happen right after format_slice() instead.
103*cdd2d676SSascha Wildner 		 */
104*cdd2d676SSascha Wildner 		command_add(cmds, "%s%s -r %s >%sinstall.disklabel.%s",
105*cdd2d676SSascha Wildner 		    a->os_root, cmd_name(a, "DISKLABEL"),
106*cdd2d676SSascha Wildner 		    slice_get_device_name(storage_get_selected_slice(a->s)),
107*cdd2d676SSascha Wildner 		    a->tmp,
108*cdd2d676SSascha Wildner 		    slice_get_device_name(storage_get_selected_slice(a->s)));
109*cdd2d676SSascha Wildner 	}
110*cdd2d676SSascha Wildner 
111*cdd2d676SSascha Wildner 	/*
112*cdd2d676SSascha Wildner 	 * Weave together a new disklabel out the of the 'virgin'
113*cdd2d676SSascha Wildner 	 * disklabel, and the user's subpartition choices.
114*cdd2d676SSascha Wildner 	 */
115*cdd2d676SSascha Wildner 
116*cdd2d676SSascha Wildner 	/*
117*cdd2d676SSascha Wildner 	 * Take everything from the 'virgin' disklabel up until the
118*cdd2d676SSascha Wildner 	 * '16 partitions' line.
119*cdd2d676SSascha Wildner 	 */
120*cdd2d676SSascha Wildner 	num_partitions = 16;
121*cdd2d676SSascha Wildner 	command_add(cmds, "%s%s '$2==\"partitions:\" || cut { cut = 1 } !cut { print $0 }' <%sinstall.disklabel.%s >%sinstall.disklabel",
122*cdd2d676SSascha Wildner 	    a->os_root, cmd_name(a, "AWK"),
123*cdd2d676SSascha Wildner 	    a->tmp,
124*cdd2d676SSascha Wildner 	    slice_get_device_name(storage_get_selected_slice(a->s)),
125*cdd2d676SSascha Wildner 	    a->tmp);
126*cdd2d676SSascha Wildner 
127*cdd2d676SSascha Wildner 	/*
128*cdd2d676SSascha Wildner 	 * 16 partitions:
129*cdd2d676SSascha Wildner 	 * #          size     offset    fstype
130*cdd2d676SSascha Wildner 	 *   c:   16383969          0    unused	#    7999.985MB
131*cdd2d676SSascha Wildner 	 */
132*cdd2d676SSascha Wildner 
133*cdd2d676SSascha Wildner 	command_add(cmds, "%s%s '%d partitions:' >>%sinstall.disklabel",
134*cdd2d676SSascha Wildner 	    a->os_root, cmd_name(a, "ECHO"), num_partitions ,a->tmp);
135*cdd2d676SSascha Wildner 	command_add(cmds, "%s%s '%s' >>%sinstall.disklabel",
136*cdd2d676SSascha Wildner 	    a->os_root, cmd_name(a, "ECHO"),
137*cdd2d676SSascha Wildner 	    "#          size     offset    fstype",
138*cdd2d676SSascha Wildner 	    a->tmp);
139*cdd2d676SSascha Wildner 
140*cdd2d676SSascha Wildner #ifdef DEBUG
141*cdd2d676SSascha Wildner 	for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
142*cdd2d676SSascha Wildner 	     sp != NULL; sp = subpartition_next(sp)) {
143*cdd2d676SSascha Wildner 		command_add(cmds, "%s%s 'mountpoint: %s device: %s'",
144*cdd2d676SSascha Wildner 		     a->os_root, cmd_name(a, "ECHO"),
145*cdd2d676SSascha Wildner 		     subpartition_get_mountpoint(sp),
146*cdd2d676SSascha Wildner 		     subpartition_get_device_name(sp));
147*cdd2d676SSascha Wildner 	}
148*cdd2d676SSascha Wildner #endif
149*cdd2d676SSascha Wildner 
150*cdd2d676SSascha Wildner 	/*
151*cdd2d676SSascha Wildner 	 * Write a line for each subpartition the user wants.
152*cdd2d676SSascha Wildner 	 */
153*cdd2d676SSascha Wildner 	for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
154*cdd2d676SSascha Wildner 	     sp != NULL; sp = subpartition_next(sp)) {
155*cdd2d676SSascha Wildner 		if (subpartition_is_mfsbacked(sp)) {
156*cdd2d676SSascha Wildner 			continue;
157*cdd2d676SSascha Wildner 		}
158*cdd2d676SSascha Wildner 		if (subpartition_get_letter(sp) > 'c' && !copied_original) {
159*cdd2d676SSascha Wildner 			/*
160*cdd2d676SSascha Wildner 			 * Copy the 'c' line from the 'virgin' disklabel.
161*cdd2d676SSascha Wildner 			 */
162*cdd2d676SSascha Wildner 			command_add(cmds, "%s%s '^  c:' %sinstall.disklabel.%s >>%sinstall.disklabel",
163*cdd2d676SSascha Wildner 			    a->os_root, cmd_name(a, "GREP"),
164*cdd2d676SSascha Wildner 			    a->tmp,
165*cdd2d676SSascha Wildner 			    slice_get_device_name(storage_get_selected_slice(a->s)),
166*cdd2d676SSascha Wildner 			    a->tmp);
167*cdd2d676SSascha Wildner 			copied_original = 1;
168*cdd2d676SSascha Wildner 		}
169*cdd2d676SSascha Wildner 		if (subpartition_is_swap(sp)) {
170*cdd2d676SSascha Wildner 			command_add(cmds, "%s%s '  %c:\t%s\t*\tswap' >>%sinstall.disklabel",
171*cdd2d676SSascha Wildner 			    a->os_root, cmd_name(a, "ECHO"),
172*cdd2d676SSascha Wildner 			    subpartition_get_letter(sp),
173*cdd2d676SSascha Wildner 			    capacity_to_string(subpartition_get_capacity(sp)),
174*cdd2d676SSascha Wildner 			    a->tmp);
175*cdd2d676SSascha Wildner 		} else {
176*cdd2d676SSascha Wildner 			command_add(cmds, "%s%s '  %c:\t%s\t%s\t4.2BSD' >>%sinstall.disklabel",
177*cdd2d676SSascha Wildner 			    a->os_root, cmd_name(a, "ECHO"),
178*cdd2d676SSascha Wildner 			    subpartition_get_letter(sp),
179*cdd2d676SSascha Wildner 			    capacity_to_string(subpartition_get_capacity(sp)),
180*cdd2d676SSascha Wildner 			    subpartition_get_letter(sp) == 'a' ? "0" : "*",
181*cdd2d676SSascha Wildner 			    a->tmp);
182*cdd2d676SSascha Wildner 		}
183*cdd2d676SSascha Wildner 	}
184*cdd2d676SSascha Wildner 	if (!copied_original) {
185*cdd2d676SSascha Wildner 		/*
186*cdd2d676SSascha Wildner 		 * Copy the 'c' line from the 'virgin' disklabel,
187*cdd2d676SSascha Wildner 		 * if we haven't yet (less than 2 subpartitions.)
188*cdd2d676SSascha Wildner 		 */
189*cdd2d676SSascha Wildner 		command_add(cmds, "%s%s '^  c:' %sinstall.disklabel.%s >>%sinstall.disklabel",
190*cdd2d676SSascha Wildner 		    a->os_root, cmd_name(a, "GREP"),
191*cdd2d676SSascha Wildner 		    a->tmp,
192*cdd2d676SSascha Wildner 		    slice_get_device_name(storage_get_selected_slice(a->s)),
193*cdd2d676SSascha Wildner 		    a->tmp);
194*cdd2d676SSascha Wildner 	}
195*cdd2d676SSascha Wildner 	temp_file_add(a, "install.disklabel");
196*cdd2d676SSascha Wildner 
197*cdd2d676SSascha Wildner 	/*
198*cdd2d676SSascha Wildner 	 * Label the slice from the disklabel we just wove together.
199*cdd2d676SSascha Wildner 	 */
200*cdd2d676SSascha Wildner 	command_add(cmds, "%s%s -R -B -r %s %sinstall.disklabel",
201*cdd2d676SSascha Wildner 	    a->os_root, cmd_name(a, "DISKLABEL"),
202*cdd2d676SSascha Wildner 	    slice_get_device_name(storage_get_selected_slice(a->s)),
203*cdd2d676SSascha Wildner 	    a->tmp);
204*cdd2d676SSascha Wildner 
205*cdd2d676SSascha Wildner 	/*
206*cdd2d676SSascha Wildner 	 * Create a snapshot of the disklabel we just created
207*cdd2d676SSascha Wildner 	 * for debugging inspection in the log.
208*cdd2d676SSascha Wildner 	 */
209*cdd2d676SSascha Wildner 	command_add(cmds, "%s%s %s",
210*cdd2d676SSascha Wildner 	    a->os_root, cmd_name(a, "DISKLABEL"),
211*cdd2d676SSascha Wildner 	    slice_get_device_name(storage_get_selected_slice(a->s)));
212*cdd2d676SSascha Wildner 
213*cdd2d676SSascha Wildner 	/*
214*cdd2d676SSascha Wildner 	 * Create filesystems on the newly-created subpartitions.
215*cdd2d676SSascha Wildner 	 */
216*cdd2d676SSascha Wildner 	for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
217*cdd2d676SSascha Wildner 	     sp != NULL; sp = subpartition_next(sp)) {
218*cdd2d676SSascha Wildner 		if (subpartition_is_swap(sp) || subpartition_is_mfsbacked(sp))
219*cdd2d676SSascha Wildner 			continue;
220*cdd2d676SSascha Wildner 
221*cdd2d676SSascha Wildner 		/*
222*cdd2d676SSascha Wildner 		 * Ensure that all the needed device nodes exist.
223*cdd2d676SSascha Wildner 		 */
224*cdd2d676SSascha Wildner 		command_add_ensure_dev(a, cmds,
225*cdd2d676SSascha Wildner 		    disk_get_device_name(storage_get_selected_disk(a->s)));
226*cdd2d676SSascha Wildner 		command_add_ensure_dev(a, cmds,
227*cdd2d676SSascha Wildner 		    slice_get_device_name(storage_get_selected_slice(a->s)));
228*cdd2d676SSascha Wildner 		command_add_ensure_dev(a, cmds,
229*cdd2d676SSascha Wildner 		    subpartition_get_device_name(sp));
230*cdd2d676SSascha Wildner 
231*cdd2d676SSascha Wildner 		command_add(cmds, "%s%s%s -b %ld -f %ld %sdev/%s",
232*cdd2d676SSascha Wildner 		    a->os_root, cmd_name(a, "NEWFS"),
233*cdd2d676SSascha Wildner 		    subpartition_is_softupdated(sp) ? " -U" : "",
234*cdd2d676SSascha Wildner 		    subpartition_get_bsize(sp),
235*cdd2d676SSascha Wildner 		    subpartition_get_fsize(sp),
236*cdd2d676SSascha Wildner 		    a->os_root,
237*cdd2d676SSascha Wildner 		    subpartition_get_device_name(sp));
238*cdd2d676SSascha Wildner 	}
239*cdd2d676SSascha Wildner 
240*cdd2d676SSascha Wildner 	result = commands_execute(a, cmds);
241*cdd2d676SSascha Wildner 	commands_free(cmds);
242*cdd2d676SSascha Wildner 	return(result);
243*cdd2d676SSascha Wildner }
244*cdd2d676SSascha Wildner 
245*cdd2d676SSascha Wildner /*
246*cdd2d676SSascha Wildner  * +-------+------------+--------------+-----------------+-----------------+
247*cdd2d676SSascha Wildner  * | Mtpt  | Matt says  | FreeBSD says | I got away with | A tiny system   |
248*cdd2d676SSascha Wildner  * +-------+------------+--------------+-----------------+-----------------+
249*cdd2d676SSascha Wildner  * | /     |       256M |         100M |            256M |             64M |
250*cdd2d676SSascha Wildner  * | swap  |         1G | 2 or 3 * mem |  (4 * mem) 256M |   (1 * mem) 64M |
251*cdd2d676SSascha Wildner  * | /var  |       256M |          50M |            256M |             12M |
252*cdd2d676SSascha Wildner  * | /tmp  |       256M |          --- |            256M |             --- |
253*cdd2d676SSascha Wildner  * | /usr  | [4G to] 8G | (>160M) rest |              5G |            160M |
254*cdd2d676SSascha Wildner  * | /home |       rest |          --- |            3.5G |             --- |
255*cdd2d676SSascha Wildner  * +-------+------------+--------------+-----------------+-----------------+
256*cdd2d676SSascha Wildner  * | total |       10G+ |       ~430M+ |            9.5G |            300M |
257*cdd2d676SSascha Wildner  * +-------+------------+--------------+-----------------+-----------------+
258*cdd2d676SSascha Wildner  */
259*cdd2d676SSascha Wildner 
260*cdd2d676SSascha Wildner static long
261*cdd2d676SSascha Wildner default_capacity(struct storage *s, int mtpt)
262*cdd2d676SSascha Wildner {
263*cdd2d676SSascha Wildner 	unsigned long swap;
264*cdd2d676SSascha Wildner 	unsigned long capacity;
265*cdd2d676SSascha Wildner 
266*cdd2d676SSascha Wildner 	if (mtpt == MTPT_HOME)
267*cdd2d676SSascha Wildner 		return(-1);
268*cdd2d676SSascha Wildner 
269*cdd2d676SSascha Wildner 	capacity = slice_get_capacity(storage_get_selected_slice(s));
270*cdd2d676SSascha Wildner 	swap = 2 * storage_get_memsize(s);
271*cdd2d676SSascha Wildner 	if (storage_get_memsize(s) > (capacity / 2) || capacity < 4096)
272*cdd2d676SSascha Wildner 		swap = storage_get_memsize(s);
273*cdd2d676SSascha Wildner 	if (storage_get_memsize(s) > capacity)
274*cdd2d676SSascha Wildner 		swap = capacity / 2;
275*cdd2d676SSascha Wildner 	if (swap > 8192)
276*cdd2d676SSascha Wildner 		swap = 8192;
277*cdd2d676SSascha Wildner 
278*cdd2d676SSascha Wildner 	if (capacity < DISK_MIN) {
279*cdd2d676SSascha Wildner 		/*
280*cdd2d676SSascha Wildner 		 * For the purposes of this installer:
281*cdd2d676SSascha Wildner 		 * can't be done.  Sorry.
282*cdd2d676SSascha Wildner 		 */
283*cdd2d676SSascha Wildner 		return(-1);
284*cdd2d676SSascha Wildner 	} else if (capacity < 523) {
285*cdd2d676SSascha Wildner 		switch (mtpt) {
286*cdd2d676SSascha Wildner 		case MTPT_ROOT:	return(70);
287*cdd2d676SSascha Wildner 		case MTPT_SWAP: return(swap);
288*cdd2d676SSascha Wildner 		case MTPT_VAR:	return(32);
289*cdd2d676SSascha Wildner 		case MTPT_TMP:	return(32);
290*cdd2d676SSascha Wildner 		case MTPT_USR:	return(174);
291*cdd2d676SSascha Wildner 		}
292*cdd2d676SSascha Wildner 	} else if (capacity < 1024) {
293*cdd2d676SSascha Wildner 		switch (mtpt) {
294*cdd2d676SSascha Wildner 		case MTPT_ROOT:	return(96);
295*cdd2d676SSascha Wildner 		case MTPT_SWAP: return(swap);
296*cdd2d676SSascha Wildner 		case MTPT_VAR:	return(64);
297*cdd2d676SSascha Wildner 		case MTPT_TMP:	return(64);
298*cdd2d676SSascha Wildner 		case MTPT_USR:	return(256);
299*cdd2d676SSascha Wildner 		}
300*cdd2d676SSascha Wildner 	} else if (capacity < 4096) {
301*cdd2d676SSascha Wildner 		switch (mtpt) {
302*cdd2d676SSascha Wildner 		case MTPT_ROOT:	return(128);
303*cdd2d676SSascha Wildner 		case MTPT_SWAP: return(swap);
304*cdd2d676SSascha Wildner 		case MTPT_VAR:	return(128);
305*cdd2d676SSascha Wildner 		case MTPT_TMP:	return(128);
306*cdd2d676SSascha Wildner 		case MTPT_USR:	return(512);
307*cdd2d676SSascha Wildner 		}
308*cdd2d676SSascha Wildner 	} else if (capacity < 10240) {
309*cdd2d676SSascha Wildner 		switch (mtpt) {
310*cdd2d676SSascha Wildner 		case MTPT_ROOT:	return(256);
311*cdd2d676SSascha Wildner 		case MTPT_SWAP: return(swap);
312*cdd2d676SSascha Wildner 		case MTPT_VAR:	return(256);
313*cdd2d676SSascha Wildner 		case MTPT_TMP:	return(256);
314*cdd2d676SSascha Wildner 		case MTPT_USR:	return(3072);
315*cdd2d676SSascha Wildner 		}
316*cdd2d676SSascha Wildner 	} else {
317*cdd2d676SSascha Wildner 		switch (mtpt) {
318*cdd2d676SSascha Wildner 		case MTPT_ROOT:	return(256);
319*cdd2d676SSascha Wildner 		case MTPT_SWAP: return(swap);
320*cdd2d676SSascha Wildner 		case MTPT_VAR:	return(256);
321*cdd2d676SSascha Wildner 		case MTPT_TMP:	return(256);
322*cdd2d676SSascha Wildner 		case MTPT_USR:	return(8192);
323*cdd2d676SSascha Wildner 		}
324*cdd2d676SSascha Wildner 	}
325*cdd2d676SSascha Wildner 	/* shouldn't ever happen */
326*cdd2d676SSascha Wildner 	return(-1);
327*cdd2d676SSascha Wildner }
328*cdd2d676SSascha Wildner 
329*cdd2d676SSascha Wildner static int
330*cdd2d676SSascha Wildner check_capacity(struct i_fn_args *a)
331*cdd2d676SSascha Wildner {
332*cdd2d676SSascha Wildner 	struct subpartition *sp;
333*cdd2d676SSascha Wildner 	unsigned long min_capacity[7] = {70, 0, 8, 0, 174, 0, 0};
334*cdd2d676SSascha Wildner 	unsigned long total_capacity = 0;
335*cdd2d676SSascha Wildner 	int mtpt;
336*cdd2d676SSascha Wildner 
337*cdd2d676SSascha Wildner 	if (subpartition_find(storage_get_selected_slice(a->s), "/usr") == NULL)
338*cdd2d676SSascha Wildner 		min_capacity[MTPT_ROOT] += min_capacity[MTPT_USR];
339*cdd2d676SSascha Wildner 
340*cdd2d676SSascha Wildner 	for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
341*cdd2d676SSascha Wildner 	     sp != NULL; sp = subpartition_next(sp)) {
342*cdd2d676SSascha Wildner 		if (subpartition_get_capacity(sp) == -1)
343*cdd2d676SSascha Wildner 			total_capacity++;
344*cdd2d676SSascha Wildner 		else
345*cdd2d676SSascha Wildner 			total_capacity += subpartition_get_capacity(sp);
346*cdd2d676SSascha Wildner 		for (mtpt = 0; def_mountpt[mtpt] != NULL; mtpt++) {
347*cdd2d676SSascha Wildner 			if (strcmp(subpartition_get_mountpoint(sp), def_mountpt[mtpt]) == 0 &&
348*cdd2d676SSascha Wildner 			    min_capacity[mtpt] > 0 &&
349*cdd2d676SSascha Wildner 			    subpartition_get_capacity(sp) < min_capacity[mtpt]) {
350*cdd2d676SSascha Wildner 				inform(a->c, _("WARNING: the %s subpartition should "
351*cdd2d676SSascha Wildner 				    "be at least %dM in size or you will "
352*cdd2d676SSascha Wildner 				    "risk running out of space during "
353*cdd2d676SSascha Wildner 				    "the installation."),
354*cdd2d676SSascha Wildner 				    subpartition_get_mountpoint(sp), min_capacity[mtpt]);
355*cdd2d676SSascha Wildner 			}
356*cdd2d676SSascha Wildner 		}
357*cdd2d676SSascha Wildner 	}
358*cdd2d676SSascha Wildner 
359*cdd2d676SSascha Wildner 	if (total_capacity > slice_get_capacity(storage_get_selected_slice(a->s))) {
360*cdd2d676SSascha Wildner 		inform(a->c, _("The space allocated to all of your selected "
361*cdd2d676SSascha Wildner 		    "subpartitions (%dM) exceeds the total "
362*cdd2d676SSascha Wildner 		    "capacity of the selected primary partition "
363*cdd2d676SSascha Wildner 		    "(%dM). Remove some subpartitions or choose "
364*cdd2d676SSascha Wildner 		    "a smaller size for them and try again."),
365*cdd2d676SSascha Wildner 		    total_capacity, slice_get_capacity(storage_get_selected_slice(a->s)));
366*cdd2d676SSascha Wildner 		return(0);
367*cdd2d676SSascha Wildner 	}
368*cdd2d676SSascha Wildner 
369*cdd2d676SSascha Wildner 	return(1);
370*cdd2d676SSascha Wildner }
371*cdd2d676SSascha Wildner 
372*cdd2d676SSascha Wildner static int
373*cdd2d676SSascha Wildner check_subpartition_selections(struct dfui_response *r, struct i_fn_args *a)
374*cdd2d676SSascha Wildner {
375*cdd2d676SSascha Wildner 	struct dfui_dataset *ds;
376*cdd2d676SSascha Wildner 	struct dfui_dataset *star_ds = NULL;
377*cdd2d676SSascha Wildner 	struct aura_dict *d;
378*cdd2d676SSascha Wildner 	const char *mountpoint, *capstring;
379*cdd2d676SSascha Wildner 	long capacity = 0;
380*cdd2d676SSascha Wildner 	long bsize, fsize;
381*cdd2d676SSascha Wildner 	int found_root = 0;
382*cdd2d676SSascha Wildner 	int softupdates, mfsbacked;
383*cdd2d676SSascha Wildner 	int valid = 1;
384*cdd2d676SSascha Wildner 
385*cdd2d676SSascha Wildner 	d = aura_dict_new(1, AURA_DICT_LIST);
386*cdd2d676SSascha Wildner 
387*cdd2d676SSascha Wildner 	if ((ds = dfui_response_dataset_get_first(r)) == NULL) {
388*cdd2d676SSascha Wildner 		inform(a->c, _("Please set up at least one subpartition."));
389*cdd2d676SSascha Wildner 		valid = 0;
390*cdd2d676SSascha Wildner 	}
391*cdd2d676SSascha Wildner 
392*cdd2d676SSascha Wildner 	for (ds = dfui_response_dataset_get_first(r); valid && ds != NULL;
393*cdd2d676SSascha Wildner 	    ds = dfui_dataset_get_next(ds)) {
394*cdd2d676SSascha Wildner #ifdef DEBUG
395*cdd2d676SSascha Wildner 		dfui_dataset_dump(ds);
396*cdd2d676SSascha Wildner #endif
397*cdd2d676SSascha Wildner 		mountpoint = dfui_dataset_get_value(ds, "mountpoint");
398*cdd2d676SSascha Wildner 		capstring = dfui_dataset_get_value(ds, "capacity");
399*cdd2d676SSascha Wildner 
400*cdd2d676SSascha Wildner 		if (expert) {
401*cdd2d676SSascha Wildner 			softupdates =
402*cdd2d676SSascha Wildner 			    (strcmp(dfui_dataset_get_value(ds, "softupdates"), "Y") == 0);
403*cdd2d676SSascha Wildner 			fsize = atol(dfui_dataset_get_value(ds, "fsize"));
404*cdd2d676SSascha Wildner 			bsize = atol(dfui_dataset_get_value(ds, "bsize"));
405*cdd2d676SSascha Wildner 			mfsbacked = (strcmp(dfui_dataset_get_value(ds, "mfsbacked"), "Y") == 0);
406*cdd2d676SSascha Wildner 		} else {
407*cdd2d676SSascha Wildner 			softupdates = (strcmp(mountpoint, "/") == 0 ? 0 : 1);
408*cdd2d676SSascha Wildner 			mfsbacked = (strcmp(mountpoint, "/tmp") == 0 ? 0 : 1);
409*cdd2d676SSascha Wildner 			fsize = -1;
410*cdd2d676SSascha Wildner 			bsize = -1;
411*cdd2d676SSascha Wildner 		}
412*cdd2d676SSascha Wildner 
413*cdd2d676SSascha Wildner 		if (aura_dict_exists(d, mountpoint, strlen(mountpoint) + 1)) {
414*cdd2d676SSascha Wildner 			inform(a->c, _("The same mount point cannot be specified "
415*cdd2d676SSascha Wildner 			    "for two different subpartitions."));
416*cdd2d676SSascha Wildner 			valid = 0;
417*cdd2d676SSascha Wildner 		}
418*cdd2d676SSascha Wildner 
419*cdd2d676SSascha Wildner 		if (strcmp(mountpoint, "/") == 0)
420*cdd2d676SSascha Wildner 			found_root = 1;
421*cdd2d676SSascha Wildner 
422*cdd2d676SSascha Wildner 		if (strcmp(capstring, "*") == 0) {
423*cdd2d676SSascha Wildner 			if (star_ds != NULL) {
424*cdd2d676SSascha Wildner 				inform(a->c, _("You cannot have more than one subpartition "
425*cdd2d676SSascha Wildner 				    "with a '*' capacity (meaning 'use the remainder "
426*cdd2d676SSascha Wildner 				    "of the primary partition'.)"));
427*cdd2d676SSascha Wildner 				valid = 0;
428*cdd2d676SSascha Wildner 			} else {
429*cdd2d676SSascha Wildner 				star_ds = ds;
430*cdd2d676SSascha Wildner 			}
431*cdd2d676SSascha Wildner 		}
432*cdd2d676SSascha Wildner 
433*cdd2d676SSascha Wildner 		if (!(!strcasecmp(mountpoint, "swap") || mountpoint[0] == '/')) {
434*cdd2d676SSascha Wildner 			inform(a->c, _("Mount point must be either 'swap', or it must "
435*cdd2d676SSascha Wildner 			    "start with a '/'."));
436*cdd2d676SSascha Wildner 			valid = 0;
437*cdd2d676SSascha Wildner 		}
438*cdd2d676SSascha Wildner 
439*cdd2d676SSascha Wildner 		if (strpbrk(mountpoint, " \\\"'`") != NULL) {
440*cdd2d676SSascha Wildner 			inform(a->c, _("Mount point may not contain the following "
441*cdd2d676SSascha Wildner 			    "characters: blank space, backslash, or "
442*cdd2d676SSascha Wildner 			    "single, double, or back quotes."));
443*cdd2d676SSascha Wildner 			valid = 0;
444*cdd2d676SSascha Wildner 		}
445*cdd2d676SSascha Wildner 
446*cdd2d676SSascha Wildner 		if (strlen(capstring) == 0) {
447*cdd2d676SSascha Wildner 			inform(a->c, _("A capacity must be specified."));
448*cdd2d676SSascha Wildner 			valid = 0;
449*cdd2d676SSascha Wildner 		}
450*cdd2d676SSascha Wildner 
451*cdd2d676SSascha Wildner 		if (!string_to_capacity(capstring, &capacity)) {
452*cdd2d676SSascha Wildner 			inform(a->c, _("Capacity must be either a '*' symbol to indicate "
453*cdd2d676SSascha Wildner 			    "'use the rest of the primary partition', or it "
454*cdd2d676SSascha Wildner 			    "must be a series of decimal digits ending with a "
455*cdd2d676SSascha Wildner 			    "'M' (indicating megabytes) or a 'G' (indicating "
456*cdd2d676SSascha Wildner 			    "gigabytes.)"));
457*cdd2d676SSascha Wildner 			valid = 0;
458*cdd2d676SSascha Wildner 		}
459*cdd2d676SSascha Wildner 
460*cdd2d676SSascha Wildner 		if ((strcasecmp(mountpoint, "swap") == 0) && (capacity > 8192)) {
461*cdd2d676SSascha Wildner 			inform(a->c, _("Swap capacity is limited to 8G."));
462*cdd2d676SSascha Wildner 			valid = 0;
463*cdd2d676SSascha Wildner 		}
464*cdd2d676SSascha Wildner 
465*cdd2d676SSascha Wildner 		/*
466*cdd2d676SSascha Wildner 		 * If we made it through that obstacle course, all is well.
467*cdd2d676SSascha Wildner 		 */
468*cdd2d676SSascha Wildner 
469*cdd2d676SSascha Wildner 		if (valid)
470*cdd2d676SSascha Wildner 			aura_dict_store(d, mountpoint, strlen(mountpoint) + 1, "", 1);
471*cdd2d676SSascha Wildner 	}
472*cdd2d676SSascha Wildner 
473*cdd2d676SSascha Wildner 	if (!found_root) {
474*cdd2d676SSascha Wildner 		inform(a->c, _("You must include a / (root) subpartition."));
475*cdd2d676SSascha Wildner 		valid = 0;
476*cdd2d676SSascha Wildner 	}
477*cdd2d676SSascha Wildner 
478*cdd2d676SSascha Wildner 	if (aura_dict_size(d) > 16) {
479*cdd2d676SSascha Wildner 		inform(a->c, _("You cannot have more than 16 subpartitions "
480*cdd2d676SSascha Wildner 		    "on a single primary partition.  Remove some "
481*cdd2d676SSascha Wildner 		    "and try again."));
482*cdd2d676SSascha Wildner 		valid = 0;
483*cdd2d676SSascha Wildner 	}
484*cdd2d676SSascha Wildner 
485*cdd2d676SSascha Wildner 	aura_dict_free(d);
486*cdd2d676SSascha Wildner 
487*cdd2d676SSascha Wildner 	return(valid);
488*cdd2d676SSascha Wildner }
489*cdd2d676SSascha Wildner 
490*cdd2d676SSascha Wildner static void
491*cdd2d676SSascha Wildner save_subpartition_selections(struct dfui_response *r, struct i_fn_args *a)
492*cdd2d676SSascha Wildner {
493*cdd2d676SSascha Wildner 	struct dfui_dataset *ds;
494*cdd2d676SSascha Wildner 	char mfsbacked;
495*cdd2d676SSascha Wildner 	const char *mountpoint, *capstring;
496*cdd2d676SSascha Wildner 	long capacity;
497*cdd2d676SSascha Wildner 	long bsize, fsize;
498*cdd2d676SSascha Wildner 	int softupdates;
499*cdd2d676SSascha Wildner 	int valid = 1;
500*cdd2d676SSascha Wildner 
501*cdd2d676SSascha Wildner 	subpartitions_free(storage_get_selected_slice(a->s));
502*cdd2d676SSascha Wildner 
503*cdd2d676SSascha Wildner 	for (ds = dfui_response_dataset_get_first(r); valid && ds != NULL;
504*cdd2d676SSascha Wildner 	    ds = dfui_dataset_get_next(ds)) {
505*cdd2d676SSascha Wildner 		mountpoint = dfui_dataset_get_value(ds, "mountpoint");
506*cdd2d676SSascha Wildner 		capstring = dfui_dataset_get_value(ds, "capacity");
507*cdd2d676SSascha Wildner 
508*cdd2d676SSascha Wildner 		if (expert) {
509*cdd2d676SSascha Wildner 			softupdates =
510*cdd2d676SSascha Wildner 			    (strcmp(dfui_dataset_get_value(ds, "softupdates"), "Y") == 0);
511*cdd2d676SSascha Wildner 			fsize = atol(dfui_dataset_get_value(ds, "fsize"));
512*cdd2d676SSascha Wildner 			bsize = atol(dfui_dataset_get_value(ds, "bsize"));
513*cdd2d676SSascha Wildner 			mfsbacked = (strcmp(dfui_dataset_get_value(ds, "mfsbacked"), "Y") == 0);
514*cdd2d676SSascha Wildner 		} else {
515*cdd2d676SSascha Wildner 			softupdates = (strcmp(mountpoint, "/") == 0 ? 0 : 1);
516*cdd2d676SSascha Wildner 			mfsbacked = 0;
517*cdd2d676SSascha Wildner 			fsize = -1;
518*cdd2d676SSascha Wildner 			bsize = -1;
519*cdd2d676SSascha Wildner 		}
520*cdd2d676SSascha Wildner 
521*cdd2d676SSascha Wildner 		if (string_to_capacity(capstring, &capacity)) {
522*cdd2d676SSascha Wildner 			subpartition_new(storage_get_selected_slice(a->s), mountpoint, capacity,
523*cdd2d676SSascha Wildner 			    softupdates, fsize, bsize, mfsbacked);
524*cdd2d676SSascha Wildner 		}
525*cdd2d676SSascha Wildner 	}
526*cdd2d676SSascha Wildner }
527*cdd2d676SSascha Wildner 
528*cdd2d676SSascha Wildner static void
529*cdd2d676SSascha Wildner populate_create_subpartitions_form(struct dfui_form *f, struct i_fn_args *a)
530*cdd2d676SSascha Wildner {
531*cdd2d676SSascha Wildner 	struct subpartition *sp;
532*cdd2d676SSascha Wildner 	struct dfui_dataset *ds;
533*cdd2d676SSascha Wildner 	char temp[32];
534*cdd2d676SSascha Wildner 	int mtpt;
535*cdd2d676SSascha Wildner 	long capacity;
536*cdd2d676SSascha Wildner 
537*cdd2d676SSascha Wildner 	if (slice_subpartition_first(storage_get_selected_slice(a->s)) != NULL) {
538*cdd2d676SSascha Wildner 		/*
539*cdd2d676SSascha Wildner 		 * The user has already given us their subpartition
540*cdd2d676SSascha Wildner 		 * preferences, so use them here.
541*cdd2d676SSascha Wildner 		 */
542*cdd2d676SSascha Wildner 		for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
543*cdd2d676SSascha Wildner 		     sp != NULL; sp = subpartition_next(sp)) {
544*cdd2d676SSascha Wildner 			ds = dfui_dataset_new();
545*cdd2d676SSascha Wildner 			dfui_dataset_celldata_add(ds, "mountpoint",
546*cdd2d676SSascha Wildner 			    subpartition_get_mountpoint(sp));
547*cdd2d676SSascha Wildner 			dfui_dataset_celldata_add(ds, "capacity",
548*cdd2d676SSascha Wildner 			    capacity_to_string(subpartition_get_capacity(sp)));
549*cdd2d676SSascha Wildner 			if (expert) {
550*cdd2d676SSascha Wildner 				dfui_dataset_celldata_add(ds, "softupdates",
551*cdd2d676SSascha Wildner 				    subpartition_is_softupdated(sp) ? "Y" : "N");
552*cdd2d676SSascha Wildner 				dfui_dataset_celldata_add(ds, "mfsbacked",
553*cdd2d676SSascha Wildner 				    subpartition_is_mfsbacked(sp) ? "Y" : "N");
554*cdd2d676SSascha Wildner 				snprintf(temp, 32, "%ld", subpartition_get_fsize(sp));
555*cdd2d676SSascha Wildner 				dfui_dataset_celldata_add(ds, "fsize",
556*cdd2d676SSascha Wildner 				    temp);
557*cdd2d676SSascha Wildner 				snprintf(temp, 32, "%ld", subpartition_get_bsize(sp));
558*cdd2d676SSascha Wildner 				dfui_dataset_celldata_add(ds, "bsize",
559*cdd2d676SSascha Wildner 				    temp);
560*cdd2d676SSascha Wildner 			}
561*cdd2d676SSascha Wildner 			dfui_form_dataset_add(f, ds);
562*cdd2d676SSascha Wildner 		}
563*cdd2d676SSascha Wildner 	} else {
564*cdd2d676SSascha Wildner 		/*
565*cdd2d676SSascha Wildner 		 * Otherwise, populate the form with datasets representing
566*cdd2d676SSascha Wildner 		 * reasonably-calculated defaults.  The defaults are chosen
567*cdd2d676SSascha Wildner 		 * based on the slice's total capacity and the machine's
568*cdd2d676SSascha Wildner 		 * total physical memory (for swap.)
569*cdd2d676SSascha Wildner 		 */
570*cdd2d676SSascha Wildner 		for (mtpt = 0; def_mountpt[mtpt] != NULL; mtpt++) {
571*cdd2d676SSascha Wildner 			capacity = default_capacity(a->s, mtpt);
572*cdd2d676SSascha Wildner 			ds = dfui_dataset_new();
573*cdd2d676SSascha Wildner 			dfui_dataset_celldata_add(ds, "mountpoint",
574*cdd2d676SSascha Wildner 			    def_mountpt[mtpt]);
575*cdd2d676SSascha Wildner 			dfui_dataset_celldata_add(ds, "capacity",
576*cdd2d676SSascha Wildner 			    capacity_to_string(capacity));
577*cdd2d676SSascha Wildner 			if (expert) {
578*cdd2d676SSascha Wildner 				dfui_dataset_celldata_add(ds, "softupdates",
579*cdd2d676SSascha Wildner 				    strcmp(def_mountpt[mtpt], "/") != 0 ? "Y" : "N");
580*cdd2d676SSascha Wildner 				dfui_dataset_celldata_add(ds, "mfsbacked",
581*cdd2d676SSascha Wildner 				    "N");
582*cdd2d676SSascha Wildner 				dfui_dataset_celldata_add(ds, "fsize",
583*cdd2d676SSascha Wildner 				    capacity < 1024 ? "1024" : "2048");
584*cdd2d676SSascha Wildner 				dfui_dataset_celldata_add(ds, "bsize",
585*cdd2d676SSascha Wildner 				    capacity < 1024 ? "8192" : "16384");
586*cdd2d676SSascha Wildner 			}
587*cdd2d676SSascha Wildner 			dfui_form_dataset_add(f, ds);
588*cdd2d676SSascha Wildner 		}
589*cdd2d676SSascha Wildner 	}
590*cdd2d676SSascha Wildner }
591*cdd2d676SSascha Wildner 
592*cdd2d676SSascha Wildner static int
593*cdd2d676SSascha Wildner warn_subpartition_selections(struct i_fn_args *a)
594*cdd2d676SSascha Wildner {
595*cdd2d676SSascha Wildner 	int valid = 0;
596*cdd2d676SSascha Wildner 	struct aura_buffer *omit, *consequences;
597*cdd2d676SSascha Wildner 
598*cdd2d676SSascha Wildner 	omit = aura_buffer_new(2048);
599*cdd2d676SSascha Wildner 	consequences = aura_buffer_new(2048);
600*cdd2d676SSascha Wildner 
601*cdd2d676SSascha Wildner 	valid = check_capacity(a);
602*cdd2d676SSascha Wildner 	if (subpartition_find(storage_get_selected_slice(a->s), "/var") == NULL) {
603*cdd2d676SSascha Wildner 		aura_buffer_cat(omit, "/var ");
604*cdd2d676SSascha Wildner 		aura_buffer_cat(consequences, _("/var will be a plain dir in /\n"));
605*cdd2d676SSascha Wildner 	}
606*cdd2d676SSascha Wildner 	if (subpartition_find(storage_get_selected_slice(a->s), "/usr") == NULL) {
607*cdd2d676SSascha Wildner 		aura_buffer_cat(omit, "/usr ");
608*cdd2d676SSascha Wildner 		aura_buffer_cat(consequences, _("/usr will be a plain dir in /\n"));
609*cdd2d676SSascha Wildner 	}
610*cdd2d676SSascha Wildner         if (subpartition_find(storage_get_selected_slice(a->s), "/tmp") == NULL) {
611*cdd2d676SSascha Wildner                 aura_buffer_cat(omit, "/tmp ");
612*cdd2d676SSascha Wildner 		aura_buffer_cat(consequences, _("/tmp will be symlinked to /var/tmp\n"));
613*cdd2d676SSascha Wildner 	}
614*cdd2d676SSascha Wildner         if (subpartition_find(storage_get_selected_slice(a->s), "/home") == NULL) {
615*cdd2d676SSascha Wildner                 aura_buffer_cat(omit, "/home ");
616*cdd2d676SSascha Wildner 		aura_buffer_cat(consequences, _("/home will be symlinked to /usr/home\n"));
617*cdd2d676SSascha Wildner 	}
618*cdd2d676SSascha Wildner 
619*cdd2d676SSascha Wildner 	if (valid && aura_buffer_len(omit) > 0) {
620*cdd2d676SSascha Wildner 		switch (dfui_be_present_dialog(a->c, _("Really omit?"),
621*cdd2d676SSascha Wildner 		    _("Omit Subpartition(s)|Return to Create Subpartitions"),
622*cdd2d676SSascha Wildner 		    _("You have elected to not have the following "
623*cdd2d676SSascha Wildner 		    "subpartition(s):\n\n%s\n\n"
624*cdd2d676SSascha Wildner 		    "The ramifications of these subpartition(s) being "
625*cdd2d676SSascha Wildner 		    "missing will be:\n\n%s\n"
626*cdd2d676SSascha Wildner 		    "Is this really what you want to do?"),
627*cdd2d676SSascha Wildner 		    aura_buffer_buf(omit), aura_buffer_buf(consequences))) {
628*cdd2d676SSascha Wildner 		case 1:
629*cdd2d676SSascha Wildner 			valid = 1;
630*cdd2d676SSascha Wildner 			break;
631*cdd2d676SSascha Wildner 		case 2:
632*cdd2d676SSascha Wildner 			valid = 0;
633*cdd2d676SSascha Wildner 			break;
634*cdd2d676SSascha Wildner 		default:
635*cdd2d676SSascha Wildner 			abort_backend();
636*cdd2d676SSascha Wildner 		}
637*cdd2d676SSascha Wildner 	}
638*cdd2d676SSascha Wildner 
639*cdd2d676SSascha Wildner 	aura_buffer_free(omit);
640*cdd2d676SSascha Wildner 	aura_buffer_free(consequences);
641*cdd2d676SSascha Wildner 
642*cdd2d676SSascha Wildner 	return(!valid);
643*cdd2d676SSascha Wildner }
644*cdd2d676SSascha Wildner 
645*cdd2d676SSascha Wildner static struct dfui_form *
646*cdd2d676SSascha Wildner make_create_subpartitions_form(struct i_fn_args *a)
647*cdd2d676SSascha Wildner {
648*cdd2d676SSascha Wildner 	struct dfui_field *fi;
649*cdd2d676SSascha Wildner 	struct dfui_form *f;
650*cdd2d676SSascha Wildner 	char msg_buf[1][1024];
651*cdd2d676SSascha Wildner 
652*cdd2d676SSascha Wildner 	snprintf(msg_buf[0], sizeof(msg_buf[0]),
653*cdd2d676SSascha Wildner 	    _("Subpartitions further divide a primary partition for "
654*cdd2d676SSascha Wildner 	    "use with %s.  Some reasons you may want "
655*cdd2d676SSascha Wildner 	    "a set of subpartitions are:\n\n"
656*cdd2d676SSascha Wildner 	    "- you want to restrict how much data can be written "
657*cdd2d676SSascha Wildner 	    "to certain parts of the primary partition, to quell "
658*cdd2d676SSascha Wildner 	    "denial-of-service attacks; and\n"
659*cdd2d676SSascha Wildner 	    "- you want to speed up access to data on the disk."
660*cdd2d676SSascha Wildner 	    ""), OPERATING_SYSTEM_NAME);
661*cdd2d676SSascha Wildner 
662*cdd2d676SSascha Wildner 	f = dfui_form_create(
663*cdd2d676SSascha Wildner 	    "create_subpartitions",
664*cdd2d676SSascha Wildner 	    _("Create Subpartitions"),
665*cdd2d676SSascha Wildner 	    _("Set up the subpartitions (also known as just `partitions' "
666*cdd2d676SSascha Wildner 	    "in BSD tradition) you want to have on this primary "
667*cdd2d676SSascha Wildner 	    "partition.\n\n"
668*cdd2d676SSascha Wildner 	    "For Capacity, use 'M' to indicate megabytes, 'G' to "
669*cdd2d676SSascha Wildner 	    "indicate gigabytes, or a single '*' to indicate "
670*cdd2d676SSascha Wildner 	    "'use the remaining space on the primary partition'."),
671*cdd2d676SSascha Wildner 
672*cdd2d676SSascha Wildner 	    msg_buf[0],
673*cdd2d676SSascha Wildner 
674*cdd2d676SSascha Wildner 	    "p", "special", "dfinstaller_create_subpartitions",
675*cdd2d676SSascha Wildner 	    "p", "minimum_width","64",
676*cdd2d676SSascha Wildner 
677*cdd2d676SSascha Wildner 	    "f", "mountpoint", _("Mountpoint"), "", "",
678*cdd2d676SSascha Wildner 	    "f", "capacity", _("Capacity"), "", "",
679*cdd2d676SSascha Wildner 
680*cdd2d676SSascha Wildner 	    "a", "ok", _("Accept and Create"), "", "",
681*cdd2d676SSascha Wildner 	    "a", "cancel",
682*cdd2d676SSascha Wildner 	    (disk_get_formatted(storage_get_selected_disk(a->s)) ?
683*cdd2d676SSascha Wildner 	    _("Return to Select Disk") :
684*cdd2d676SSascha Wildner 	    _("Return to Select Primary Partition")), "", "",
685*cdd2d676SSascha Wildner 	    "p", "accelerator", "ESC",
686*cdd2d676SSascha Wildner 
687*cdd2d676SSascha Wildner 	    NULL
688*cdd2d676SSascha Wildner 	);
689*cdd2d676SSascha Wildner 
690*cdd2d676SSascha Wildner 	dfui_form_set_multiple(f, 1);
691*cdd2d676SSascha Wildner 	dfui_form_set_extensible(f, 1);
692*cdd2d676SSascha Wildner 
693*cdd2d676SSascha Wildner 	if (expert) {
694*cdd2d676SSascha Wildner 		fi = dfui_form_field_add(f, "softupdates",
695*cdd2d676SSascha Wildner 		    dfui_info_new(_("Softupdates"), "", ""));
696*cdd2d676SSascha Wildner 		dfui_field_property_set(fi, "control", "checkbox");
697*cdd2d676SSascha Wildner 
698*cdd2d676SSascha Wildner 		fi = dfui_form_field_add(f, "mfsbacked",
699*cdd2d676SSascha Wildner 		    dfui_info_new(_("MFS"), "", ""));
700*cdd2d676SSascha Wildner 		dfui_field_property_set(fi, "control", "checkbox");
701*cdd2d676SSascha Wildner 
702*cdd2d676SSascha Wildner 		fi = dfui_form_field_add(f, "fsize",
703*cdd2d676SSascha Wildner 		    dfui_info_new(_("Frag Sz"), "", ""));
704*cdd2d676SSascha Wildner 
705*cdd2d676SSascha Wildner 		fi = dfui_form_field_add(f, "bsize",
706*cdd2d676SSascha Wildner 		    dfui_info_new(_("Block Sz"), "", ""));
707*cdd2d676SSascha Wildner 
708*cdd2d676SSascha Wildner 		dfui_form_action_add(f, "switch",
709*cdd2d676SSascha Wildner 		    dfui_info_new(_("Switch to Normal Mode"), "", ""));
710*cdd2d676SSascha Wildner 	} else {
711*cdd2d676SSascha Wildner 		dfui_form_action_add(f, "switch",
712*cdd2d676SSascha Wildner 		    dfui_info_new(_("Switch to Expert Mode"), "", ""));
713*cdd2d676SSascha Wildner 	}
714*cdd2d676SSascha Wildner 
715*cdd2d676SSascha Wildner 	return(f);
716*cdd2d676SSascha Wildner }
717*cdd2d676SSascha Wildner 
718*cdd2d676SSascha Wildner /*
719*cdd2d676SSascha Wildner  * Returns:
720*cdd2d676SSascha Wildner  *	-1 = the form should be redisplayed
721*cdd2d676SSascha Wildner  *	 0 = failure, function is over
722*cdd2d676SSascha Wildner  *	 1 = success, function is over
723*cdd2d676SSascha Wildner  */
724*cdd2d676SSascha Wildner static int
725*cdd2d676SSascha Wildner show_create_subpartitions_form(struct dfui_form *f, struct i_fn_args *a)
726*cdd2d676SSascha Wildner {
727*cdd2d676SSascha Wildner 	struct dfui_dataset *ds;
728*cdd2d676SSascha Wildner 	struct dfui_response *r;
729*cdd2d676SSascha Wildner 
730*cdd2d676SSascha Wildner 	for (;;) {
731*cdd2d676SSascha Wildner 		if (dfui_form_dataset_get_first(f) == NULL)
732*cdd2d676SSascha Wildner 			populate_create_subpartitions_form(f, a);
733*cdd2d676SSascha Wildner 
734*cdd2d676SSascha Wildner 		if (!dfui_be_present(a->c, f, &r))
735*cdd2d676SSascha Wildner 			abort_backend();
736*cdd2d676SSascha Wildner 
737*cdd2d676SSascha Wildner 		if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
738*cdd2d676SSascha Wildner 			dfui_response_free(r);
739*cdd2d676SSascha Wildner 			return(0);
740*cdd2d676SSascha Wildner 		} else if (strcmp(dfui_response_get_action_id(r), "switch") == 0) {
741*cdd2d676SSascha Wildner 			if (check_subpartition_selections(r, a)) {
742*cdd2d676SSascha Wildner 				save_subpartition_selections(r, a);
743*cdd2d676SSascha Wildner 				expert = expert ? 0 : 1;
744*cdd2d676SSascha Wildner 				dfui_response_free(r);
745*cdd2d676SSascha Wildner 				return(-1);
746*cdd2d676SSascha Wildner 			}
747*cdd2d676SSascha Wildner 		} else {
748*cdd2d676SSascha Wildner 			if (check_subpartition_selections(r, a)) {
749*cdd2d676SSascha Wildner 				save_subpartition_selections(r, a);
750*cdd2d676SSascha Wildner 				if (!warn_subpartition_selections(a)) {
751*cdd2d676SSascha Wildner 					if (!create_subpartitions(a)) {
752*cdd2d676SSascha Wildner 						inform(a->c, _("The subpartitions you chose were "
753*cdd2d676SSascha Wildner 							"not correctly created, and the "
754*cdd2d676SSascha Wildner 							"primary partition may "
755*cdd2d676SSascha Wildner 							"now be in an inconsistent state. "
756*cdd2d676SSascha Wildner 							"We recommend re-formatting it "
757*cdd2d676SSascha Wildner 							"before proceeding."));
758*cdd2d676SSascha Wildner 						dfui_response_free(r);
759*cdd2d676SSascha Wildner 						return(0);
760*cdd2d676SSascha Wildner 					} else {
761*cdd2d676SSascha Wildner 						dfui_response_free(r);
762*cdd2d676SSascha Wildner 						return(1);
763*cdd2d676SSascha Wildner 					}
764*cdd2d676SSascha Wildner 				}
765*cdd2d676SSascha Wildner 			}
766*cdd2d676SSascha Wildner 		}
767*cdd2d676SSascha Wildner 
768*cdd2d676SSascha Wildner 		dfui_form_datasets_free(f);
769*cdd2d676SSascha Wildner 		/* dfui_form_datasets_add_from_response(f, r); */
770*cdd2d676SSascha Wildner 		for (ds = dfui_response_dataset_get_first(r); ds != NULL;
771*cdd2d676SSascha Wildner 		    ds = dfui_dataset_get_next(ds)) {
772*cdd2d676SSascha Wildner 			dfui_form_dataset_add(f, dfui_dataset_dup(ds));
773*cdd2d676SSascha Wildner 		}
774*cdd2d676SSascha Wildner 	}
775*cdd2d676SSascha Wildner }
776*cdd2d676SSascha Wildner 
777*cdd2d676SSascha Wildner /*
778*cdd2d676SSascha Wildner  * fn_create_subpartitions: let the user specify what subpartitions they
779*cdd2d676SSascha Wildner  * want on the disk, how large each should be, and where it should be mounted.
780*cdd2d676SSascha Wildner  */
781*cdd2d676SSascha Wildner void
782*cdd2d676SSascha Wildner fn_create_subpartitions(struct i_fn_args *a)
783*cdd2d676SSascha Wildner {
784*cdd2d676SSascha Wildner 	struct commands *cmds;
785*cdd2d676SSascha Wildner 
786*cdd2d676SSascha Wildner 	cmds = commands_new();
787*cdd2d676SSascha Wildner 
788*cdd2d676SSascha Wildner 	/*
789*cdd2d676SSascha Wildner 	 * Auto-disklabel the slice.
790*cdd2d676SSascha Wildner 	 * NB: one cannot use "/dev/adXsY" here -
791*cdd2d676SSascha Wildner 	 * it must be in the form "adXsY".
792*cdd2d676SSascha Wildner 	 */
793*cdd2d676SSascha Wildner 	if (use_hammer == 1) {
794*cdd2d676SSascha Wildner 		command_add(cmds, "%s%s if=/dev/zero of=/dev/%s bs=32k count=16",
795*cdd2d676SSascha Wildner 		    a->os_root, cmd_name(a, "DD"),
796*cdd2d676SSascha Wildner 		    slice_get_raw_device_name(storage_get_selected_slice(a->s)));
797*cdd2d676SSascha Wildner 		command_add(cmds, "%s%s -B -r -w %s auto",
798*cdd2d676SSascha Wildner 		    a->os_root, cmd_name(a, "DISKLABEL64"),
799*cdd2d676SSascha Wildner 		    slice_get_raw_device_name(storage_get_selected_slice(a->s)));
800*cdd2d676SSascha Wildner 		commands_execute(a, cmds);
801*cdd2d676SSascha Wildner 		commands_free(cmds);
802*cdd2d676SSascha Wildner 		fn_create_subpartitions_hammer(a);
803*cdd2d676SSascha Wildner 	} else {
804*cdd2d676SSascha Wildner 		command_add(cmds, "%s%s if=/dev/zero of=/dev/%s bs=32k count=16",
805*cdd2d676SSascha Wildner 		    a->os_root, cmd_name(a, "DD"),
806*cdd2d676SSascha Wildner 		    slice_get_raw_device_name(storage_get_selected_slice(a->s)));
807*cdd2d676SSascha Wildner 		command_add(cmds, "%s%s -B -r -w %s auto",
808*cdd2d676SSascha Wildner 		    a->os_root, cmd_name(a, "DISKLABEL"),
809*cdd2d676SSascha Wildner 		    slice_get_raw_device_name(storage_get_selected_slice(a->s)));
810*cdd2d676SSascha Wildner 		commands_execute(a, cmds);
811*cdd2d676SSascha Wildner 		commands_free(cmds);
812*cdd2d676SSascha Wildner 		fn_create_subpartitions_ufs(a);
813*cdd2d676SSascha Wildner 	}
814*cdd2d676SSascha Wildner }
815*cdd2d676SSascha Wildner 
816*cdd2d676SSascha Wildner void
817*cdd2d676SSascha Wildner fn_create_subpartitions_ufs(struct i_fn_args *a)
818*cdd2d676SSascha Wildner {
819*cdd2d676SSascha Wildner 	struct dfui_form *f;
820*cdd2d676SSascha Wildner 	int done = 0;
821*cdd2d676SSascha Wildner 
822*cdd2d676SSascha Wildner 	a->result = 0;
823*cdd2d676SSascha Wildner 	while (!done) {
824*cdd2d676SSascha Wildner 		f = make_create_subpartitions_form(a);
825*cdd2d676SSascha Wildner 		switch (show_create_subpartitions_form(f, a)) {
826*cdd2d676SSascha Wildner 		case -1:
827*cdd2d676SSascha Wildner 			done = 0;
828*cdd2d676SSascha Wildner 			break;
829*cdd2d676SSascha Wildner 		case 0:
830*cdd2d676SSascha Wildner 			done = 1;
831*cdd2d676SSascha Wildner 			a->result = 0;
832*cdd2d676SSascha Wildner 			break;
833*cdd2d676SSascha Wildner 		case 1:
834*cdd2d676SSascha Wildner 			done = 1;
835*cdd2d676SSascha Wildner 			a->result = 1;
836*cdd2d676SSascha Wildner 			break;
837*cdd2d676SSascha Wildner 		}
838*cdd2d676SSascha Wildner 		dfui_form_free(f);
839*cdd2d676SSascha Wildner 	}
840*cdd2d676SSascha Wildner }
841