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 	if (!is_be)
237 		blkid_probe_set_block_size(pr, le32_to_cpu(ufs->fs_fsize));
238 	else
239 		blkid_probe_set_block_size(pr, be32_to_cpu(ufs->fs_fsize));
240 
241 	return 0;
242 }
243 
244 /*
245  * According to libvolume_id the UFS superblock could be on four positions.
246  * The original libblkid has checked one position (.kboff=8) only.
247  *
248  * We know four UFS magic strings and UFS could be both little-endian and
249  * big-endian. ... so we have:
250  *
251  *	4 position * 4 string * 2 version = 32 magic strings
252  *
253  * It seems simpler to check for these string in probing function that hardcode
254  * all in the .magic array.
255  */
256 const struct blkid_idinfo ufs_idinfo =
257 {
258 	.name		= "ufs",
259 	.usage		= BLKID_USAGE_FILESYSTEM,
260 	.probefunc	= probe_ufs,
261 	.magics		= BLKID_NONE_MAGIC
262 };
263 
264