fstyp.c (c719c59a) fstyp.c (0e42dee6)
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28/* All Rights Reserved */
29
30/*
31 * Portions of this source code were derived from Berkeley 4.3 BSD
32 * under license from the Regents of the University of California.
33 */
34
35#pragma ident "%Z%%M% %I% %E% SMI"
36
37/*
23 * Use is subject to license terms.
24 */
25
26/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27/* All Rights Reserved */
28
29/*
30 * Portions of this source code were derived from Berkeley 4.3 BSD
31 * under license from the Regents of the University of California.
32 */
33
34#pragma ident "%Z%%M% %I% %E% SMI"
35
36/*
38 * fstyp
39 *
40 * Designed to work with block devices (e.g., /dev/diskette), not
41 * raw devices (e.g., /dev/rdiskette)
37 * libfstyp module for pcfs
42 */
43#include <sys/param.h>
44#include <sys/types.h>
45#include <sys/mntent.h>
46#include <errno.h>
47#include <sys/fs/pc_fs.h>
48#include <sys/fs/pc_label.h>
38 */
39#include <sys/param.h>
40#include <sys/types.h>
41#include <sys/mntent.h>
42#include <errno.h>
43#include <sys/fs/pc_fs.h>
44#include <sys/fs/pc_label.h>
45#include <sys/fs/pc_dir.h>
49#include <sys/stat.h>
50#include <sys/vfs.h>
46#include <sys/stat.h>
47#include <sys/vfs.h>
51
52#include <stdio.h>
48#include <stdio.h>
49#include <unistd.h>
50#include <string.h>
51#include <strings.h>
53#include <sys/mnttab.h>
52#include <sys/mnttab.h>
54
55#include <locale.h>
53#include <locale.h>
54#include <libfstyp_module.h>
56
55
57extern offset_t llseek();
56#define PC_LABEL_SIZE 11
58
57
58struct fstyp_fat16_bs {
59 uint8_t f_drvnum;
60 uint8_t f_reserved1;
61 uint8_t f_bootsig;
62 uint8_t f_volid[4];
63 uint8_t f_label[11];
64 uint8_t f_typestring[8];
65};
59
66
60#define PC_BPSEC(a) ((a[12]<<8)+a[11]) /* bytes per sector */
61#define PC_SPC(a) (a[13]) /* sectors per cluster */
62#define PC_RESSEC(a) ((a[15]<<8)+a[14]) /* reserved sectors */
63#define PC_NFAT(a) (a[16]) /* number of fats */
64#define PC_NROOTENT(a) ((a[18]<<8)+a[17]) /* number of root dir entries */
65#define PC_MEDIA(a) (a[21]) /* media descriptor */
66#define PC_SPT(a) ((a[25]<<8)+a[24]) /* sectors per track */
67#define PC_NHEAD(a) ((a[27]<<8)+a[26]) /* number of heads */
68#define PC_HIDSEC(a) ((a[29]<<8)+a[28]) /* number of hidden sectors */
69#define PC_DRVNUM(a) (a[36]) /* drive number */
70#define PC_LAB_ADDR(a) (&a[43]) /* addr of volume label */
71#define LABEL_SIZE 11 /* size of volume label */
67struct fstyp_fat32_bs {
68 uint32_t f_fatlength;
69 uint16_t f_flags;
70 uint8_t f_major;
71 uint8_t f_minor;
72 uint32_t f_rootcluster;
73 uint16_t f_infosector;
74 uint16_t f_backupboot;
75 uint8_t f_reserved2[12];
76 uint8_t f_drvnum;
77 uint8_t f_reserved1;
78 uint8_t f_bootsig;
79 uint8_t f_volid[4];
80 uint8_t f_label[11];
81 uint8_t f_typestring[8];
82};
72
83
73/*
74 * Parse out all the following forms as unsigned quantities. It would
75 * not be unusual for them to be large enough that the high bit would be
76 * set and they would then be misinterpreted as negative quantities.
77 *
78 * The values are:
79 * number of sectors
80 * big number of sectors (MSDOS4.0 and later)
81 * sectors/FAT
82 * big sectors/FAT (FAT32 only)
83 */
84#define PC_NSEC(a) ((unsigned short)((a[20]<<8)+a[19]))
85#define PC_BIGNSEC(a) ((unsigned)((a[35]<<24)+(a[34]<<16)+(a[33]<<8)+a[32]))
86#define PC_SPF(a) ((unsigned short)((a[23]<<8)+a[22]))
87#define PC_BIGSPF(a) ((unsigned)((a[39]<<24)+(a[38]<<16)+(a[37]<<8)+a[36]))
84typedef struct fstyp_pcfs {
85 int fd;
86 off_t offset;
87 nvlist_t *attr;
88 struct bootsec bs;
89 struct fstyp_fat16_bs bs16;
90 struct fstyp_fat32_bs bs32;
91 ushort_t bps;
92 int fattype;
93 char volume_label[PC_LABEL_SIZE + 1];
88
94
89/*
90 * Boolean macros
91 */
92#define PC_EXTSIG(a) (a[38] == 0x29) /* do we have an extended BPB? */
93#define PC_EXTSIG32(a) (a[66] == 0x29) /* do we have FAT32 w/ extended BPB? */
95 /* parameters derived or calculated per FAT spec */
96 ulong_t FATSz;
97 ulong_t TotSec;
98 ulong_t RootDirSectors;
99 ulong_t FirstDataSector;
100 ulong_t DataSec;
101 ulong_t CountOfClusters;
102} fstyp_pcfs_t;
94
103
95int vflag = 0; /* verbose output */
96int errflag = 0;
97char *cbasename;
98char *special;
99char *fstype;
100
104
101static void usage(void);
102static void dumpfs(char *name);
103static int valid_media(unsigned char media_type);
105/* We should eventually make the structs "packed" so these won't be needed */
106#define PC_BPSEC(h) ltohs((h)->bs.bps[0])
107#define PC_RESSEC(h) ltohs((h)->bs.res_sec[0])
108#define PC_NROOTENT(h) ltohs((h)->bs.rdirents[0])
109#define PC_NSEC(h) ltohs((h)->bs.numsect[0])
110#define PC_DRVNUM(h) (FSTYP_IS_32(h) ? (h)->bs32.f_drvnum : \
111 (h)->bs16.f_drvnum)
112#define PC_VOLID(a) (FSTYP_IS_32(h) ? ltohi((h)->bs32.f_volid[0]) : \
113 ltohi((h)->bs16.f_volid[0]))
114#define PC_LABEL_ADDR(a) (FSTYP_IS_32(h) ? \
115 &((h)->bs32.f_label[0]) : &((h)->bs16.f_label[0]))
104
116
117#define FSTYP_IS_32(h) ((h)->fattype == 32)
118
119#define FSTYP_MAX_CLUSTER_SIZE (64 * 1024) /* though officially 32K */
120#define FSTYP_MAX_DIR_SIZE (65536 * 32)
121
122static int read_bootsec(fstyp_pcfs_t *h);
123static int valid_media(fstyp_pcfs_t *h);
124static int well_formed(fstyp_pcfs_t *h);
125static void calculate_parameters(fstyp_pcfs_t *h);
126static void determine_fattype(fstyp_pcfs_t *h);
127static void get_label(fstyp_pcfs_t *h);
128static void get_label_16(fstyp_pcfs_t *h);
129static void get_label_32(fstyp_pcfs_t *h);
130static int next_cluster_32(fstyp_pcfs_t *h, int n);
131static boolean_t dir_find_label(fstyp_pcfs_t *h, struct pcdir *d, int nent);
132static int is_pcfs(fstyp_pcfs_t *h);
133static int dumpfs(fstyp_pcfs_t *h, FILE *fout, FILE *ferr);
134static int get_attr(fstyp_pcfs_t *h);
135
136int fstyp_mod_init(int fd, off_t offset, fstyp_mod_handle_t *handle);
137void fstyp_mod_fini(fstyp_mod_handle_t handle);
138int fstyp_mod_ident(fstyp_mod_handle_t handle);
139int fstyp_mod_get_attr(fstyp_mod_handle_t handle, nvlist_t **attrp);
140int fstyp_mod_dump(fstyp_mod_handle_t handle, FILE *fout, FILE *ferr);
141
105int
142int
106main(int argc, char *argv[])
143fstyp_mod_init(int fd, off_t offset, fstyp_mod_handle_t *handle)
107{
144{
108 int c;
145 struct fstyp_pcfs *h;
109
146
110 (void) setlocale(LC_ALL, "");
111#if !defined(TEXT_DOMAIN)
112#define TEXT_DOMAIN "SYS_TEST"
113#endif
114 (void) textdomain(TEXT_DOMAIN);
147 if ((h = calloc(1, sizeof (struct fstyp_pcfs))) == NULL) {
148 return (FSTYP_ERR_NOMEM);
149 }
150 h->fd = fd;
151 h->offset = offset;
115
152
116 cbasename = argv[0];
117 while ((c = getopt(argc, argv, "v")) != EOF) {
118 switch (c) {
153 *handle = (fstyp_mod_handle_t)h;
154 return (0);
155}
119
156
120 case 'v': /* dump super block */
121 vflag++;
122 break;
157void
158fstyp_mod_fini(fstyp_mod_handle_t handle)
159{
160 struct fstyp_pcfs *h = (struct fstyp_pcfs *)handle;
123
161
124 case '?':
125 errflag++;
162 if (h->attr == NULL) {
163 nvlist_free(h->attr);
164 h->attr = NULL;
165 }
166 free(h);
167}
168
169int
170fstyp_mod_ident(fstyp_mod_handle_t handle)
171{
172 struct fstyp_pcfs *h = (struct fstyp_pcfs *)handle;
173
174 return (is_pcfs(h));
175}
176
177int
178fstyp_mod_get_attr(fstyp_mod_handle_t handle, nvlist_t **attrp)
179{
180 struct fstyp_pcfs *h = (struct fstyp_pcfs *)handle;
181 int error;
182
183 if (h->attr == NULL) {
184 if (nvlist_alloc(&h->attr, NV_UNIQUE_NAME_TYPE, 0)) {
185 return (FSTYP_ERR_NOMEM);
126 }
186 }
187 if ((error = get_attr(h)) != 0) {
188 nvlist_free(h->attr);
189 h->attr = NULL;
190 return (error);
191 }
127 }
192 }
128 if (errflag || argc <= optind) {
129 usage();
130 exit(31+1);
193
194 *attrp = h->attr;
195 return (0);
196}
197
198int
199fstyp_mod_dump(fstyp_mod_handle_t handle, FILE *fout, FILE *ferr)
200{
201 struct fstyp_pcfs *h = (struct fstyp_pcfs *)handle;
202
203 return (dumpfs(h, fout, ferr));
204}
205
206
207/*
208 * Read in boot sector. Convert into host endianness where possible.
209 */
210static int
211read_bootsec(fstyp_pcfs_t *h)
212{
213 char buf[PC_SECSIZE];
214
215 (void) lseek(h->fd, h->offset, SEEK_SET);
216 if (read(h->fd, buf, sizeof (buf)) != sizeof (buf)) {
217 return (FSTYP_ERR_IO);
131 }
218 }
132 special = argv[optind];
133 dumpfs(special);
134
219
220 bcopy(buf, &h->bs, sizeof (h->bs));
221 bcopy(buf + sizeof (struct bootsec), &h->bs16, sizeof (h->bs16));
222 bcopy(buf + sizeof (struct bootsec), &h->bs32, sizeof (h->bs32));
223
224 h->bs.fatsec = ltohs(h->bs.fatsec);
225 h->bs.spt = ltohs(h->bs.spt);
226 h->bs.nhead = ltohs(h->bs.nhead);
227 h->bs.hiddensec = ltohi(h->bs.hiddensec);
228 h->bs.totalsec = ltohi(h->bs.totalsec);
229
230 h->bs32.f_fatlength = ltohi(h->bs32.f_fatlength);
231 h->bs32.f_flags = ltohs(h->bs32.f_flags);
232 h->bs32.f_rootcluster = ltohi(h->bs32.f_rootcluster);
233 h->bs32.f_infosector = ltohs(h->bs32.f_infosector);
234 h->bs32.f_backupboot = ltohs(h->bs32.f_backupboot);
235
236 h->bps = PC_BPSEC(h);
237
135 return (0);
136}
137
238 return (0);
239}
240
241static int
242valid_media(fstyp_pcfs_t *h)
243{
244 switch (h->bs.mediadesriptor) {
245 case MD_FIXED:
246 case SS8SPT:
247 case DS8SPT:
248 case SS9SPT:
249 case DS9SPT:
250 case DS18SPT:
251 case DS9_15SPT:
252 return (1);
253 default:
254 return (0);
255 }
256}
138
257
258static int
259well_formed(fstyp_pcfs_t *h)
260{
261 int fatmatch;
262
263 if (h->bs16.f_bootsig == 0x29) {
264 fatmatch = ((h->bs16.f_typestring[0] == 'F' &&
265 h->bs16.f_typestring[1] == 'A' &&
266 h->bs16.f_typestring[2] == 'T') &&
267 (h->bs.fatsec > 0) &&
268 ((PC_NSEC(h) == 0 && h->bs.totalsec > 0) ||
269 PC_NSEC(h) > 0));
270 } else if (h->bs32.f_bootsig == 0x29) {
271 fatmatch = ((h->bs32.f_typestring[0] == 'F' &&
272 h->bs32.f_typestring[1] == 'A' &&
273 h->bs32.f_typestring[2] == 'T') &&
274 (h->bs.fatsec == 0 && h->bs32.f_fatlength > 0) &&
275 ((PC_NSEC(h) == 0 && h->bs.totalsec > 0) ||
276 PC_NSEC(h) > 0));
277 } else {
278 fatmatch = (PC_NSEC(h) > 0 && h->bs.fatsec > 0);
279 }
280
281 return (fatmatch && h->bps > 0 && h->bps % 512 == 0 &&
282 h->bs.spcl > 0 && PC_RESSEC(h) >= 1 && h->bs.nfat > 0);
283}
284
139static void
285static void
140usage(void)
286calculate_parameters(fstyp_pcfs_t *h)
141{
287{
142 (void) fprintf(stderr, gettext("pcfs usage: fstyp [-v] special\n"));
288 if (PC_NSEC(h) != 0) {
289 h->TotSec = PC_NSEC(h);
290 } else {
291 h->TotSec = h->bs.totalsec;
292 }
293 if (h->bs.fatsec != 0) {
294 h->FATSz = h->bs.fatsec;
295 } else {
296 h->FATSz = h->bs32.f_fatlength;
297 }
298 if ((h->bps == 0) || (h->bs.spcl == 0)) {
299 return;
300 }
301 h->RootDirSectors =
302 ((PC_NROOTENT(h) * 32) + (h->bps - 1)) / h->bps;
303 h->FirstDataSector =
304 PC_RESSEC(h) + h->bs.nfat * h->FATSz + h->RootDirSectors;
305 h->DataSec = h->TotSec - h->FirstDataSector;
306 h->CountOfClusters = h->DataSec / h->bs.spcl;
143}
144
145static void
307}
308
309static void
146dumpfs(char *name)
310determine_fattype(fstyp_pcfs_t *h)
147{
311{
148 unsigned char buf[DEV_BSIZE];
149 char label[LABEL_SIZE+1];
150 unsigned char media;
312 if ((h->CountOfClusters >= 4085 && h->CountOfClusters <= 4095) ||
313 (h->CountOfClusters >= 65525 && h->CountOfClusters <= 65535)) {
314 h->fattype = 0;
315 } else if (h->CountOfClusters < 4085) {
316 h->fattype = 12;
317 } else if (h->CountOfClusters < 65525) {
318 h->fattype = 16;
319 } else {
320 h->fattype = 32;
321 }
322}
151
323
152 close(0);
153 if (open(name, 0) != 0) {
154 perror(name);
155 exit(1);
324static void
325get_label(fstyp_pcfs_t *h)
326{
327 /*
328 * Use label from the boot sector by default.
329 * Can overwrite later with the one from root directory.
330 */
331 (void) memcpy(h->volume_label, PC_LABEL_ADDR(h), PC_LABEL_SIZE);
332 h->volume_label[PC_LABEL_SIZE] = '\0';
333
334 if (h->fattype == 0) {
335 return;
336 } else if (FSTYP_IS_32(h)) {
337 get_label_32(h);
338 } else {
339 get_label_16(h);
156 }
340 }
157 llseek(0, (offset_t)0, 0);
158 if (read(0, buf, sizeof (buf)) != sizeof (buf)) {
341}
159
342
160 /*
161 * As an fstyp command, this can get called for a device from
162 * any filesystem (or for that matter, a bogus device). The
163 * read() returns EINVAL when it's not a pcfs. In this case,
164 * don't print an error message.
165 */
166 if (errno != EINVAL) {
167 perror(name);
343/*
344 * Get volume label from the root directory entry.
345 * In FAT12/16 the root directory is of fixed size.
346 * It immediately follows the FATs
347 */
348static void
349get_label_16(fstyp_pcfs_t *h)
350{
351 ulong_t FirstRootDirSecNum;
352 int secsize;
353 off_t offset;
354 uint8_t buf[PC_SECSIZE * 4];
355 int i;
356 int nent, resid;
357
358 if ((secsize = h->bps) > sizeof (buf)) {
359 return;
360 }
361
362 FirstRootDirSecNum = PC_RESSEC(h) + h->bs.nfat * h->bs.fatsec;
363 offset = h->offset + FirstRootDirSecNum * secsize;
364 resid = PC_NROOTENT(h);
365
366 for (i = 0; i < h->RootDirSectors; i++) {
367 (void) lseek(h->fd, offset, SEEK_SET);
368 if (read(h->fd, buf, secsize) != secsize) {
369 return;
168 }
370 }
169 exit(1);
371
372 nent = secsize / sizeof (struct pcdir);
373 if (nent > resid) {
374 nent = resid;
375 }
376 if (dir_find_label(h, (struct pcdir *)buf, nent)) {
377 return;
378 }
379
380 resid -= nent;
381 offset += PC_SECSIZE;
170 }
382 }
383}
171
384
172 media = (unsigned char)PC_MEDIA(buf);
173 if (!valid_media(media))
174 exit(31+1);
175 if (!well_formed(buf))
176 exit(31+1);
177 printf("%s\n", "pcfs");
385/*
386 * Get volume label from the root directory entry.
387 * In FAT32 root is a usual directory, a cluster chain.
388 * It starts at BPB_RootClus.
389 */
390static void
391get_label_32(fstyp_pcfs_t *h)
392{
393 off_t offset;
394 int clustersize;
395 int n;
396 ulong_t FirstSectorofCluster;
397 uint8_t *buf;
398 int nent;
399 int cnt = 0;
178
400
179 if (!vflag)
180 exit(0);
401 clustersize = h->bs.spcl * h->bps;
402 if ((clustersize == 0) || (clustersize > FSTYP_MAX_CLUSTER_SIZE) ||
403 ((buf = calloc(1, clustersize)) == NULL)) {
404 return;
405 }
181
406
182 printf("Bytes Per Sector %d\t\tSectors Per Cluster %d\n",
183 (unsigned short)PC_BPSEC(buf), (unsigned char)PC_SPC(buf));
184 printf("Reserved Sectors %d\t\tNumber of FATs %d\n",
185 (unsigned short)PC_RESSEC(buf), (unsigned char)PC_NFAT(buf));
186 printf("Root Dir Entries %d\t\tNumber of Sectors %d\n",
187 (unsigned short)PC_NROOTENT(buf), (unsigned short)PC_NSEC(buf));
188 printf("Sectors Per FAT %d\t\tSectors Per Track %d\n",
189 (unsigned short)PC_SPF(buf), (unsigned short)PC_SPT(buf));
190 printf("Number of Heads %d\t\tNumber Hidden Sectors %d\n",
191 (unsigned short)PC_NHEAD(buf), (unsigned short)PC_HIDSEC(buf));
192 strncpy(label, PC_LAB_ADDR(buf), LABEL_SIZE);
193 label[LABEL_SIZE+1] = 0;
194 printf("Volume Label: %s\n", label);
195 printf("Drive Number: 0x%x\n", (unsigned char)PC_DRVNUM(buf));
196 printf("Media Type: 0x%x ", media);
407 for (n = h->bs32.f_rootcluster; n != 0; n = next_cluster_32(h, n)) {
408 FirstSectorofCluster =
409 (n - 2) * h->bs.spcl + h->FirstDataSector;
410 offset = h->offset + FirstSectorofCluster * h->bps;
411 (void) lseek(h->fd, offset, SEEK_SET);
412 if (read(h->fd, buf, clustersize) != clustersize) {
413 break;
414 }
197
415
198 switch (media) {
416 nent = clustersize / sizeof (struct pcdir);
417 if (dir_find_label(h, (struct pcdir *)buf, nent)) {
418 break;
419 }
420
421 if (++cnt > FSTYP_MAX_DIR_SIZE / clustersize) {
422 break;
423 }
424 }
425
426 free(buf);
427}
428
429/*
430 * Get a FAT entry pointing to the next file cluster
431 */
432int
433next_cluster_32(fstyp_pcfs_t *h, int n)
434{
435 uint8_t buf[PC_SECSIZE];
436 ulong_t ThisFATSecNum;
437 ulong_t ThisFATEntOffset;
438 off_t offset;
439 uint32_t val;
440 int next = 0;
441
442 ThisFATSecNum = PC_RESSEC(h) + (n * 4) / h->bps;
443 ThisFATEntOffset = (n * 4) % h->bps;
444 offset = h->offset + ThisFATSecNum * h->bps;
445
446 (void) lseek(h->fd, offset, SEEK_SET);
447 if (read(h->fd, buf, sizeof (buf)) == sizeof (buf)) {
448 val = buf[ThisFATEntOffset] & 0x0fffffff;
449 next = ltohi(val);
450 }
451
452 return (next);
453}
454
455/*
456 * Given an array of pcdir structs, find one containing volume label.
457 */
458static boolean_t
459dir_find_label(fstyp_pcfs_t *h, struct pcdir *d, int nent)
460{
461 int i;
462
463 for (i = 0; i < nent; i++, d++) {
464 if ((d->pcd_filename[0] != PCD_UNUSED) &&
465 (d->pcd_filename[0] != PCD_ERASED) &&
466 ((d->pcd_attr & (PCA_LABEL | PCA_DIR)) == PCA_LABEL) &&
467 (d->un.pcd_scluster_hi == 0) &&
468 (d->pcd_scluster_lo == 0)) {
469 (void) memcpy(h->volume_label, d->pcd_filename,
470 PC_LABEL_SIZE);
471 h->volume_label[PC_LABEL_SIZE] = '\0';
472 return (B_TRUE);
473 }
474 }
475 return (B_FALSE);
476}
477
478static int
479is_pcfs(fstyp_pcfs_t *h)
480{
481 int error;
482
483 if ((error = read_bootsec(h)) != 0) {
484 return (error);
485 }
486 if (!valid_media(h)) {
487 return (FSTYP_ERR_NO_MATCH);
488 }
489 if (!well_formed(h)) {
490 return (FSTYP_ERR_NO_MATCH);
491 }
492
493 calculate_parameters(h);
494 determine_fattype(h);
495 get_label(h);
496
497 return (0);
498}
499
500/* ARGSUSED */
501static int
502dumpfs(fstyp_pcfs_t *h, FILE *fout, FILE *ferr)
503{
504 (void) fprintf(fout,
505 "Bytes Per Sector %d\t\tSectors Per Cluster %d\n",
506 h->bps, h->bs.spcl);
507 (void) fprintf(fout,
508 "Reserved Sectors %d\t\tNumber of FATs %d\n",
509 (unsigned short)PC_RESSEC(h), h->bs.nfat);
510 (void) fprintf(fout,
511 "Root Dir Entries %d\t\tNumber of Sectors %d\n",
512 (unsigned short)PC_NROOTENT(h), (unsigned short)PC_NSEC(h));
513 (void) fprintf(fout,
514 "Sectors Per FAT %d\t\tSectors Per Track %d\n",
515 h->bs.fatsec, h->bs.spt);
516 (void) fprintf(fout,
517 "Number of Heads %d\t\tNumber Hidden Sectors %d\n",
518 h->bs.nhead, h->bs.hiddensec);
519 (void) fprintf(fout, "Volume ID: 0x%x\n", PC_VOLID(h));
520 (void) fprintf(fout, "Volume Label: %s\n", h->volume_label);
521 (void) fprintf(fout, "Drive Number: 0x%x\n", PC_DRVNUM(h));
522 (void) fprintf(fout, "Media Type: 0x%x ", h->bs.mediadesriptor);
523
524 switch (h->bs.mediadesriptor) {
199 case MD_FIXED:
525 case MD_FIXED:
200 printf("\"Fixed\" Disk\n");
526 (void) fprintf(fout, "\"Fixed\" Disk\n");
201 break;
202 case SS8SPT:
527 break;
528 case SS8SPT:
203 printf("Single Sided, 8 Sectors Per Track\n");
529 (void) fprintf(fout, "Single Sided, 8 Sectors Per Track\n");
204 break;
205 case DS8SPT:
530 break;
531 case DS8SPT:
206 printf("Double Sided, 8 Sectors Per Track\n");
532 (void) fprintf(fout, "Double Sided, 8 Sectors Per Track\n");
207 break;
208 case SS9SPT:
533 break;
534 case SS9SPT:
209 printf("Single Sided, 9 Sectors Per Track\n");
535 (void) fprintf(fout, "Single Sided, 9 Sectors Per Track\n");
210 break;
211 case DS9SPT:
536 break;
537 case DS9SPT:
212 printf("Double Sided, 9 Sectors Per Track\n");
538 (void) fprintf(fout, "Double Sided, 9 Sectors Per Track\n");
213 break;
214 case DS18SPT:
539 break;
540 case DS18SPT:
215 printf("Double Sided, 18 Sectors Per Track\n");
541 (void) fprintf(fout, "Double Sided, 18 Sectors Per Track\n");
216 break;
217 case DS9_15SPT:
542 break;
543 case DS9_15SPT:
218 printf("Double Sided, 9-15 Sectors Per Track\n");
544 (void) fprintf(fout, "Double Sided, 9-15 Sectors Per Track\n");
219 break;
220 default:
545 break;
546 default:
221 printf("Unknown Media Type\n");
547 (void) fprintf(fout, "Unknown Media Type\n");
222 }
223
548 }
549
224 close(0);
225 exit(0);
550 return (0);
226}
227
551}
552
228static int
229valid_media(unsigned char media_type)
230{
231 switch (media_type) {
553#define ADD_STRING(h, name, value) \
554 if (nvlist_add_string(h->attr, name, value) != 0) { \
555 return (FSTYP_ERR_NOMEM); \
556 }
232
557
233 case MD_FIXED:
234 case SS8SPT:
235 case DS8SPT:
236 case SS9SPT:
237 case DS9SPT:
238 case DS18SPT:
239 case DS9_15SPT:
240 return (1);
241 default:
242 return (0);
558#define ADD_UINT32(h, name, value) \
559 if (nvlist_add_uint32(h->attr, name, value) != 0) { \
560 return (FSTYP_ERR_NOMEM); \
243 }
561 }
244}
245
562
246int
247well_formed(unsigned char bs[])
563#define ADD_UINT64(h, name, value) \
564 if (nvlist_add_uint64(h->attr, name, value) != 0) { \
565 return (FSTYP_ERR_NOMEM); \
566 }
567
568#define ADD_BOOL(h, name, value) \
569 if (nvlist_add_boolean_value(h->attr, name, value) != 0) { \
570 return (FSTYP_ERR_NOMEM); \
571 }
572
573static int
574get_attr(fstyp_pcfs_t *h)
248{
575{
249 int fatmatch;
576 char s[64];
250
577
251 if (PC_EXTSIG(bs)) {
252 fatmatch = ((bs[PCFS_TYPESTRING_OFFSET16] == 'F' &&
253 bs[PCFS_TYPESTRING_OFFSET16 + 1] == 'A' &&
254 bs[PCFS_TYPESTRING_OFFSET16 + 2] == 'T') &&
255 (PC_SPF(bs) > 0) &&
256 ((PC_NSEC(bs) == 0 && PC_BIGNSEC(bs) > 0) ||
257 PC_NSEC(bs) > 0));
258 } else if (PC_EXTSIG32(bs)) {
259 fatmatch = ((bs[PCFS_TYPESTRING_OFFSET32] == 'F' &&
260 bs[PCFS_TYPESTRING_OFFSET32 + 1] == 'A' &&
261 bs[PCFS_TYPESTRING_OFFSET32 + 2] == 'T') &&
262 (PC_SPF(bs) == 0 && PC_BIGSPF(bs) > 0) &&
263 ((PC_NSEC(bs) == 0 && PC_BIGNSEC(bs) > 0) ||
264 PC_NSEC(bs) > 0));
265 } else {
266 fatmatch = (PC_NSEC(bs) > 0 && PC_SPF(bs) > 0);
578 ADD_UINT32(h, "bytes_per_sector", h->bps);
579 ADD_UINT32(h, "sectors_per_cluster", h->bs.spcl);
580 ADD_UINT32(h, "reserved_sectors", PC_RESSEC(h));
581 ADD_UINT32(h, "fats", h->bs.nfat);
582 ADD_UINT32(h, "root_entry_count", PC_NROOTENT(h));
583 ADD_UINT32(h, "total_sectors_16", PC_NSEC(h));
584 ADD_UINT32(h, "media", h->bs.mediadesriptor);
585 ADD_UINT32(h, "fat_size_16", h->bs.fatsec);
586 ADD_UINT32(h, "sectors_per_track", h->bs.spt);
587 ADD_UINT32(h, "heads", h->bs.nhead);
588 ADD_UINT32(h, "hidden_sectors", h->bs.hiddensec);
589 ADD_UINT32(h, "total_sectors_32", h->bs.totalsec);
590 ADD_UINT32(h, "drive_number", PC_DRVNUM(h));
591 ADD_UINT32(h, "volume_id", PC_VOLID(h));
592 ADD_STRING(h, "volume_label", h->volume_label);
593 if (FSTYP_IS_32(h)) {
594 ADD_UINT32(h, "fat_size_32", h->bs32.f_fatlength);
267 }
595 }
596 ADD_UINT32(h, "total_sectors", h->TotSec);
597 ADD_UINT32(h, "fat_size", h->FATSz);
598 ADD_UINT32(h, "count_of_clusters", h->CountOfClusters);
599 ADD_UINT32(h, "fat_entry_size", h->fattype);
268
600
269 return (fatmatch && PC_BPSEC(bs) > 0 && PC_BPSEC(bs) % 512 == 0 &&
270 PC_SPC(bs) > 0 && PC_RESSEC(bs) >= 1 && PC_NFAT(bs) > 0);
601 ADD_BOOL(h, "gen_clean", B_TRUE);
602 if (PC_VOLID(a) != 0) {
603 (void) snprintf(s, sizeof (s), "%08x", PC_VOLID(a));
604 ADD_STRING(h, "gen_guid", s);
605 }
606 (void) snprintf(s, sizeof (s), "%d", h->fattype);
607 ADD_STRING(h, "gen_version", s);
608 ADD_STRING(h, "gen_volume_label", h->volume_label);
609
610 return (0);
271}
611}