1/*
2 * volume_id - reads filesystem label and uuid
3 *
4 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
5 *
6 *	This program is free software; you can redistribute it and/or modify it
7 *	under the terms of the GNU General Public License as published by the
8 *	Free Software Foundation version 2 of the License.
9 */
10
11#ifndef _GNU_SOURCE
12#define _GNU_SOURCE 1
13#endif
14
15#ifdef HAVE_CONFIG_H
16#  include <config.h>
17#endif
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <unistd.h>
22#include <string.h>
23#include <errno.h>
24#include <ctype.h>
25
26#include "libvolume_id.h"
27#include "util.h"
28
29struct ufs_super_block {
30	uint32_t	fs_link;
31	uint32_t	fs_rlink;
32	uint32_t	fs_sblkno;
33	uint32_t	fs_cblkno;
34	uint32_t	fs_iblkno;
35	uint32_t	fs_dblkno;
36	uint32_t	fs_cgoffset;
37	uint32_t	fs_cgmask;
38	uint32_t	fs_time;
39	uint32_t	fs_size;
40	uint32_t	fs_dsize;
41	uint32_t	fs_ncg;
42	uint32_t	fs_bsize;
43	uint32_t	fs_fsize;
44	uint32_t	fs_frag;
45	uint32_t	fs_minfree;
46	uint32_t	fs_rotdelay;
47	uint32_t	fs_rps;
48	uint32_t	fs_bmask;
49	uint32_t	fs_fmask;
50	uint32_t	fs_bshift;
51	uint32_t	fs_fshift;
52	uint32_t	fs_maxcontig;
53	uint32_t	fs_maxbpg;
54	uint32_t	fs_fragshift;
55	uint32_t	fs_fsbtodb;
56	uint32_t	fs_sbsize;
57	uint32_t	fs_csmask;
58	uint32_t	fs_csshift;
59	uint32_t	fs_nindir;
60	uint32_t	fs_inopb;
61	uint32_t	fs_nspf;
62	uint32_t	fs_optim;
63	uint32_t	fs_npsect_state;
64	uint32_t	fs_interleave;
65	uint32_t	fs_trackskew;
66	uint32_t	fs_id[2];
67	uint32_t	fs_csaddr;
68	uint32_t	fs_cssize;
69	uint32_t	fs_cgsize;
70	uint32_t	fs_ntrak;
71	uint32_t	fs_nsect;
72	uint32_t	fs_spc;
73	uint32_t	fs_ncyl;
74	uint32_t	fs_cpg;
75	uint32_t	fs_ipg;
76	uint32_t	fs_fpg;
77	struct ufs_csum {
78		uint32_t	cs_ndir;
79		uint32_t	cs_nbfree;
80		uint32_t	cs_nifree;
81		uint32_t	cs_nffree;
82	} PACKED fs_cstotal;
83	int8_t		fs_fmod;
84	int8_t		fs_clean;
85	int8_t		fs_ronly;
86	int8_t		fs_flags;
87	union {
88		struct {
89			int8_t	fs_fsmnt[512];
90			uint32_t	fs_cgrotor;
91			uint32_t	fs_csp[31];
92			uint32_t	fs_maxcluster;
93			uint32_t	fs_cpc;
94			uint16_t	fs_opostbl[16][8];
95		} PACKED fs_u1;
96		struct {
97			int8_t		fs_fsmnt[468];
98			uint8_t		fs_volname[32];
99			uint64_t	fs_swuid;
100			int32_t		fs_pad;
101			uint32_t	fs_cgrotor;
102			uint32_t	fs_ocsp[28];
103			uint32_t	fs_contigdirs;
104			uint32_t	fs_csp;
105			uint32_t	fs_maxcluster;
106			uint32_t	fs_active;
107			int32_t		fs_old_cpc;
108			int32_t		fs_maxbsize;
109			int64_t		fs_sparecon64[17];
110			int64_t		fs_sblockloc;
111			struct ufs2_csum_total {
112				uint64_t	cs_ndir;
113				uint64_t	cs_nbfree;
114				uint64_t	cs_nifree;
115				uint64_t	cs_nffree;
116				uint64_t	cs_numclusters;
117				uint64_t	cs_spare[3];
118			} PACKED fs_cstotal;
119			struct ufs_timeval {
120				int32_t		tv_sec;
121				int32_t		tv_usec;
122			} PACKED fs_time;
123			int64_t		fs_size;
124			int64_t		fs_dsize;
125			uint64_t	fs_csaddr;
126			int64_t		fs_pendingblocks;
127			int32_t		fs_pendinginodes;
128		} PACKED fs_u2;
129	}  fs_u11;
130	union {
131		struct {
132			int32_t		fs_sparecon[53];
133			int32_t		fs_reclaim;
134			int32_t		fs_sparecon2[1];
135			int32_t		fs_state;
136			uint32_t	fs_qbmask[2];
137			uint32_t	fs_qfmask[2];
138		} PACKED fs_sun;
139		struct {
140			int32_t		fs_sparecon[53];
141			int32_t		fs_reclaim;
142			int32_t		fs_sparecon2[1];
143			uint32_t	fs_npsect;
144			uint32_t	fs_qbmask[2];
145			uint32_t	fs_qfmask[2];
146		} PACKED fs_sunx86;
147		struct {
148			int32_t		fs_sparecon[50];
149			int32_t		fs_contigsumsize;
150			int32_t		fs_maxsymlinklen;
151			int32_t		fs_inodefmt;
152			uint32_t	fs_maxfilesize[2];
153			uint32_t	fs_qbmask[2];
154			uint32_t	fs_qfmask[2];
155			int32_t		fs_state;
156		} PACKED fs_44;
157	} fs_u2;
158	int32_t		fs_postblformat;
159	int32_t		fs_nrpos;
160	int32_t		fs_postbloff;
161	int32_t		fs_rotbloff;
162	uint32_t	fs_magic;
163	uint8_t		fs_space[1];
164} PACKED;
165
166#define UFS_MAGIC			0x00011954
167#define UFS2_MAGIC			0x19540119
168#define UFS_MAGIC_FEA			0x00195612
169#define UFS_MAGIC_LFN			0x00095014
170
171int volume_id_probe_ufs(struct volume_id *id, uint64_t off, uint64_t size)
172{
173	uint32_t magic;
174	int i;
175	struct ufs_super_block *ufs;
176	int offsets[] = {0, 8, 64, 256, -1};
177
178	info("probing at offset 0x%llx", (unsigned long long) off);
179
180	for (i = 0; offsets[i] >= 0; i++) {
181		ufs = (struct ufs_super_block *) volume_id_get_buffer(id, off + (offsets[i] * 0x400), 0x800);
182		if (ufs == NULL)
183			return -1;
184
185		dbg("offset 0x%x", offsets[i] * 0x400);
186		magic = be32_to_cpu(ufs->fs_magic);
187		if ((magic == UFS_MAGIC) ||
188		    (magic == UFS2_MAGIC) ||
189		    (magic == UFS_MAGIC_FEA) ||
190		    (magic == UFS_MAGIC_LFN)) {
191			dbg("magic 0x%08x(be)", magic);
192			goto found;
193		}
194		magic = le32_to_cpu(ufs->fs_magic);
195		if ((magic == UFS_MAGIC) ||
196		    (magic == UFS2_MAGIC) ||
197		    (magic == UFS_MAGIC_FEA) ||
198		    (magic == UFS_MAGIC_LFN)) {
199			dbg("magic 0x%08x(le)", magic);
200			goto found;
201		}
202	}
203	return -1;
204
205found:
206	volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
207	id->type = "ufs";
208	switch (magic) {
209	case UFS_MAGIC:
210		strcpy(id->type_version, "1");
211		break;
212	case UFS2_MAGIC:
213		strcpy(id->type_version, "2");
214		volume_id_set_label_raw(id, ufs->fs_u11.fs_u2.fs_volname, 32);
215		volume_id_set_label_string(id, ufs->fs_u11.fs_u2.fs_volname, 32);
216		break;
217	default:
218		break;
219	}
220
221	return 0;
222}
223