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 #define UFS_MAGIC 0x00011954
160 #define UFS2_MAGIC 0x19540119
161 #define UFS_MAGIC_FEA 0x00195612
162 #define UFS_MAGIC_LFN 0x00095014
163 #define UFS_MAGIC_SEC 0x00612195
164 #define UFS_MAGIC_4GB 0x05231994
165
probe_ufs(blkid_probe pr,const struct blkid_idmag * mag)166 static int probe_ufs(blkid_probe pr,
167 const struct blkid_idmag *mag __attribute__((__unused__)))
168 {
169 int offsets[] = { 0, 8, 64, 256 };
170 uint32_t mags[] = {
171 UFS2_MAGIC, UFS_MAGIC, UFS_MAGIC_FEA, UFS_MAGIC_LFN,
172 UFS_MAGIC_SEC, UFS_MAGIC_4GB
173 };
174 size_t i;
175 uint32_t magic;
176 struct ufs_super_block *ufs;
177 int is_be;
178
179 for (i = 0; i < ARRAY_SIZE(offsets); i++) {
180 uint32_t magLE, magBE;
181 size_t y;
182
183 ufs = (struct ufs_super_block *)
184 blkid_probe_get_buffer(pr,
185 offsets[i] * 1024,
186 sizeof(struct ufs_super_block));
187 if (!ufs)
188 return errno ? -errno : 1;
189
190 magBE = be32_to_cpu(ufs->fs_magic);
191 magLE = le32_to_cpu(ufs->fs_magic);
192
193 for (y = 0; y < ARRAY_SIZE(mags); y++) {
194 if (magLE == mags[y] || magBE == mags[y]) {
195 magic = mags[y];
196 is_be = (magBE == mags[y]);
197 goto found;
198 }
199 }
200 }
201
202 return 1;
203
204 found:
205 if (magic == UFS2_MAGIC) {
206 blkid_probe_set_version(pr, "2");
207 blkid_probe_set_label(pr, ufs->fs_u11.fs_u2.fs_volname,
208 sizeof(ufs->fs_u11.fs_u2.fs_volname));
209 } else
210 blkid_probe_set_version(pr, "1");
211 if (ufs->fs_id[0] || ufs->fs_id[1])
212 {
213 if (is_be)
214 blkid_probe_sprintf_uuid(pr,
215 (unsigned char *) &ufs->fs_id,
216 sizeof(ufs->fs_id),
217 "%08x%08x",
218 be32_to_cpu(ufs->fs_id[0]),
219 be32_to_cpu(ufs->fs_id[1]));
220 else
221 blkid_probe_sprintf_uuid(pr,
222 (unsigned char *) &ufs->fs_id,
223 sizeof(ufs->fs_id),
224 "%08x%08x",
225 le32_to_cpu(ufs->fs_id[0]),
226 le32_to_cpu(ufs->fs_id[1]));
227 }
228
229 if (blkid_probe_set_magic(pr,
230 (offsets[i] * 1024) +
231 offsetof(struct ufs_super_block, fs_magic),
232 sizeof(ufs->fs_magic),
233 (unsigned char *) &ufs->fs_magic))
234 return 1;
235
236 return 0;
237 }
238
239 /*
240 * According to libvolume_id the UFS superblock could be on four positions.
241 * The original libblkid has checked one position (.kboff=8) only.
242 *
243 * We know four UFS magic strings and UFS could be both little-endian and
244 * big-endian. ... so we have:
245 *
246 * 4 position * 4 string * 2 version = 32 magic strings
247 *
248 * It seems simpler to check for these string in probing function that hardcode
249 * all in the .magic array.
250 */
251 const struct blkid_idinfo ufs_idinfo =
252 {
253 .name = "ufs",
254 .usage = BLKID_USAGE_FILESYSTEM,
255 .probefunc = probe_ufs,
256 .magics = BLKID_NONE_MAGIC
257 };
258
259