/src/util-linux/libblkid/src/superblocks/ufs.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2008 Karel Zak <kzak@redhat.com> |
3 | | * |
4 | | * Inspired by libvolume_id by |
5 | | * Kay Sievers <kay.sievers@vrfy.org> |
6 | | * |
7 | | * This file may be redistributed under the terms of the |
8 | | * GNU Lesser General Public License. |
9 | | */ |
10 | | |
11 | | #include <stdio.h> |
12 | | #include <stdlib.h> |
13 | | #include <unistd.h> |
14 | | #include <string.h> |
15 | | #include <errno.h> |
16 | | #include <ctype.h> |
17 | | #include <stdint.h> |
18 | | #include <stddef.h> |
19 | | |
20 | | #include "superblocks.h" |
21 | | |
22 | | struct ufs_super_block { |
23 | | uint32_t fs_link; |
24 | | uint32_t fs_rlink; |
25 | | uint32_t fs_sblkno; |
26 | | uint32_t fs_cblkno; |
27 | | uint32_t fs_iblkno; |
28 | | uint32_t fs_dblkno; |
29 | | uint32_t fs_cgoffset; |
30 | | uint32_t fs_cgmask; |
31 | | uint32_t fs_time; |
32 | | uint32_t fs_size; |
33 | | uint32_t fs_dsize; |
34 | | uint32_t fs_ncg; |
35 | | uint32_t fs_bsize; |
36 | | uint32_t fs_fsize; |
37 | | uint32_t fs_frag; |
38 | | uint32_t fs_minfree; |
39 | | uint32_t fs_rotdelay; |
40 | | uint32_t fs_rps; |
41 | | uint32_t fs_bmask; |
42 | | uint32_t fs_fmask; |
43 | | uint32_t fs_bshift; |
44 | | uint32_t fs_fshift; |
45 | | uint32_t fs_maxcontig; |
46 | | uint32_t fs_maxbpg; |
47 | | uint32_t fs_fragshift; |
48 | | uint32_t fs_fsbtodb; |
49 | | uint32_t fs_sbsize; |
50 | | uint32_t fs_csmask; |
51 | | uint32_t fs_csshift; |
52 | | uint32_t fs_nindir; |
53 | | uint32_t fs_inopb; |
54 | | uint32_t fs_nspf; |
55 | | uint32_t fs_optim; |
56 | | uint32_t fs_npsect_state; |
57 | | uint32_t fs_interleave; |
58 | | uint32_t fs_trackskew; |
59 | | uint32_t fs_id[2]; |
60 | | uint32_t fs_csaddr; |
61 | | uint32_t fs_cssize; |
62 | | uint32_t fs_cgsize; |
63 | | uint32_t fs_ntrak; |
64 | | uint32_t fs_nsect; |
65 | | uint32_t fs_spc; |
66 | | uint32_t fs_ncyl; |
67 | | uint32_t fs_cpg; |
68 | | uint32_t fs_ipg; |
69 | | uint32_t fs_fpg; |
70 | | struct ufs_csum { |
71 | | uint32_t cs_ndir; |
72 | | uint32_t cs_nbfree; |
73 | | uint32_t cs_nifree; |
74 | | uint32_t cs_nffree; |
75 | | } fs_cstotal; |
76 | | int8_t fs_fmod; |
77 | | int8_t fs_clean; |
78 | | int8_t fs_ronly; |
79 | | int8_t fs_flags; |
80 | | union { |
81 | | struct { |
82 | | int8_t fs_fsmnt[512]; |
83 | | uint32_t fs_cgrotor; |
84 | | uint32_t fs_csp[31]; |
85 | | uint32_t fs_maxcluster; |
86 | | uint32_t fs_cpc; |
87 | | uint16_t fs_opostbl[16][8]; |
88 | | } fs_u1; |
89 | | struct { |
90 | | int8_t fs_fsmnt[468]; |
91 | | uint8_t fs_volname[32]; |
92 | | uint64_t fs_swuid; |
93 | | int32_t fs_pad; |
94 | | uint32_t fs_cgrotor; |
95 | | uint32_t fs_ocsp[28]; |
96 | | uint32_t fs_contigdirs; |
97 | | uint32_t fs_csp; |
98 | | uint32_t fs_maxcluster; |
99 | | uint32_t fs_active; |
100 | | int32_t fs_old_cpc; |
101 | | int32_t fs_maxbsize; |
102 | | int64_t fs_sparecon64[17]; |
103 | | int64_t fs_sblockloc; |
104 | | struct ufs2_csum_total { |
105 | | uint64_t cs_ndir; |
106 | | uint64_t cs_nbfree; |
107 | | uint64_t cs_nifree; |
108 | | uint64_t cs_nffree; |
109 | | uint64_t cs_numclusters; |
110 | | uint64_t cs_spare[3]; |
111 | | } fs_cstotal; |
112 | | struct ufs_timeval { |
113 | | int32_t tv_sec; |
114 | | int32_t tv_usec; |
115 | | } fs_time; |
116 | | int64_t fs_size; |
117 | | int64_t fs_dsize; |
118 | | uint64_t fs_csaddr; |
119 | | int64_t fs_pendingblocks; |
120 | | int32_t fs_pendinginodes; |
121 | | } __attribute__((packed)) fs_u2; |
122 | | } fs_u11; |
123 | | union { |
124 | | struct { |
125 | | int32_t fs_sparecon[53]; |
126 | | int32_t fs_reclaim; |
127 | | int32_t fs_sparecon2[1]; |
128 | | int32_t fs_state; |
129 | | uint32_t fs_qbmask[2]; |
130 | | uint32_t fs_qfmask[2]; |
131 | | } fs_sun; |
132 | | struct { |
133 | | int32_t fs_sparecon[53]; |
134 | | int32_t fs_reclaim; |
135 | | int32_t fs_sparecon2[1]; |
136 | | uint32_t fs_npsect; |
137 | | uint32_t fs_qbmask[2]; |
138 | | uint32_t fs_qfmask[2]; |
139 | | } fs_sunx86; |
140 | | struct { |
141 | | int32_t fs_sparecon[50]; |
142 | | int32_t fs_contigsumsize; |
143 | | int32_t fs_maxsymlinklen; |
144 | | int32_t fs_inodefmt; |
145 | | uint32_t fs_maxfilesize[2]; |
146 | | uint32_t fs_qbmask[2]; |
147 | | uint32_t fs_qfmask[2]; |
148 | | int32_t fs_state; |
149 | | } fs_44; |
150 | | } fs_u2; |
151 | | int32_t fs_postblformat; |
152 | | int32_t fs_nrpos; |
153 | | int32_t fs_postbloff; |
154 | | int32_t fs_rotbloff; |
155 | | uint32_t fs_magic; |
156 | | uint8_t fs_space[1]; |
157 | | } __attribute__((packed)); |
158 | | |
159 | 2.99k | #define UFS_MAGIC 0x00011954 |
160 | 3.06k | #define UFS2_MAGIC 0x19540119 |
161 | 2.99k | #define UFS_MAGIC_FEA 0x00195612 |
162 | 2.99k | #define UFS_MAGIC_LFN 0x00095014 |
163 | 2.99k | #define UFS_MAGIC_SEC 0x00612195 |
164 | 2.99k | #define UFS_MAGIC_4GB 0x05231994 |
165 | | |
166 | | static int probe_ufs(blkid_probe pr, |
167 | | const struct blkid_idmag *mag __attribute__((__unused__))) |
168 | 2.99k | { |
169 | 2.99k | int offsets[] = { 0, 8, 64, 256 }; |
170 | 2.99k | uint32_t mags[] = { |
171 | 2.99k | UFS2_MAGIC, UFS_MAGIC, UFS_MAGIC_FEA, UFS_MAGIC_LFN, |
172 | 2.99k | UFS_MAGIC_SEC, UFS_MAGIC_4GB |
173 | 2.99k | }; |
174 | 2.99k | size_t i; |
175 | 2.99k | uint32_t magic; |
176 | 2.99k | struct ufs_super_block *ufs; |
177 | 2.99k | int is_be; |
178 | | |
179 | 6.49k | for (i = 0; i < ARRAY_SIZE(offsets); i++) { |
180 | 6.26k | uint32_t magLE, magBE; |
181 | 6.26k | size_t y; |
182 | | |
183 | 6.26k | ufs = (struct ufs_super_block *) |
184 | 6.26k | blkid_probe_get_buffer(pr, |
185 | 6.26k | offsets[i] * 1024, |
186 | 6.26k | sizeof(struct ufs_super_block)); |
187 | 6.26k | if (!ufs) |
188 | 2.69k | return errno ? -errno : 1; |
189 | | |
190 | 3.56k | magBE = be32_to_cpu(ufs->fs_magic); |
191 | 3.56k | magLE = le32_to_cpu(ufs->fs_magic); |
192 | | |
193 | 24.7k | for (y = 0; y < ARRAY_SIZE(mags); y++) { |
194 | 21.2k | if (magLE == mags[y] || magBE == mags[y]) { |
195 | 70 | magic = mags[y]; |
196 | 70 | is_be = (magBE == mags[y]); |
197 | 70 | goto found; |
198 | 70 | } |
199 | 21.2k | } |
200 | 3.56k | } |
201 | | |
202 | 233 | return 1; |
203 | | |
204 | 70 | found: |
205 | 70 | if (magic == UFS2_MAGIC) { |
206 | 22 | blkid_probe_set_version(pr, "2"); |
207 | 22 | blkid_probe_set_label(pr, ufs->fs_u11.fs_u2.fs_volname, |
208 | 22 | sizeof(ufs->fs_u11.fs_u2.fs_volname)); |
209 | 22 | } else |
210 | 48 | blkid_probe_set_version(pr, "1"); |
211 | 70 | if (ufs->fs_id[0] || ufs->fs_id[1]) |
212 | 60 | { |
213 | 60 | if (is_be) |
214 | 30 | blkid_probe_sprintf_uuid(pr, |
215 | 30 | (unsigned char *) &ufs->fs_id, |
216 | 30 | sizeof(ufs->fs_id), |
217 | 30 | "%08x%08x", |
218 | 30 | be32_to_cpu(ufs->fs_id[0]), |
219 | 30 | be32_to_cpu(ufs->fs_id[1])); |
220 | 30 | else |
221 | 30 | blkid_probe_sprintf_uuid(pr, |
222 | 30 | (unsigned char *) &ufs->fs_id, |
223 | 30 | sizeof(ufs->fs_id), |
224 | 30 | "%08x%08x", |
225 | 30 | le32_to_cpu(ufs->fs_id[0]), |
226 | 30 | le32_to_cpu(ufs->fs_id[1])); |
227 | 60 | } |
228 | | |
229 | 70 | if (blkid_probe_set_magic(pr, |
230 | 70 | (offsets[i] * 1024) + |
231 | 70 | offsetof(struct ufs_super_block, fs_magic), |
232 | 70 | sizeof(ufs->fs_magic), |
233 | 70 | (unsigned char *) &ufs->fs_magic)) |
234 | 0 | return 1; |
235 | | |
236 | 70 | uint32_t bsize = 0; |
237 | 70 | if (!is_be) |
238 | 40 | bsize = le32_to_cpu(ufs->fs_fsize); |
239 | 30 | else |
240 | 30 | bsize = be32_to_cpu(ufs->fs_fsize); |
241 | | |
242 | 70 | blkid_probe_set_fsblocksize(pr, bsize); |
243 | 70 | blkid_probe_set_block_size(pr, bsize); |
244 | 70 | blkid_probe_set_fsendianness(pr, is_be ? |
245 | 40 | BLKID_ENDIANNESS_BIG : BLKID_ENDIANNESS_LITTLE); |
246 | | |
247 | 70 | return 0; |
248 | 70 | } |
249 | | |
250 | | /* |
251 | | * According to libvolume_id the UFS superblock could be on four positions. |
252 | | * The original libblkid has checked one position (.kboff=8) only. |
253 | | * |
254 | | * We know four UFS magic strings and UFS could be both little-endian and |
255 | | * big-endian. ... so we have: |
256 | | * |
257 | | * 4 position * 4 string * 2 version = 32 magic strings |
258 | | * |
259 | | * It seems simpler to check for these string in probing function that hardcode |
260 | | * all in the .magic array. |
261 | | */ |
262 | | const struct blkid_idinfo ufs_idinfo = |
263 | | { |
264 | | .name = "ufs", |
265 | | .usage = BLKID_USAGE_FILESYSTEM, |
266 | | .probefunc = probe_ufs, |
267 | | .magics = BLKID_NONE_MAGIC |
268 | | }; |
269 | | |