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#define HFS_VOLHDR_OFFSET 1024 /* technote 1150 */ 34#define HFS_VOLHDR_SIZE 512 /* technote 1150 */ 35 36#define E_OPENDEV -1 37#define E_READ -5 38 39void usage(void); 40char *rawname(char *name); 41char *unrawname(char *name); 42int checkVolHdr(const unsigned char *volhdr); 43char *blockcheck(char *origname); 44 45char *progname; 46 47/* 48 * perhaps check the alternate volume header as well 49 50 * prefer to use raw device. TODO: suppose block device is valid but 51 * the corresponding raw device is not valid, then we fail. this is 52 * probably no the desired behavior. 53 */ 54 55int 56main(int argc, char **argv) 57{ 58 unsigned char volhdr[HFS_VOLHDR_SIZE] = {0}; 59 int fd, retval; 60 char *devname; 61 62 fd = -1; 63 retval = 0; 64 65 if ((progname = strrchr(*argv, '/'))) 66 ++progname; 67 else 68 progname = *argv; 69 70 if (argc != 2) { 71 usage(); 72 } else { 73 devname = blockcheck(argv[1]); 74 75 if (devname != NULL) { 76 if ((fd = open(devname, O_RDONLY, 0)) < 0) { 77 retval = E_OPENDEV; 78 } else if (pread(fd, volhdr, HFS_VOLHDR_SIZE, HFS_VOLHDR_OFFSET) != HFS_VOLHDR_SIZE) { 79 retval = E_READ; 80 } else { 81 retval = checkVolHdr(volhdr); 82 } 83 84 if (-1 != fd) { 85 close(fd); 86 fd = -1; 87 } 88 } 89 } 90 91 return retval; 92} 93 94void 95usage(void) 96{ 97 fprintf(stdout, "usage: %s device\n", progname); 98 return; 99} 100 101/* copied from diskdev_cmds/fsck_hfs/utilities.c */ 102char * 103rawname(char *name) 104{ 105 static char rawbuf[32]; 106 char *dp; 107 108 if ((dp = strrchr(name, '/')) == 0) 109 return (0); 110 *dp = 0; 111 (void) strcpy(rawbuf, name); 112 *dp = '/'; 113 (void) strcat(rawbuf, "/r"); 114 (void) strcat(rawbuf, &dp[1]); 115 116 return (rawbuf); 117} 118 119/* copied from diskdev_cmds/fsck_hfs/utilities.c */ 120char * 121unrawname(char *name) 122{ 123 char *dp; 124 struct stat stb; 125 126 if ((dp = strrchr(name, '/')) == 0) 127 return (name); 128 if (stat(name, &stb) < 0) 129 return (name); 130 if ((stb.st_mode & S_IFMT) != S_IFCHR) 131 return (name); 132 if (dp[1] != 'r') 133 return (name); 134 (void) strcpy(&dp[1], &dp[2]); 135 136 return (name); 137} 138 139/* 140 * copied from diskdev_cmds/fsck_hfs/utilities.c, and modified: 141 * 1) remove "hotroot" 142 * 2) if error, return NULL 143 * 3) if not a char device, return NULL (effectively, this is treated 144 * as error even if accessing the block device might have been OK) 145 */ 146char * 147blockcheck(char *origname) 148{ 149 struct stat stblock, stchar; 150 char *newname, *raw; 151 int retried; 152 153 retried = 0; 154 newname = origname; 155retry: 156 if (stat(newname, &stblock) < 0) { 157 perror(newname); 158 fprintf(stderr, "Can't stat %s\n", newname); 159 return NULL; 160 } 161 if ((stblock.st_mode & S_IFMT) == S_IFBLK) { 162 raw = rawname(newname); 163 if (stat(raw, &stchar) < 0) { 164 perror(raw); 165 fprintf(stderr, "Can't stat %s\n", raw); 166 return NULL; 167 } 168 if ((stchar.st_mode & S_IFMT) == S_IFCHR) { 169 return (raw); 170 } else { 171 fprintf(stderr, "%s is not a character device\n", raw); 172 return NULL; 173 } 174 } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) { 175 newname = unrawname(newname); 176 retried++; 177 goto retry; 178 } 179 /* not a block or character device */ 180 return NULL; 181} 182 183/* 184 * (sanity) check the volume header in volhdr 185 * 186 * return 1 if volhdr is an HFS volhdr, 0 otherwise 187 */ 188int 189checkVolHdr(const unsigned char *volhdr) 190{ 191 int retval; 192 193 retval = 0; 194 195 if (strncmp((const char *)volhdr, "H+", 2) == 0) { 196 /* technote 1150: H+ is version 4 */ 197 retval = (volhdr[3] == 4); 198 } else if (strncmp((const char *)volhdr, "HX", 2) == 0) { 199 /* technote 1150: HX is version 5 */ 200 retval = (volhdr[3] == 5); 201 } 202 return retval; 203} 204