]> git.saurik.com Git - apple/hfs.git/blame - fstyp_hfs/fstyp_hfs.c
hfs-556.100.11.tar.gz
[apple/hfs.git] / fstyp_hfs / fstyp_hfs.c
CommitLineData
51e135ce
A
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
558d2836
A
108 (void) memset(rawbuf, 0, sizeof(rawbuf));
109
110 /* find the last "/" in a path, like /dev/disk2 */
51e135ce 111 if ((dp = strrchr(name, '/')) == 0)
558d2836
A
112 return NULL;
113
114 /* temporarily replace the last "/" with a NUL */
51e135ce 115 *dp = 0;
558d2836
A
116
117 /* copy name, with the "/" removed into 'rawbuf' */
118 (void) strlcpy(rawbuf, name, sizeof(rawbuf));
119
120 /* replace the "/" back */
51e135ce 121 *dp = '/';
558d2836
A
122
123 /* Now add the "/r" to make it a raw device */
124 (void) strlcat(rawbuf, "/r", sizeof(rawbuf));
125
126 /* then copy the rest of the string (after the /) into place */
127 (void) strlcat(rawbuf, &dp[1], sizeof(rawbuf));
51e135ce
A
128
129 return (rawbuf);
130}
131
132/* copied from diskdev_cmds/fsck_hfs/utilities.c */
133char *
134unrawname(char *name)
135{
136 char *dp;
137 struct stat stb;
138
139 if ((dp = strrchr(name, '/')) == 0)
140 return (name);
141 if (stat(name, &stb) < 0)
142 return (name);
143 if ((stb.st_mode & S_IFMT) != S_IFCHR)
144 return (name);
145 if (dp[1] != 'r')
146 return (name);
147 (void) strcpy(&dp[1], &dp[2]);
148
149 return (name);
150}
151
152/*
153 * copied from diskdev_cmds/fsck_hfs/utilities.c, and modified:
154 * 1) remove "hotroot"
155 * 2) if error, return NULL
156 * 3) if not a char device, return NULL (effectively, this is treated
157 * as error even if accessing the block device might have been OK)
158 */
159char *
160blockcheck(char *origname)
161{
162 struct stat stblock, stchar;
163 char *newname, *raw;
164 int retried;
165
166 retried = 0;
167 newname = origname;
168retry:
169 if (stat(newname, &stblock) < 0) {
170 perror(newname);
171 fprintf(stderr, "Can't stat %s\n", newname);
172 return NULL;
173 }
174 if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
175 raw = rawname(newname);
176 if (stat(raw, &stchar) < 0) {
177 perror(raw);
178 fprintf(stderr, "Can't stat %s\n", raw);
179 return NULL;
180 }
181 if ((stchar.st_mode & S_IFMT) == S_IFCHR) {
182 return (raw);
183 } else {
184 fprintf(stderr, "%s is not a character device\n", raw);
185 return NULL;
186 }
187 } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) {
188 newname = unrawname(newname);
189 retried++;
190 goto retry;
191 }
192 /* not a block or character device */
193 return NULL;
194}
195
196/*
197 * (sanity) check the volume header in volhdr
198 *
199 * return 1 if volhdr is an HFS volhdr, 0 otherwise
200 */
201int
202checkVolHdr(const unsigned char *volhdr)
203{
204 int retval;
205
206 retval = 0;
207
208 if (strncmp((const char *)volhdr, "H+", 2) == 0) {
209 /* technote 1150: H+ is version 4 */
210 retval = (volhdr[3] == 4);
211 } else if (strncmp((const char *)volhdr, "HX", 2) == 0) {
212 /* technote 1150: HX is version 5 */
213 retval = (volhdr[3] == 5);
214 }
215 return retval;
216}