1 (* 'df' command for virtual domains.
2 (C) Copyright 2007 Richard W.M. Jones, Red Hat Inc.
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version,
9 with the OCaml linking exception described in ../COPYING.LIB.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 Support for EXT2/EXT3 filesystems.
30 let ( +* ) = Int32.add
31 let ( -* ) = Int32.sub
32 let ( ** ) = Int32.mul
33 let ( /* ) = Int32.div
35 (* The fields in an ext2/3 superblock. *)
37 s_inodes_count : int32;
38 s_blocks_count : int32;
39 s_r_blocks_count : int32;
40 s_free_blocks_count : int32;
41 s_free_inodes_count : int32;
42 s_first_data_block : int32;
43 s_log_block_size : int32;
44 s_log_frag_size : int32;
45 s_blocks_per_group : int32;
46 s_frags_per_group : int32;
47 s_inodes_per_group : int32;
51 s_max_mnt_count : int;
54 s_minor_rev_level : int;
56 s_checkinterval : int32;
63 s_block_group_nr : int;
64 s_feature_compat : int32;
65 s_feature_incompat : int32;
66 s_feature_ro_compat : int32;
68 s_volume_name : string;
69 s_last_mounted : string;
70 s_algorithm_usage_bitmap : int32;
71 s_prealloc_blocks : int;
72 s_prealloc_dir_blocks : int;
73 s_reserved_gdt_blocks : int;
74 s_journal_uuid : string;
75 s_journal_inum : int32;
76 s_journal_dev : int32;
77 s_last_orphan : int32;
82 s_def_hash_version : int;
83 s_reserved_char_pad : int;
84 s_reserved_word_pad : int;
85 s_default_mount_opts : int32;
86 s_first_meta_bg : int32;
88 (* Computed fields, don't appear in superblock: *)
93 (* Private data functions. *)
94 let attach_private_data, get_private_data =
95 private_data_functions (fun {fs_cb = {fs_cb_uq = u}} -> u)
98 let superblock_offset = ~^1024
99 let superblock_len = ~^1024
101 (* Parse ext2/3 superblock and return a big structure containing
102 * all the fields. Also there are some extra fields which don't
103 * appear in the superblock itself, but are computed from other fields.
105 * If the device doesn't contain a superblock, raises Not_found.
107 let parse_ext2_sb dev =
108 (* Load the superblock. *)
109 let bits = dev#read_bitstring superblock_offset superblock_len in
111 (* The structure is straight from /usr/include/linux/ext3_fs.h *)
113 | { s_inodes_count : 32 : littleendian; (* Inodes count *)
114 s_blocks_count : 32 : littleendian; (* Blocks count *)
115 s_r_blocks_count : 32 : littleendian; (* Reserved blocks count *)
116 s_free_blocks_count : 32 : littleendian; (* Free blocks count *)
117 s_free_inodes_count : 32 : littleendian; (* Free inodes count *)
118 s_first_data_block : 32 : littleendian; (* First Data Block *)
119 s_log_block_size : 32 : littleendian; (* Block size *)
120 s_log_frag_size : 32 : littleendian; (* Fragment size *)
121 s_blocks_per_group : 32 : littleendian; (* # Blocks per group *)
122 s_frags_per_group : 32 : littleendian; (* # Fragments per group *)
123 s_inodes_per_group : 32 : littleendian; (* # Inodes per group *)
124 s_mtime : 32 : littleendian; (* Mount time *)
125 s_wtime : 32 : littleendian; (* Write time *)
126 s_mnt_count : 16 : littleendian; (* Mount count *)
127 s_max_mnt_count : 16 : littleendian; (* Maximal mount count *)
128 0xef53 : 16 : littleendian; (* Magic signature *)
129 s_state : 16 : littleendian; (* File system state *)
130 s_errors : 16 : littleendian; (* Behaviour when detecting errors *)
131 s_minor_rev_level : 16 : littleendian; (* minor revision level *)
132 s_lastcheck : 32 : littleendian; (* time of last check *)
133 s_checkinterval : 32 : littleendian; (* max. time between checks *)
134 s_creator_os : 32 : littleendian; (* OS *)
135 s_rev_level : 32 : littleendian; (* Revision level *)
136 s_def_resuid : 16 : littleendian; (* Default uid for reserved blocks *)
137 s_def_resgid : 16 : littleendian; (* Default gid for reserved blocks *)
138 s_first_ino : 32 : littleendian; (* First non-reserved inode *)
139 s_inode_size : 16 : littleendian; (* size of inode structure *)
140 s_block_group_nr : 16 : littleendian; (* block group # of this superblock *)
141 s_feature_compat : 32 : littleendian; (* compatible feature set *)
142 s_feature_incompat : 32 : littleendian; (* incompatible feature set *)
143 s_feature_ro_compat : 32 : littleendian; (* readonly-compatible feature set *)
144 s_uuid : 128 : string; (* 128-bit uuid for volume *)
145 s_volume_name : 128 : string; (* volume name *)
146 s_last_mounted : 512 : string; (* directory where last mounted *)
147 s_algorithm_usage_bitmap : 32 : littleendian; (* For compression *)
148 s_prealloc_blocks : 8; (* Nr of blocks to try to preallocate*)
149 s_prealloc_dir_blocks : 8; (* Nr to preallocate for dirs *)
150 s_reserved_gdt_blocks : 16 : littleendian;(* Per group desc for online growth *)
151 s_journal_uuid : 128 : string; (* uuid of journal superblock *)
152 s_journal_inum : 32 : littleendian; (* inode number of journal file *)
153 s_journal_dev : 32 : littleendian; (* device number of journal file *)
154 s_last_orphan : 32 : littleendian; (* start of list of inodes to delete *)
155 s_hash_seed0 : 32 : littleendian; (* HTREE hash seed *)
156 s_hash_seed1 : 32 : littleendian;
157 s_hash_seed2 : 32 : littleendian;
158 s_hash_seed3 : 32 : littleendian;
159 s_def_hash_version : 8; (* Default hash version to use *)
160 s_reserved_char_pad : 8;
161 s_reserved_word_pad : 16 : littleendian;
162 s_default_mount_opts : 32 : littleendian;
163 s_first_meta_bg : 32 : littleendian } -> (* First metablock block group *)
165 (* Work out the block size in bytes. *)
166 let block_size = ~^1024 <^< Int32.to_int s_log_block_size in
168 (* Number of groups. *)
171 (s_blocks_count -* s_first_data_block -* 1l)
172 /* s_blocks_per_group +* 1l
175 { s_inodes_count = s_inodes_count;
176 s_blocks_count = s_blocks_count;
177 s_r_blocks_count = s_r_blocks_count;
178 s_free_blocks_count = s_free_blocks_count;
179 s_free_inodes_count = s_free_inodes_count;
180 s_first_data_block = s_first_data_block;
181 s_log_block_size = s_log_block_size;
182 s_log_frag_size = s_log_frag_size;
183 s_blocks_per_group = s_blocks_per_group;
184 s_frags_per_group = s_frags_per_group;
185 s_inodes_per_group = s_inodes_per_group;
188 s_mnt_count = s_mnt_count;
189 s_max_mnt_count = s_max_mnt_count;
192 s_minor_rev_level = s_minor_rev_level;
193 s_lastcheck = s_lastcheck;
194 s_checkinterval = s_checkinterval;
195 s_creator_os = s_creator_os;
196 s_rev_level = s_rev_level;
197 s_def_resuid = s_def_resuid;
198 s_def_resgid = s_def_resgid;
199 s_first_ino = s_first_ino;
200 s_inode_size = s_inode_size;
201 s_block_group_nr = s_block_group_nr;
202 s_feature_compat = s_feature_compat;
203 s_feature_incompat = s_feature_incompat;
204 s_feature_ro_compat = s_feature_ro_compat;
206 s_volume_name = s_volume_name;
207 s_last_mounted = s_last_mounted;
208 s_algorithm_usage_bitmap = s_algorithm_usage_bitmap;
209 s_prealloc_blocks = s_prealloc_blocks;
210 s_prealloc_dir_blocks = s_prealloc_dir_blocks;
211 s_reserved_gdt_blocks = s_reserved_gdt_blocks;
212 s_journal_uuid = s_journal_uuid;
213 s_journal_inum = s_journal_inum;
214 s_journal_dev = s_journal_dev;
215 s_last_orphan = s_last_orphan;
216 s_hash_seed0 = s_hash_seed0;
217 s_hash_seed1 = s_hash_seed1;
218 s_hash_seed2 = s_hash_seed2;
219 s_hash_seed3 = s_hash_seed3;
220 s_def_hash_version = s_def_hash_version;
221 s_reserved_char_pad = s_reserved_char_pad;
222 s_reserved_word_pad = s_reserved_word_pad;
223 s_default_mount_opts = s_default_mount_opts;
224 s_first_meta_bg = s_first_meta_bg;
225 block_size = block_size;
226 groups_count = groups_count }
229 raise Not_found (* Not an EXT2/3 superblock. *)
232 let sb = parse_ext2_sb dev in (* May raise Not_found. *)
235 (* Number of group descriptors per block. *)
236 let s_inodes_per_block = s_blocksize /
237 let s_desc_per_block = block_size / s_inodes_per_block in
239 (s_groups_count +^ s_desc_per_block -^ 1L)
243 (* Calculate the block overhead (used by superblocks, inodes, etc.)
244 * See fs/ext2/super.c.
246 let overhead = Int63.of_int32 sb.s_first_data_block in
247 let overhead = (* XXX *) overhead in
249 (* The blocksize of the filesystem is likely to be quite different
250 * from that of the underlying device, so create an overlay device
251 * with the natural filesystem blocksize.
253 let fs_dev = new blocksize_overlay sb.block_size dev in
256 fs_cb = callbacks ();
259 fs_blocksize = sb.block_size;
260 fs_blocks_total = Int63.of_int32 sb.s_blocks_count -^ overhead;
264 fs_blocks_reserved = Int63.of_int32 sb.s_r_blocks_count;
265 fs_blocks_avail = Int63.of_int32 sb.s_free_blocks_count;
267 Int63.of_int32 sb.s_blocks_count -^ overhead
268 -^ Int63.of_int32 sb.s_free_blocks_count;
269 fs_inodes_total = Int63.of_int32 sb.s_inodes_count;
270 fs_inodes_reserved = ~^0; (* XXX? *)
271 fs_inodes_avail = Int63.of_int32 sb.s_free_inodes_count;
272 fs_inodes_used = Int63.of_int32 sb.s_inodes_count
274 -^ Int63.of_int32 sb.s_free_inodes_count;
277 (* Attach the original superblock as private data so we can
278 * get to it quickly in other callbacks.
280 attach_private_data fs sb;
283 and offset_is_free _ _ = false
288 fs_cb_uq = (incr i; !i);
290 fs_cb_printable_name = "Linux ext2/3";
291 fs_cb_offset_is_free = offset_is_free;
294 (* Register the plugin. *)
295 let () = register_plugin ~filesystem:probe id