2 -- $Id: Capacity.lua,v 1.76 2005/03/29 21:04:19 cpressey Exp $
3 -- Storage Descriptors (a la libinstaller) in Lua.
5 -- BEGIN lib/storage.lua --
7 local App = require("app")
8 local FileName = require("filename")
14 -- Note: these methods should try to use consistent terminology:
16 -- 'capacity' of an object refers to its capacity in megabytes.
17 -- 'size' of an object refers to its size in blocks or sectors
18 -- (which are assumed to be 512 bytes each.)
19 -- 'capstring' refers to a string which includes a unit suffix:
22 -- '*' to indicate 'use the remaining space on the device'
25 --[[-------------------]]--
26 --[[ StorageDescriptor ]]--
27 --[[-------------------]]--
29 -- This class returns an object which can represent
30 -- the system's data storage capabilities.
32 StorageDescriptor = {}
33 StorageDescriptor.new = function()
34 local disk = {} -- disks in this storage descriptor
35 local ram = 0 -- in megabytes
36 local sd = {} -- instance variable
39 local next_power_of_two = function(n)
43 while i < n and i >= 1 do
54 -- Now set up this object's interface functions
56 -- Look through `dmesg', `atacontrol list', etc, and
57 -- populate disks and ram with values
58 -- that are as accurate and readable as possible.
59 -- XXX not yet fully implemented.
60 sd.survey = function(sd)
66 cmd = App.expand("${root}${SYSCTL} -n hw.physmem")
71 App.log("`" .. cmd .. "` returned: " .. line)
73 ram = next_power_of_two(tonumber(line) / (1024 * 1024))
75 cmd = App.expand("${root}${SYSCTL} -n kern.disks")
80 App.log("`" .. cmd .. "` returned: " .. line)
82 for disk_name in string.gfind(line, "%s*(%w+)") do
83 if not string.find(disk_name, "^md") then
84 disk[disk_name] = DiskDescriptor.new(sd, disk_name)
88 for line in io.lines("/var/run/dmesg.boot") do
89 for disk_name, dd in disk do
91 string.find(line, "^" .. disk_name .. ":%s*(.*)$")
93 dd:set_desc(disk_name .. ": " .. cap)
98 cmd = App.expand("${root}${ATACONTROL} list")
100 line = pty:readline()
102 for disk_name, dd in disk do
104 string.find(line, "^%s*Master:%s*" ..
105 disk_name .. "%s*(%<.*%>)$")
108 string.find(line, "^%s*Slave:%s*" ..
109 disk_name .. "%s*(%<.*%>)$")
112 dd:set_desc(disk_name .. ": " .. cap)
115 line = pty:readline()
120 -- Refresh our view of the storage connected to the
121 -- system, but remember what disk and/or partition
122 -- was selected as well.
123 sd.resurvey = function(sd, sel_disk, sel_part)
124 local sel_disk_name, sel_part_no
127 sel_disk_name = sel_disk:get_name()
131 sel_part_no = sel_part:get_number()
137 sel_disk = sd:get_disk_by_name(sel_disk_name)
139 -- XXX warn that sel disk was lost!
143 if sel_disk and sel_part then
144 sel_part = sel_disk:find_part_by_number(sel_part_no)
146 -- XXX warn that sel part was lost!
150 return sel_disk, sel_part
153 -- Return an iterator which yields the next next
154 -- DiskDescriptor object in this StorageDescriptor
155 -- each time it is called (typically in a for loop.)
156 sd.get_disks = function(sd)
161 for disk_name, dd in disk do
162 table.insert(list, dd)
166 table.sort(list, function(a, b)
167 return a:get_name() < b:get_name()
178 -- Given the name of a disk, return that disk descriptor,
179 -- or nil if no disk by that name was found.
180 sd.get_disk_by_name = function(sd, name)
183 for dd in sd:get_disks() do
184 if dd:get_name() == name then
192 sd.get_disk_count = function(sd)
196 for disk_name, dd in disk do
203 sd.get_ram = function(sd) -- in megabytes
207 sd.get_activated_swap = function(sd) -- in megabytes
210 local found, len, devname, amount
212 pty = Pty.open(App.expand("${root}${SWAPINFO} -k"))
213 line = pty:readline()
215 if not string.find(line, "^Device") then
216 found, len, devname, amount =
217 string.find(line, "^([^%s]+)%s+(%d+)")
218 swap = swap + tonumber(amount)
220 line = pty:readline()
224 return math.floor(swap / 1024)
227 sd.dump = function(sd)
230 print("*** DUMP of StorageDescriptor ***")
231 for disk_name, dd in disk do
240 -- The following global static utility functions in the
241 -- StorageDescriptor class are really human interface functions;
242 -- they might be better placed elsewhere.
246 -- Take a capstring and return a number indicating size in blocks.
247 -- If the capstring is "*", the supplied remainder is returned.
248 -- If the capstring could not be parsed, returns nil.
250 StorageDescriptor.parse_capstring = function(str, remainder)
254 local suffix = string.sub(str, -1, -1)
255 local body = string.sub(str, 1, string.len(str) - 1)
257 if suffix == "G" or suffix == "g" then
258 return math.floor(tonumber(body) * 1024 * 1024 * 2)
259 elseif suffix == "M" or suffix == "m" then
260 return math.floor(tonumber(body) * 1024 * 2)
269 -- Takes a number specifying a size in blocks and
270 -- convert it to a capstring.
272 StorageDescriptor.format_capstring = function(blocks)
273 if blocks >= 1024 * 1024 * 2 then
274 return tostring(math.floor(blocks / (1024 * 1024 * 2) * 100) / 100) .. "G"
276 return tostring(math.floor(blocks / (1024 * 2) * 100) / 100) .. "M"
281 --[[----------------]]--
282 --[[ DiskDescriptor ]]--
283 --[[----------------]]--
286 DiskDescriptor.new = function(parent, name)
287 local dd = {} -- instance variable
288 local part = {} -- private: partitions on this disk
289 local desc = name -- private: description of disk
290 local cyl, head, sec -- private: geometry of disk
291 local touched = false -- private: whether we formatted it
293 -- Set up this object instance's interface functions first:
295 dd.get_parent = function(dd)
299 dd.get_name = function(dd)
303 dd.set_desc = function(dd, new_desc)
305 -- Calculate a score for how well this string describes
306 -- a disk. Reject obviously bogus descriptions (usually
307 -- erroneously harvested from error messages in dmesg.)
309 local calculate_score = function(s)
312 -- In the absence of any good discriminator,
313 -- the longest disk description wins.
314 score = string.len(s)
317 if string.find(s, "%d+MB") then
320 if string.find(s, "%<.*%>") then
323 if string.find(s, "%[%d+%/%d+%/%d+%]") then
327 -- Look for error messages
328 if string.find(s, "resetting") then
335 if calculate_score(new_desc) > calculate_score(desc) then
340 dd.get_desc = function(dd)
344 dd.get_geometry = function(dd)
345 return cyl, head, sec
348 dd.get_device_name = function(dd)
352 dd.get_raw_device_name = function(dd)
353 -- XXX depends on operating system
357 -- Return an iterator which yields the next next
358 -- PartitionDescriptor object in this DiskDescriptor
359 -- each time it is called (typically in a for loop.)
360 dd.get_parts = function(dd)
361 local i, n = 0, table.getn(part)
371 -- Given the number of a partition, return that
372 -- partition descriptor, or nil if not found.
373 dd.get_part_by_number = function(dd, number)
376 for pd in dd:get_parts() do
377 if pd:get_number() == number then
385 dd.get_part_count = function(dd)
386 return table.getn(part)
389 -- return the disk's capacity in megabytes.
390 -- this is actually the sum of the capacities of the
391 -- partitions on this disk.
392 dd.get_capacity = function(dd)
396 for pd in dd:get_parts() do
397 cap = cap + pd:get_capacity()
403 -- return the disk's raw size in sectors.
404 dd.get_raw_size = function(dd)
405 pty = Pty.open(App.expand(
406 "${root}${FDISK} -t -I " ..
407 dd:get_raw_device_name()))
408 line = pty:readline()
410 local found, len, start, size =
411 string.find(line, "start%s*(%d+)%s*,%s*size%s*(%d+)")
414 return tonumber(start) + tonumber(size)
416 line = pty:readline()
423 dd.touch = function(dd)
427 dd.has_been_touched = function(dd)
432 -- Determine whether any subpartition from any partition of this
433 -- disk is mounted somewhere in the filesystem.
435 dd.is_mounted = function(dd)
436 local fs_descs = MountPoints.enumerate()
437 local i, fs_desc, dev_name
439 dev_name = dd:get_device_name()
440 for i, fs_desc in fs_descs do
441 if string.find(fs_desc.device, dev_name, 1, true) then
450 -- Methods to manipulate the contents of this DiskDescriptor.
453 dd.clear_parts = function(dd)
457 dd.add_part = function(dd, pd)
458 part[pd:get_number()] = pd
463 -- Methods to add appropriate commands to CmdChains.
466 -- Commands to ensure this device exists.
467 dd.cmds_ensure_dev = function(dd, cmds)
469 cmdline = "cd ${root}dev && ${root}${TEST_DEV} ${dev} || " ..
470 "${root}${SH} MAKEDEV ${dev}",
472 dev = FileName.basename(dd:get_device_name())
477 -- Commands to format this disk.
478 dd.cmds_format = function(dd, cmds)
479 dd:cmds_ensure_dev(cmds)
482 -- Currently you need to pass 'yes' to OpenBSD's fdisk to
483 -- be able to do these. (This is a shot in the dark:)
485 if App.os.name == "OpenBSD" then
486 cmds:add("${root}${ECHO} 'yes\nyes\nyes\n' | " ..
487 "${root}${FDISK} -I " ..
488 dd:get_raw_device_name())
489 cmds:add("${root}${ECHO} 'yes\nyes\nyes\n' | " ..
490 "${root}${FDISK} -B " ..
491 dd:get_raw_device_name())
493 cmds:add("${root}${FDISK} -I " ..
494 dd:get_raw_device_name())
495 cmds:add("${root}${YES} | ${root}${FDISK} -B " ..
496 dd:get_raw_device_name())
500 -- Commands to partition this disk.
501 dd.cmds_partition = function(dd, cmds)
504 local cyl, head, sec = dd:get_geometry()
506 dd:cmds_ensure_dev(cmds)
509 cmdline = "${root}${ECHO} 'g c${cyl} h${head} s${sec}' >${tmp}new.fdisk",
519 local sysid, start, size = 0, 0, 0
521 pd = dd:get_part_by_number(i)
523 sysid = pd:get_sysid()
524 start = pd:get_start()
526 if pd:is_active() then
527 active_part_no = pd:get_number()
532 cmdline = "${root}${ECHO} 'p ${number} ${sysid} ${start} ${size}' >>${tmp}new.fdisk",
544 if active_part_no then
546 cmdline = "${root}${ECHO} 'a ${number}' >>${tmp}new.fdisk",
548 number = active_part_no
553 cmds:add("${root}${CAT} ${tmp}new.fdisk")
555 App.register_tmpfile("new.fdisk")
558 -- Execute the fdisk script.
560 cmds:add("${root}${FDISK} -v -f ${tmp}new.fdisk " ..
561 dd:get_raw_device_name())
564 dd.cmds_install_bootblock = function(dd, cmds, packet_mode)
571 cmdline = "${root}${BOOT0CFG} -B " ..
572 o .. dd:get_raw_device_name(),
573 failure = CmdChain.FAILURE_WARN,
577 cmdline = "${root}${BOOT0CFG} -v " ..
578 dd:get_raw_device_name(),
579 failure = CmdChain.FAILURE_WARN,
585 dd.cmds_wipe_start = function(dd, cmds)
586 dd:cmds_ensure_dev(cmds)
587 cmds:add("${root}${DD} if=${root}dev/zero of=${root}dev/" ..
588 dd:get_raw_device_name() .. " bs=32k count=16")
591 dd.dump = function(dd)
594 print("\t" .. name .. ": " .. cyl .. "/" .. head .. "/" .. sec .. ": " .. desc)
595 for part_no in part do
600 -- 'Constructor' - initialize our private state.
601 -- Try to find out what we can about ourselves from fdisk.
603 local pty, line, found, len
605 -- Get the geometry from 'fdisk'.
606 pty = Pty.open(App.expand("${root}${FDISK} " .. name))
607 line = pty:readline()
608 while line and not found do
609 found = string.find(line, "^%s*parameters to be used for BIOS")
610 line = pty:readline()
614 found, len, cyl, head, sec =
615 string.find(line, "^%s*cylinders=(%d+)%s*heads=(%d+)%s*" ..
616 "sectors/track=(%d+)")
618 head = tonumber(head)
624 App.log("Warning! Could not determine geometry of disk " .. name .. "!")
628 App.log("New Disk: " .. name .. ": " .. cyl .. "/" .. head .. "/" .. sec)
630 -- Get the partitions from 'fdisk -s'.
631 pty = Pty.open(App.expand("${root}${FDISK} -s " .. name))
632 line = pty:readline() -- geometry - we already have it
633 line = pty:readline() -- headings, just ignore
634 line = pty:readline()
636 local part_no, start, size, sysid, flags
637 found, len, part_no, start, size, sysid, flags =
638 string.find(line, "^%s*(%d+):%s*(%d+)%s*(%d+)" ..
639 "%s*0x(%x+)%s*0x(%x+)%s*$")
641 part_no = tonumber(part_no)
642 part[part_no] = PartitionDescriptor.new{
645 start = tonumber(start),
646 size = tonumber(size),
647 sysid = tonumber(sysid, 16),
648 flags = tonumber(flags, 16)
651 line = pty:readline()
658 --[[---------------------]]--
659 --[[ PartitionDescriptor ]]--
660 --[[---------------------]]--
662 PartitionDescriptor = {}
663 PartitionDescriptor.new = function(params)
664 local pd = {} -- instance variable
665 local subpart = {} -- subpartitions on this partition
667 local parent = assert(params.parent)
668 local number = assert(params.number)
669 local start = assert(params.start)
670 local size = assert(params.size)
671 local sysid = assert(params.sysid)
672 local flags = params.flags
673 if params.active ~= nil then
674 if params.active then
680 assert(type(flags) == "number")
682 -- First set up this object's interface functions
684 pd.get_parent = function(pd)
688 pd.get_number = function(pd)
692 pd.get_params = function(pd)
693 return start, size, sysid, flags
696 pd.get_start = function(pd)
700 pd.get_size = function(pd)
704 pd.get_sysid = function(pd)
708 pd.get_flags = function(pd)
712 -- 'size' is the partition size, in blocks.
713 -- return the partition's capacity in megabytes.
714 pd.get_capacity = function(pd)
715 return math.floor(size / 2048)
718 pd.is_active = function(pd)
719 return Bitwise.bw_and(flags, 256) == 256
722 pd.get_desc = function(pd)
723 return tostring(number) .. ": " ..
724 tostring(pd:get_capacity()) .. "M (" ..
725 tostring(start) .. "-" .. tostring(start + size) ..
729 pd.get_device_name = function(pd)
730 return parent.get_name() .. "s" .. number
733 pd.get_raw_device_name = function(pd)
734 -- XXX depends on operating system
735 return parent.get_name() .. "s" .. number -- .. "c"
738 pd.get_activated_swap = function(pd) -- in megabytes
741 local found, len, devname, amount
743 pty = Pty.open(App.expand("${root}${SWAPINFO} -k"))
744 line = pty:readline()
746 if not string.find(line, "^Device") then
747 found, len, devname, amount =
748 string.find(line, "^([^%s]+)%s+(%d+)")
749 if string.find(devname, pd:get_device_name()) then
750 swap = swap + tonumber(amount)
753 line = pty:readline()
757 return math.floor(swap / 1024)
760 -- Return an iterator which yields the next next
761 -- PartitionDescriptor object in this DiskDescriptor
762 -- each time it is called (typically in a for loop.)
763 pd.get_subparts = function(pd)
768 for letter, spd in subpart do
769 table.insert(list, spd)
772 table.sort(list, function(a, b)
773 -- not sure why we ever get a nil here, but we do:
774 if not a and not b then return false end
776 return a:get_letter() < b:get_letter()
789 pd.clear_subparts = function(pd)
793 pd.add_subpart = function(pd, spd)
794 subpart[spd:get_letter()] = spd
795 -- spd:set_parent(pd)
798 pd.get_subpart_by_letter = function(pd, letter)
799 return subpart[letter]
802 pd.get_subpart_by_mountpoint = function(pd, mountpoint)
805 for letter, spd in subpart do
806 if spd:get_mountpoint() == mountpoint then
814 pd.get_subpart_by_device_name = function(pd, device_name)
817 -- Strip any leading /dev/ or whatever.
818 device_name = FileName.basename(device_name)
820 for letter, spd in subpart do
821 if spd:get_device_name() == device_name then
830 -- Determine whether any subpartition of this
831 -- partition is mounted somewhere in the filesystem.
833 pd.is_mounted = function(pd)
834 local fs_descs = MountPoints.enumerate()
835 local i, fs_desc, dev_name
837 dev_name = pd:get_device_name()
838 for i, fs_desc in fs_descs do
839 if string.find(fs_desc.device, dev_name, 1, true) then
848 -- Methods to add appropriate commands to CmdChains.
851 -- Commands to ensure this device exists.
852 pd.cmds_ensure_dev = function(pd, cmds)
854 cmdline = "cd ${root}dev && ${root}${TEST_DEV} ${dev} || " ..
855 "${root}${SH} MAKEDEV ${dev}",
857 dev = FileName.basename(pd:get_device_name())
862 -- Commands to format this partition.
863 pd.cmds_format = function(pd, cmds)
864 pd:cmds_ensure_dev(cmds)
866 -- The information in parent NEEDS to be accurate here!
867 -- Presumably we just did a survey_storage() recently.
870 -- Set the slice's sysid to 165.
873 local cyl, head, sec = parent:get_geometry()
874 local start, size, sysid, flags = pd:get_params()
876 cmds:set_replacements{
880 number = pd:get_number(),
884 dev = pd:get_raw_device_name(),
885 parent_dev = parent:get_raw_device_name()
889 "${root}${ECHO} 'g c${cyl} h${head} s${sec}' >${tmp}new.fdisk",
890 "${root}${ECHO} 'p ${number} ${sysid} ${start} ${size}' >>${tmp}new.fdisk"
893 if pd:is_active() then
894 cmds:add("${root}${ECHO} 'a ${number}' >>${tmp}new.fdisk")
897 App.register_tmpfile("new.fdisk")
900 -- Dump the fdisk script to the log for debugging.
901 -- Execute the fdisk script
902 -- Auto-disklabel the slice.
903 -- Remove any old disklabel that might be hanging around.
906 "${root}${CAT} ${tmp}new.fdisk",
907 "${root}${FDISK} -v -f ${tmp}new.fdisk ${parent_dev}",
908 "${root}${DISKLABEL} -B -r -w ${dev} auto",
909 "${root}${RM} -f ${tmp}install.disklabel.${parent_dev}"
913 pd.cmds_wipe_start = function(pd, cmds)
914 pd:cmds_ensure_dev(cmds)
916 "${root}${DD} if=${root}dev/zero of=${root}dev/" ..
917 pd:get_raw_device_name() .. " bs=32k count=16"
921 pd.cmds_install_bootstrap = function(pd, cmds)
922 pd:cmds_ensure_dev(cmds)
924 -- NB: one cannot use "/dev/adXsY" here -
925 -- it must be in the form "adXsY".
928 "${root}${DISKLABEL} -B " ..
929 pd:get_raw_device_name()
934 pd.cmds_disklabel = function(pd, cmds)
935 -- Disklabel the given partition with the
936 -- subpartitions attached to it.
939 if App.os.name == "DragonFly" then
943 cmds:set_replacements{
944 part = pd:get_device_name(),
945 num_parts = tostring(num_parts)
948 if not FileName.is_file(App.dir.tmp .. "install.disklabel" .. pd:get_device_name()) then
950 -- Get a copy of the 'virgin' disklabel.
951 -- XXX It might make more sense for this to
952 -- happen right after format_slice() instead.
954 cmds:add("${root}${DISKLABEL} -r ${part} >${tmp}install.disklabel.${part}")
958 -- Weave together a new disklabel out the of the 'virgin'
959 -- disklabel, and the user's subpartition choices.
963 -- Take everything from the 'virgin' disklabel up until the
964 -- '8 or 16 partitions' line, which looks like:
966 -- 8 or 16 partitions:
967 -- # size offset fstype [fsize bsize bps/cpg]
968 -- c: 2128833 0 unused 0 0 # (Cyl. 0 - 2111*)
972 "${root}${AWK} '$2==\"partitions:\" || cut { cut = 1 } !cut { print $0 }' " ..
973 "<${tmp}install.disklabel.${part} >${tmp}install.disklabel",
974 "${root}${ECHO} '${num_parts} partitions:' >>${tmp}install.disklabel",
975 "${root}${ECHO} '# size offset fstype [fsize bsize bps/cpg]' " ..
976 ">>${tmp}install.disklabel"
980 -- Write a line for each subpartition the user wants.
984 local copied_original = false
986 for spd in pd:get_subparts() do
987 if spd:get_letter() > "c" and not copied_original then
989 -- Copy the 'c' line from the 'virgin' disklabel.
991 cmds:add("${root}${GREP} '^ c:' ${tmp}install.disklabel.${part} " ..
992 ">>${tmp}install.disklabel")
993 copied_original = true
996 cmds:set_replacements{
997 letter = spd:get_letter(),
998 fsize = spd:get_fsize(),
999 bsize = spd:get_bsize()
1002 if spd:get_letter() == "a" then
1003 cmds:set_replacements{ offset = "0" }
1005 cmds:set_replacements{ offset = "*" }
1007 if spd:get_size() == -1 then
1008 cmds:set_replacements{ size = "*" }
1010 cmds:set_replacements{ size = tostring(spd:get_size()) }
1013 if spd:is_swap() then
1014 cmds:add("${root}${ECHO} ' ${letter}:\t${size}\t*\tswap' >>${tmp}install.disklabel")
1016 cmds:add("${root}${ECHO} ' ${letter}:\t${size}\t${offset}\t4.2BSD\t${fsize}\t${bsize}\t99' >>${tmp}install.disklabel")
1020 if not copied_original then
1022 -- Copy the 'c' line from the 'virgin' disklabel,
1023 -- if we haven't yet (less than 2 subpartitions.)
1025 cmds:add("${root}${GREP} '^ c:' ${tmp}install.disklabel.${part} >>${tmp}install.disklabel")
1028 App.register_tmpfile("install.disklabel")
1031 -- Label the slice from the disklabel we just wove together.
1033 -- Then create a snapshot of the disklabel we just created
1034 -- for debugging inspection in the log.
1037 "${root}${DISKLABEL} -R -B -r ${part} ${tmp}install.disklabel",
1038 "${root}${DISKLABEL} ${part}"
1042 -- Create filesystems on the newly-created subpartitions.
1044 pd:get_parent():cmds_ensure_dev(cmds)
1045 pd:cmds_ensure_dev(cmds)
1047 for spd in pd:get_subparts() do
1048 if not spd:is_swap() then
1049 spd:cmds_ensure_dev(cmds)
1051 if spd:is_softupdated() then
1052 cmds:add("${root}${NEWFS} -U ${root}dev/" ..
1053 spd:get_device_name())
1055 cmds:add("${root}${NEWFS} ${root}dev/" ..
1056 spd:get_device_name())
1062 pd.cmds_write_fstab = function(pd, cmds, filename)
1063 -- Write a new fstab for the given partition
1064 -- to the given filename.
1066 if not filename then
1067 filename = "${root}mnt/etc/fstab"
1070 cmds:set_replacements{
1071 header = "# Device\t\tMountpoint\tFStype\tOptions\t\tDump\tPass#",
1072 procline = "proc\t\t\t/proc\t\tprocfs\trw\t\t0\t0",
1075 filename = App.expand(filename)
1078 cmds:add("${root}${ECHO} '${header}' >${filename}")
1080 for spd in pd:get_subparts() do
1081 cmds:set_replacements{
1082 device = spd:get_device_name(),
1083 mountpoint = spd:get_mountpoint()
1086 if spd:get_mountpoint() == "/" then
1087 cmds:add("${root}${ECHO} '/dev/${device}\t\t${mountpoint}\t\tufs\trw\t\t1\t1' >>${filename}")
1088 elseif spd:is_swap() then
1089 cmds:add("${root}${ECHO} '/dev/${device}\t\tnone\t\tswap\tsw\t\t0\t0' >>${filename}")
1091 cmds:add("${root}${ECHO} '/dev/${device}\t\t${mountpoint}\t\tufs\trw\t\t2\t2' >>${filename}")
1095 cmds:add("${root}${ECHO} '${procline}' >>${filename}")
1098 pd.dump = function(pd)
1101 print("\t\tPartition " .. number .. ": " ..
1102 start .. "," .. size .. ":" .. sysid .. "/" .. flags)
1103 for spd in pd:get_subparts() do
1108 App.log("New Partition: " .. number .. ": " ..
1109 start .. "," .. size .. ":" .. sysid .. "/" .. flags)
1111 -- 'Constructor' - initialize this object's state.
1112 -- If this looks like a BSD slice, try to probe it with
1113 -- disklabel to get an idea of the subpartitions on it.
1115 local pty, line, found, len
1116 local letter, size, offset, fstype, fsize, bsize
1118 if sysid == 165 then
1119 pty = Pty.open(App.expand("${root}${DISKLABEL} " .. parent:get_name() ..
1121 line = pty:readline()
1123 while line and not found do
1124 found = string.find(line, "^%d+%s+partitions:")
1125 line = pty:readline()
1129 found, len, letter, size, offset, fstype,
1130 fsize, bsize = string.find(line,
1131 "^%s*(%a):%s*(%d+)%s*(%d+)%s*([^%s]+)")
1134 if fstype == "4.2BSD" then
1135 found, len, letter, size,
1136 offset, fstype, fsize,
1137 bsize = string.find(line,
1138 "^%s*(%a):%s*(%d+)%s*" ..
1139 "(%d+)%s*([^%s]+)%s*" ..
1143 SubpartitionDescriptor.new{
1153 line = pty:readline()
1163 --[[------------------------]]--
1164 --[[ SubpartitionDescriptor ]]--
1165 --[[------------------------]]--
1167 SubpartitionDescriptor = {}
1168 SubpartitionDescriptor.new = function(params)
1169 local spd = {} -- instance variable
1171 local parent = assert(params.parent)
1172 local letter = assert(params.letter)
1173 local size = assert(params.size)
1174 local offset = assert(params.offset)
1175 local fstype = assert(params.fstype)
1176 local fsize = assert(params.fsize)
1177 local bsize = assert(params.bsize)
1178 local mountpoint = params.mountpoint
1180 -- Now set up this object's interface functions
1182 spd.get_parent = function(spd)
1186 spd.get_letter = function(spd)
1190 spd.set_mountpoint = function(spd, new_mountpoint)
1191 mountpoint = new_mountpoint
1194 spd.get_mountpoint = function(spd)
1198 spd.get_fstype = function(spd)
1202 spd.get_device_name = function(spd)
1203 return parent.get_parent().get_name() ..
1204 "s" .. parent.get_number() .. letter
1207 spd.get_raw_device_name = function(spd)
1208 -- XXX depends on operating system
1209 return parent.get_parent().get_name() ..
1210 "s" .. parent.get_number() .. letter
1213 spd.get_capacity = function(spd) -- in megabytes
1214 return math.floor(size / 2048)
1217 spd.get_size = function(spd) -- in sectors
1221 spd.get_fsize = function(spd)
1225 spd.get_bsize = function(spd)
1229 spd.is_swap = function(spd)
1230 return fstype == "swap"
1233 spd.is_softupdated = function(spd)
1234 -- XXX this should be a property
1235 return mountpoint ~= "/"
1238 spd.dump = function(pd)
1239 print("\t\t\t" .. letter .. ": " .. offset .. "," .. size ..
1240 ": " .. fstype .. " -> " .. mountpoint)
1243 -- Commands to ensure this device exists.
1244 spd.cmds_ensure_dev = function(spd, cmds)
1246 cmdline = "cd ${root}dev && ${root}${TEST_DEV} ${dev} || " ..
1247 "${root}${SH} MAKEDEV ${dev}",
1249 dev = FileName.basename(spd:get_device_name())
1258 App.log("New Subpartition on " .. parent:get_device_name() .. ": " ..
1259 letter .. ": " .. offset .. "," .. size .. ": " .. fstype ..
1260 " F=" .. fsize .. ", B=" .. bsize)
1265 -- END of lib/storage.lua --