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 char *cbasename; 98 char *special; 99 char *fstype; 100 101 static void usage(void); 102 static void dumpfs(char *name); 103 static int valid_media(unsigned char media_type); 104 105 int 106 main(int argc, char *argv[]) 107 { 108 int c; 109 110 (void) setlocale(LC_ALL, ""); 111 #if !defined(TEXT_DOMAIN) 112 #define TEXT_DOMAIN "SYS_TEST" 113 #endif 114 (void) textdomain(TEXT_DOMAIN); 115 116 cbasename = argv[0]; 117 while ((c = getopt(argc, argv, "v")) != EOF) { 118 switch (c) { 119 120 case 'v': /* dump super block */ 121 vflag++; 122 break; 123 124 case '?': 125 errflag++; 126 } 127 } 128 if (errflag || argc <= optind) { 129 usage(); 130 exit(31+1); 131 } 132 special = argv[optind]; 133 dumpfs(special); 134 135 return (0); 136 } 137 138 139 static void 140 usage(void) 141 { 142 (void) fprintf(stderr, gettext("pcfs usage: fstyp [-v] special\n")); 143 } 144 145 static void 146 dumpfs(char *name) 147 { 148 unsigned char buf[DEV_BSIZE]; 149 char label[LABEL_SIZE+1]; 150 unsigned char media; 151 152 close(0); 153 if (open(name, 0) != 0) { 154 perror(name); 155 exit(1); 156 } 157 llseek(0, (offset_t)0, 0); 158 if (read(0, buf, sizeof (buf)) != sizeof (buf)) { 159 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); 168 } 169 exit(1); 170 } 171 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"); 178 179 if (!vflag) 180 exit(0); 181 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); 197 198 switch (media) { 199 case MD_FIXED: 200 printf("\"Fixed\" Disk\n"); 201 break; 202 case SS8SPT: 203 printf("Single Sided, 8 Sectors Per Track\n"); 204 break; 205 case DS8SPT: 206 printf("Double Sided, 8 Sectors Per Track\n"); 207 break; 208 case SS9SPT: 209 printf("Single Sided, 9 Sectors Per Track\n"); 210 break; 211 case DS9SPT: 212 printf("Double Sided, 9 Sectors Per Track\n"); 213 break; 214 case DS18SPT: 215 printf("Double Sided, 18 Sectors Per Track\n"); 216 break; 217 case DS9_15SPT: 218 printf("Double Sided, 9-15 Sectors Per Track\n"); 219 break; 220 default: 221 printf("Unknown Media Type\n"); 222 } 223 224 close(0); 225 exit(0); 226 } 227 228 static int 229 valid_media(unsigned char media_type) 230 { 231 switch (media_type) { 232 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); 243 } 244 } 245 246 int 247 well_formed(unsigned char bs[]) 248 { 249 int fatmatch; 250 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); 267 } 268 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); 271 } 272