Install a moduli(5) manual page.
[dragonfly.git] / contrib / bsdinstaller-1.1.6 / src / backend / lua / install / 400_select_subparts.lua
1 -- $Id: 400_select_subparts.lua,v 1.24 2005/03/29 13:12:43 den Exp $
2
3 local expert_mode = false
4
5 local datasets_list = nil
6
7 local fillout_missing_expert_values = function()
8         local i, size
9
10         for i in datasets_list do
11                 local dataset = datasets_list[i]
12
13                 if not dataset.softupdates and
14                    not dataset.fsize and not dataset.bsize then
15                         if dataset.mountpoint == "/" then
16                                 dataset.softupdates = "N"
17                         else
18                                 dataset.softupdates = "Y"
19                         end
20
21                         size = StorageDescriptor.parse_capstring(dataset.capstring, -1)
22                         if size and size < (1024 * 1024 * 1024) then
23                                 dataset.fsize = "1024"
24                                 dataset.bsize = "8192"
25                         else
26                                 dataset.fsize = "2048"
27                                 dataset.bsize = "16384"
28                         end
29                 end
30         end
31 end
32
33 local warn_subpartition_selections = function(pd)
34         local omit = ""
35         local consequences = ""
36
37         if not pd:get_subpart_by_mountpoint("/var") then
38                 omit = omit .. "/var "
39                 consequences = consequences ..
40                     _("%s will be a plain dir in %s\n", "/var", "/")
41         end
42
43         if not pd:get_subpart_by_mountpoint("/usr") then
44                 omit = omit .. "/usr "
45                 consequences = consequences ..
46                     _("%s will be a plain dir in %s\n", "/usr", "/")
47         end
48
49         if not pd:get_subpart_by_mountpoint("/tmp") then
50                 omit = omit .. "/tmp "
51                 consequences = consequences ..
52                     _("%s will be symlinked to %s\n", "/tmp", "/var/tmp")
53         end
54
55         if not pd:get_subpart_by_mountpoint("/home") then
56                 omit = omit .. "/home "
57                 consequences = consequences ..
58                     _("%s will be symlinked to %s\n", "/home", "/usr/home")
59         end
60
61         if string.len(omit) > 0 then
62                 local choices = {}
63                 
64                 choices[_("Omit Subpartition(s)")] = true
65                 choices[_("Return to Create Subpartitions")] = false
66
67                 return App.ui:select(_(
68                     "You have elected to not have the following "       ..
69                     "subpartition(s):\n\n%s\n\n"                        ..
70                     "The ramifications of these subpartition(s) being " ..
71                     "missing will be:\n\n%s\n"                          ..
72                     "Is this really what you want to do?",
73                     omit, consequences), choices)
74         else
75                 return true
76         end
77 end
78
79 local validate_subpart_descriptors = function(pd)
80         local spd, k, v
81         local part_size = pd:get_size()
82         local used_size = 0
83         local min_size = {}
84
85         -- XXX this should come from a config file.
86         for k, v in {
87             ["/"]       =  "70M",
88             ["/var"]    =   "8M",
89             ["/usr"]    = "174M"
90         } do
91                 min_size[k] = StorageDescriptor.parse_capstring(v, 0) or 0
92         end
93
94         --
95         -- If the user didn't select a /usr partition, / is going to
96         -- have to hold all that stuff - so make sure it's big enough.
97         --
98         if not pd:get_subpart_by_mountpoint("/usr") then
99                 min_size["/"] = min_size["/"] + min_size["/usr"]
100         end
101
102         for spd in pd:get_subparts() do
103                 local spd_size = spd:get_size()
104                 local mtpt = spd:get_mountpoint()
105                 local min_mt_size = min_size[mtpt]
106
107                 used_size = used_size + spd_size
108
109                 if min_mt_size and spd_size < min_mt_size then
110                         if not App.ui:confirm(_(
111                             "WARNING: the %s subpartition should "      ..
112                             "be at least %s in size or you will "       ..
113                             "risk running out of space during "         ..
114                             "the installation.\n\n"                     ..
115                             "Proceed anyway?",
116                             mtpt,
117                             StorageDescriptor.format_capstring(min_mt_size))) then
118                                 return false
119                         end
120                 end
121         end
122
123         if used_size > part_size then
124                 if not App.ui:confirm(_(
125                     "WARNING: The total number of sectors needed "      ..
126                     "for the requested subpartitions (%d) exceeds the " ..
127                     "number of sectors available in the partition (%d) " ..
128                     "by %d sectors (%s.)\n\n"                           ..
129                     "This is an invalid configuration; we "             ..
130                     "recommend shrinking the size of one or "           ..
131                     "more subpartitions before proceeding.\n\n"         ..
132                     "Proceed anyway?",
133                     used_size, part_size, used_size - part_size,
134                     StorageDescriptor.format_capstring(used_size - part_size))) then
135                         return false
136                 end
137         end
138
139         if used_size < part_size - App.state.max_waste then
140                 if not App.ui:confirm(_(
141                     "Note: the total capacity required "        ..
142                     "for the requested subpartitions (%s) does not make "       ..
143                     "full use of the capacity available in the "        ..
144                     "partition (%s.)  %d sectors (%s) of space will go " ..
145                     "unused.\n\n"                                       ..
146                     "You may wish to expand one or more subpartitions " ..
147                     "before proceeding.\n\n"                            ..
148                     "Proceed anyway?",
149                     StorageDescriptor.format_capstring(used_size),
150                     StorageDescriptor.format_capstring(part_size),
151                     part_size - used_size,
152                     StorageDescriptor.format_capstring(part_size - used_size))) then
153                         return false
154                 end
155         end
156
157         if App.option.enable_crashdumps then
158                 local num_swap_subparts = 0
159                 local num_dumponable = 0
160
161                 for spd in pd:get_subparts() do
162                         if spd:is_swap() then
163                                 num_swap_subparts = num_swap_subparts + 1
164                                 if spd:get_capacity() >= App.state.store:get_ram() then
165                                         num_dumponable = num_dumponable + 1
166                                 end
167                         end
168                 end
169                 
170                 if num_swap_subparts > 0 and num_dumponable == 0 then
171                         if not App.ui:confirm(_(
172                             "Note: none of the swap subpartitions that "        ..
173                             "you have selected are large enough to hold "       ..
174                             "the contents of memory, and thus cannot be "       ..
175                             "used to hold a crash dump (an image of the "       ..
176                             "computers' memory at the time of failure.) "       ..
177                             "Because this complicates troubleshooting, "        ..
178                             "we recommend that you increase the size of "       ..
179                             "one of your swap subpartitions.\n\n"               ..
180                             "Proceed anyway?",
181                             mtpt, min_cap)) then
182                                 return false
183                         end
184                 end
185         end
186
187         return warn_subpartition_selections(pd)
188 end
189
190 --
191 -- Take a list of tables representing the user's choices and
192 -- create a matching set of subpartition descriptors under
193 -- the given partition description from them.  In the process,
194 -- the desired subpartitions are checked for validity.
195 --
196 local create_subpart_descriptors = function(pd, list)
197         local i, letter, dataset
198         local size, offset, fstype
199         local total_size = 0
200         local wildcard_size = false
201
202         pd:clear_subparts()
203
204         offset = 0
205         for i, dataset in list do
206                 if dataset.capstring == "*" then
207                         if wildcard_size then
208                                 App.ui:inform(_(
209                                     "Only one subpartition may have " ..
210                                     "a capacity of '*'."
211                                 ))
212                                 return false
213                         end
214                         wildcard_size = true
215                 end
216                 size = StorageDescriptor.parse_capstring(dataset.capstring, 0)
217                 if not size then
218                         App.ui:inform(_(
219                             "Capacity must either end in 'M' "          ..
220                             "for megabytes, 'G' for gigabytes, "        ..
221                             "or be '*' to indicate 'use all "           ..
222                             "remaining space.'"
223                         ))
224                         return false
225                 end
226                 total_size = total_size + size
227         end
228
229         offset = 0
230         for i, letter in ipairs({"a", "b", "d", "e", "f", "g", "h", "i",
231                                  "j", "k", "l", "m", "n", "o", "p" }) do
232                 if i > table.getn(list) then break end
233                 dataset = list[i]
234
235                 size = StorageDescriptor.parse_capstring(dataset.capstring,
236                     pd:get_size() - total_size)
237
238                 if dataset.mountpoint == "swap" then
239                         fstype = "swap"
240                 else
241                         fstype = "4.2BSD"
242                 end
243
244                 pd:add_subpart(SubpartitionDescriptor.new{
245                     parent = pd,
246                     letter = letter,
247                     size   = size,
248                     offset = offset,
249                     fstype = fstype,
250                     fsize  = tonumber(dataset.fsize),
251                     bsize  = tonumber(dataset.bsize),
252                     mountpoint = dataset.mountpoint
253                 })
254
255                 offset = offset + size
256         end
257
258         return validate_subpart_descriptors(pd)
259 end
260
261 return {
262     name = "select_subparts",
263     title = "Select Subpartitions",
264     action = function(fsm)
265         local part_no, pd
266         local part_actions = {}
267         local i, letter
268
269         if not datasets_list then
270                 datasets_list = App.load_conf("mountpoints")(
271                     App.state.sel_part:get_capacity(),
272                     App.state.storage:get_ram()
273                 )
274         end
275
276         local fields_list = {
277                 {
278                     id = "mountpoint",
279                     name = _("Mountpoint")
280                 },
281                 {
282                     id = "capstring",
283                     name = _("Capacity")
284                 }
285         }
286
287         local actions_list = {
288                 {
289                     id = "ok",
290                     name = _("Accept and Create"),
291                     effect = function()
292                         return fsm:next()
293                     end
294                 },
295                 {
296                     id = "cancel",
297                     name = _("Return to %s", fsm:prev().title),
298                     effect = function()
299                         return fsm:prev()
300                     end
301                 }
302         }
303
304         if expert_mode then
305                 table.insert(fields_list,
306                     {
307                         id = "softupdates",
308                         name = _("Softupdates?"),
309                         control = "checkbox"
310                     }
311                 )
312                 table.insert(fields_list,
313                     {
314                         id = "fsize",
315                         name = _("Frag Size")
316                     }
317                 )
318                 table.insert(fields_list,
319                     {
320                         id = "bsize",
321                         name = _("Block Size")
322                     }
323                 )
324
325                 table.insert(actions_list,
326                     {
327                         id = "switch",
328                         name = _("Switch to Normal Mode"),
329                         effect = function()
330                                 expert_mode = not expert_mode
331                                 return fsm:current()
332                         end
333                     }
334                 )
335         else
336                 table.insert(actions_list,
337                     {
338                         id = "switch",
339                         name = _("Switch to Expert Mode"),
340                         effect = function()
341                                 expert_mode = not expert_mode
342                                 return fsm:current()
343                         end
344                     }
345                 )
346         end
347
348         local response = App.ui:present({
349             id = "select_subpartitions",
350             name = _("Select Subpartitions"),
351             short_desc = _("Set up the subpartitions (also known "      ..
352                 "as just `partitions' in BSD tradition) you want to "   ..
353                 "have on this primary partition.\n\n"                   ..
354                 "For Capacity, use 'M' to indicate megabytes, 'G' to "  ..
355                 "indicate gigabytes, or a single '*' to indicate "      ..
356                 "'use the remaining space on the primary partition'."),
357             long_desc = _("Subpartitions further divide a primary partition for " ..
358                 "use with %s.  Some reasons you may want "              ..
359                 "a set of subpartitions are:\n\n"                       ..
360                 "- you want to restrict how much data can be written "  ..
361                 "to certain parts of the primary partition, to quell "  ..
362                 "denial-of-service attacks; and\n"                      ..
363                 "- you want to speed up access to data on the disk.",
364                 App.os.name),
365             special = "bsdinstaller_create_subpartitions",
366             minimum_width = "64",
367
368             actions = actions_list,
369             fields = fields_list,
370             datasets = datasets_list,
371
372             multiple = "true",
373             extensible = "true"
374         })
375
376         -- remember these subpartition selections in case we come back here.
377         datasets_list = response.datasets
378         fillout_missing_expert_values()
379
380         if response.action_id == "ok" then
381                 if create_subpart_descriptors(App.state.sel_part, datasets_list) then
382                         local cmds = CmdChain.new()
383
384                         App.state.sel_part:cmds_disklabel(cmds)
385                         cmds:execute()
386                 else
387                         return fsm:current()
388                 end
389         end
390
391         return response.result
392     end
393 }