1/* 2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include <stdio.h> 25#include <stdlib.h> 26#include <sys/disk.h> 27#include <fcntl.h> 28#include <errno.h> 29#include <unistd.h> 30#include <string.h> 31#include <sys/stat.h> 32 33/* copied from diskdev_cmds/fsck_msdos/dosfs.h */ 34#define DOSBOOTBLOCKSIZE 512 35#define MAX_SECTOR_SIZE 4096 36 37#define E_OPENDEV -1 38#define E_READ -5 39 40void usage(void); 41char *rawname(char *name); 42char *unrawname(char *name); 43int checkVolHdr(const unsigned char *volhdr); 44char *blockcheck(char *origname); 45 46char *progname; 47 48/* 49 * prefer to use raw device. TODO: suppose block device is valid but 50 * the corresponding raw device is not valid, then we fail. this is 51 * probably no the desired behavior. 52 */ 53 54int 55main(int argc, char **argv) 56{ 57 unsigned char volhdr[MAX_SECTOR_SIZE] = {0}; 58 int fd, retval; 59 char *devname; 60 61 fd = -1; 62 retval = 0; 63 64 if ((progname = strrchr(*argv, '/'))) 65 ++progname; 66 else 67 progname = *argv; 68 69 if (argc != 2) { 70 usage(); 71 } else { 72 devname = blockcheck(argv[1]); 73 74 if (devname != NULL) { 75 if ((fd = open(devname, O_RDONLY, 0)) < 0) { 76 retval = E_OPENDEV; 77 } else if (read(fd, volhdr, MAX_SECTOR_SIZE) != MAX_SECTOR_SIZE) { 78 retval = E_READ; 79 } else { 80 retval = checkVolHdr(volhdr); 81 } 82 83 if (-1 != fd) { 84 close(fd); 85 fd = -1; 86 } 87 } 88 } 89 90 return retval; 91} 92 93void 94usage(void) 95{ 96 fprintf(stdout, "usage: %s device\n", progname); 97 return; 98} 99 100/* copied from diskdev_cmds/fsck_hfs/utilities.c */ 101char * 102rawname(char *name) 103{ 104 static char rawbuf[32]; 105 char *dp; 106 107 if ((dp = strrchr(name, '/')) == 0) 108 return (0); 109 *dp = 0; 110 (void) strcpy(rawbuf, name); 111 *dp = '/'; 112 (void) strcat(rawbuf, "/r"); 113 (void) strcat(rawbuf, &dp[1]); 114 115 return (rawbuf); 116} 117 118/* copied from diskdev_cmds/fsck_hfs/utilities.c */ 119char * 120unrawname(char *name) 121{ 122 char *dp; 123 struct stat stb; 124 125 if ((dp = strrchr(name, '/')) == 0) 126 return (name); 127 if (stat(name, &stb) < 0) 128 return (name); 129 if ((stb.st_mode & S_IFMT) != S_IFCHR) 130 return (name); 131 if (dp[1] != 'r') 132 return (name); 133 (void) strcpy(&dp[1], &dp[2]); 134 135 return (name); 136} 137 138/* 139 * copied from diskdev_cmds/fsck_hfs/utilities.c, and modified: 140 * 1) remove "hotroot" 141 * 2) if error, return NULL 142 * 3) if not a char device, return NULL (effectively, this is treated 143 * as error even if accessing the block device might have been OK) 144 */ 145char * 146blockcheck(char *origname) 147{ 148 struct stat stblock, stchar; 149 char *newname, *raw; 150 int retried; 151 152 retried = 0; 153 newname = origname; 154retry: 155 if (stat(newname, &stblock) < 0) { 156 perror(newname); 157 fprintf(stderr, "Can't stat %s\n", newname); 158 return NULL; 159 } 160 if ((stblock.st_mode & S_IFMT) == S_IFBLK) { 161 raw = rawname(newname); 162 if (stat(raw, &stchar) < 0) { 163 perror(raw); 164 fprintf(stderr, "Can't stat %s\n", raw); 165 return NULL; 166 } 167 if ((stchar.st_mode & S_IFMT) == S_IFCHR) { 168 return (raw); 169 } else { 170 fprintf(stderr, "%s is not a character device\n", raw); 171 return NULL; 172 } 173 } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) { 174 newname = unrawname(newname); 175 retried++; 176 goto retry; 177 } 178 /* not a block or character device */ 179 return NULL; 180} 181 182/* 183 * (sanity) check the volume header in volhdr 184 * 185 * return 1 if volhdr is a FAT volhdr, 0 otherwise 186 */ 187int 188checkVolHdr(const unsigned char *volhdr) 189{ 190 /* NTFS volumes have an OEMid of NTFS followed by four spaces. */ 191 const char *ntfs_oemid = "NTFS "; 192 int retval; 193 194 retval = 1; 195 196 /* copied from diskdev_cmds/fsck_msdos/boot.c */ 197 198 /* 199 * [2699033] 200 * 201 * The first three bytes are an Intel x86 jump instruction. It should 202 * be one of the following forms: 0xE9 0x?? 0x?? 0xEC 0x?? 0x90 where 203 * 0x?? means any byte value is OK. 204 */ 205 if (volhdr[0] != 0xE9 && (volhdr[0] != 0xEB || volhdr[2] != 0x90)) { 206 retval = 0; 207 } 208 if (!memcmp(ntfs_oemid, volhdr + 3, 8)) 209 retval = 0; 210 return retval; 211} 212