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. 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 /* 23 * Copyright 2005 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 /* 38 * fstyp 39 * 40 * Designed to work with block devices (e.g., /dev/diskette), not 41 * raw devices (e.g., /dev/rdiskette) 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> 49 #include <sys/stat.h> 50 #include <sys/vfs.h> 51 52 #include <stdio.h> 53 #include <sys/mnttab.h> 54 55 #include <locale.h> 56 57 extern offset_t llseek(); 58 59 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 */ 72 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])) 88 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? */ 94 95 int vflag = 0; /* verbose output */ 96 int errflag = 0; 97 extern int optind; 98 char *cbasename; 99 char *special; 100 char *fstype; 101 102 int 103 main(argc, argv) 104 int argc; 105 char *argv[]; 106 { 107 int c; 108 109 (void) setlocale(LC_ALL, ""); 110 #if !defined(TEXT_DOMAIN) 111 #define TEXT_DOMAIN "SYS_TEST" 112 #endif 113 (void) textdomain(TEXT_DOMAIN); 114 115 cbasename = argv[0]; 116 while ((c = getopt(argc, argv, "v")) != EOF) { 117 switch (c) { 118 119 case 'v': /* dump super block */ 120 vflag++; 121 break; 122 123 case '?': 124 errflag++; 125 } 126 } 127 if (errflag || argc <= optind) { 128 usage(); 129 exit(31+1); 130 } 131 special = argv[optind]; 132 dumpfs(special); 133 134 /* NOTREACHED */ 135 } 136 137 138 usage() 139 { 140 (void) fprintf(stderr, gettext("pcfs usage: fstyp [-v] special\n")); 141 } 142 143 144 dumpfs(name) 145 char *name; 146 { 147 unsigned char buf[DEV_BSIZE]; 148 char label[LABEL_SIZE+1]; 149 unsigned char media; 150 151 close(0); 152 if (open(name, 0) != 0) { 153 perror(name); 154 exit(1); 155 } 156 llseek(0, (offset_t)0, 0); 157 if (read(0, buf, sizeof (buf)) != sizeof (buf)) { 158 159 /* 160 * As an fstyp command, this can get called for a device from 161 * any filesystem (or for that matter, a bogus device). The 162 * read() returns EINVAL when it's not a pcfs. In this case, 163 * don't print an error message. 164 */ 165 if (errno != EINVAL) { 166 perror(name); 167 } 168 exit(1); 169 } 170 171 media = (unsigned char)PC_MEDIA(buf); 172 if (!valid_media(media)) 173 exit(31+1); 174 if (!well_formed(buf)) 175 exit(31+1); 176 printf("%s\n", "pcfs"); 177 178 if (!vflag) 179 exit(0); 180 181 printf("Bytes Per Sector %d\t\tSectors Per Cluster %d\n", 182 (unsigned short)PC_BPSEC(buf), (unsigned char)PC_SPC(buf)); 183 printf("Reserved Sectors %d\t\tNumber of FATs %d\n", 184 (unsigned short)PC_RESSEC(buf), (unsigned char)PC_NFAT(buf)); 185 printf("Root Dir Entries %d\t\tNumber of Sectors %d\n", 186 (unsigned short)PC_NROOTENT(buf), (unsigned short)PC_NSEC(buf)); 187 printf("Sectors Per FAT %d\t\tSectors Per Track %d\n", 188 (unsigned short)PC_SPF(buf), (unsigned short)PC_SPT(buf)); 189 printf("Number of Heads %d\t\tNumber Hidden Sectors %d\n", 190 (unsigned short)PC_NHEAD(buf), (unsigned short)PC_HIDSEC(buf)); 191 strncpy(label, PC_LAB_ADDR(buf), LABEL_SIZE); 192 label[LABEL_SIZE+1] = 0; 193 printf("Volume Label: %s\n", label); 194 printf("Drive Number: 0x%x\n", (unsigned char)PC_DRVNUM(buf)); 195 printf("Media Type: 0x%x ", media); 196 197 switch (media) { 198 case MD_FIXED: 199 printf("\"Fixed\" Disk\n"); 200 break; 201 case SS8SPT: 202 printf("Single Sided, 8 Sectors Per Track\n"); 203 break; 204 case DS8SPT: 205 printf("Double Sided, 8 Sectors Per Track\n"); 206 break; 207 case SS9SPT: 208 printf("Single Sided, 9 Sectors Per Track\n"); 209 break; 210 case DS9SPT: 211 printf("Double Sided, 9 Sectors Per Track\n"); 212 break; 213 case DS18SPT: 214 printf("Double Sided, 18 Sectors Per Track\n"); 215 break; 216 case DS9_15SPT: 217 printf("Double Sided, 9-15 Sectors Per Track\n"); 218 break; 219 default: 220 printf("Unknown Media Type\n"); 221 } 222 223 close(0); 224 exit(0); 225 } 226 227 valid_media(media_type) 228 unsigned char media_type; 229 { 230 switch (media_type) { 231 232 case MD_FIXED: 233 case SS8SPT: 234 case DS8SPT: 235 case SS9SPT: 236 case DS9SPT: 237 case DS18SPT: 238 case DS9_15SPT: 239 return (1); 240 default: 241 return (0); 242 } 243 } 244 245 well_formed(unsigned char bs[]) 246 { 247 int fatmatch; 248 249 if (PC_EXTSIG(bs)) { 250 fatmatch = ((bs[PCFS_TYPESTRING_OFFSET16] == 'F' && 251 bs[PCFS_TYPESTRING_OFFSET16 + 1] == 'A' && 252 bs[PCFS_TYPESTRING_OFFSET16 + 2] == 'T') && 253 (PC_SPF(bs) > 0) && 254 ((PC_NSEC(bs) == 0 && PC_BIGNSEC(bs) > 0) || 255 PC_NSEC(bs) > 0)); 256 } else if (PC_EXTSIG32(bs)) { 257 fatmatch = ((bs[PCFS_TYPESTRING_OFFSET32] == 'F' && 258 bs[PCFS_TYPESTRING_OFFSET32 + 1] == 'A' && 259 bs[PCFS_TYPESTRING_OFFSET32 + 2] == 'T') && 260 (PC_SPF(bs) == 0 && PC_BIGSPF(bs) > 0) && 261 ((PC_NSEC(bs) == 0 && PC_BIGNSEC(bs) > 0) || 262 PC_NSEC(bs) > 0)); 263 } else { 264 fatmatch = (PC_NSEC(bs) > 0 && PC_SPF(bs) > 0); 265 } 266 267 return (fatmatch && PC_BPSEC(bs) > 0 && PC_BPSEC(bs) % 512 == 0 && 268 PC_SPC(bs) > 0 && PC_RESSEC(bs) >= 1 && PC_NFAT(bs) > 0); 269 } 270