2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <sys/param.h>
37 #include <sys/types.h>
38 #include <sys/ioctl.h>
45 * We don't have a (non-C++) standard header for UDF (yet?), so
46 * let's define the basic structures and constants we'll be using.
49 typedef struct UDFVolumeSequenceDescriptor
{
52 unsigned char version
;
53 unsigned char data
[2041];
56 #define UDFSTART (32*1024) /* First 32k is unused */
59 char *rawname(char *name
);
60 char *unrawname(char *name
);
61 int CheckUDF(int, int);
62 char *blockcheck(char *origname
);
67 * prefer to use raw device. TODO: suppose block device is valid but
68 * the corresponding raw device is not valid, then we fail. this is
69 * probably no the desired behavior.
73 main(int argc
, char **argv
)
81 if ((progname
= strrchr(*argv
, '/')))
89 devname
= blockcheck(argv
[1]);
90 if (devname
!= NULL
) {
91 if ((fd
= open(devname
, O_RDONLY
, 0)) < 0) {
95 if (ioctl(fd
, DKIOCGETBLOCKSIZE
, (char*)&bsize
) == -1) {
97 warn("DKIOCGETBLOCKSIZE ioctl failed for %s", devname
);
99 bsize
= 2048; /* A standard default size */
101 retval
= CheckUDF(fd
, bsize
) == 1;
102 if (retval
== 0 && bsize
!= 2048) {
103 retval
= CheckUDF(fd
, 2048) == 1;
114 int retval
= memcmp(vsd
->id
, "BEA01", 5)==0 ||
115 memcmp(vsd
->id
, "BOOT2", 5)==0 ||
116 memcmp(vsd
->id
, "NSR02", 5)==0 ||
117 memcmp(vsd
->id
, "NSR03", 5)==0 ||
118 memcmp(vsd
->id
, "TEA01", 5)==0 ||
119 memcmp(vsd
->id
, "CDW02", 5)==0 ||
120 memcmp(vsd
->id
, "CD001", 5)==0;
122 fprintf(stderr
, "IsVSD: Returning %d\n", retval
);
128 * This is inspired by the udf25 kext code.
129 * It concludes that a device has a UDF filesystem
131 * 1) It has a Volume Sequence Descriptor;
132 * 2) That VSD has a "BEA01" in it;
133 * 3) That VSD has an "NSR02" or "NSR03" in it before the terminating one.
135 * It may be necessary to check the AVDP(s), as well.
139 CheckUDF(int fd
, int blockSize
) {
146 max
= curr
+ (512 * blockSize
);
147 if (lseek(fd
, curr
, SEEK_SET
) == -1) {
148 warn("Cannot seek to %llu", curr
);
154 err
= read(fd
, buf
, sizeof(buf
));
155 if (err
!= sizeof(buf
)) {
157 warn("Cannot read %zu bytes", sizeof(buf
));
159 warn("Cannot read %zd bytes, only read %zd", sizeof(buf
), err
);
167 if (vsd
->type
== 0 &&
168 memcmp(vsd
->id
, "BEA01", 5) == 0 &&
182 err
= read(fd
, buf
, sizeof(buf
));
183 if (err
!= sizeof(buf
)) {
185 warn("Cannot read %zu bytes", sizeof(buf
));
187 warn("Cannot read %zu bytes, only read %zd", sizeof(buf
), err
);
195 if (vsd
->type
== 0 &&
196 memcmp(vsd
->id
, "TEA01", 5) == 0 &&
198 /* we're at the end */
200 } else if (memcmp(vsd
->id
, "NSR02", 5) == 0 ||
201 memcmp(vsd
->id
, "NSR03", 5) == 0) {
214 fprintf(stdout
, "usage: %s device\n", progname
);
218 /* copied from diskdev_cmds/fsck_hfs/utilities.c */
222 static char rawbuf
[32];
225 if ((dp
= strrchr(name
, '/')) == 0)
228 (void) strlcpy(rawbuf
, name
, sizeof(rawbuf
));
230 (void) strlcat(rawbuf
, "/r", sizeof(rawbuf
));
231 (void) strlcat(rawbuf
, &dp
[1], sizeof(rawbuf
));
236 /* copied from diskdev_cmds/fsck_hfs/utilities.c */
238 unrawname(char *name
)
244 if ((dp
= strrchr(name
, '/')) == 0)
246 if (stat(name
, &stb
) < 0)
248 if ((stb
.st_mode
& S_IFMT
) != S_IFCHR
)
252 dp_len
= strlen(&dp
[2]) + 1;
253 (void)memmove(&dp
[1], &dp
[2], dp_len
);
259 * copied from diskdev_cmds/fsck_hfs/utilities.c, and modified:
260 * 1) remove "hotroot"
261 * 2) if error, return NULL
262 * 3) if not a char device, return NULL (effectively, this is treated
263 * as error even if accessing the block device might have been OK)
266 blockcheck(char *origname
)
268 struct stat stblock
, stchar
;
274 if (stat(newname
, &stblock
) < 0) {
276 fprintf(stderr
, "Can't stat %s\n", newname
);
279 if ((stblock
.st_mode
& S_IFMT
) == S_IFBLK
) {
280 raw
= rawname(newname
);
281 if (stat(raw
, &stchar
) < 0) {
283 fprintf(stderr
, "Can't stat %s\n", raw
);
286 if ((stchar
.st_mode
& S_IFMT
) == S_IFCHR
) {
289 fprintf(stderr
, "%s is not a character device\n", raw
);
292 } else if ((stblock
.st_mode
& S_IFMT
) == S_IFCHR
&& !retried
) {
293 newname
= unrawname(newname
);
298 else if ((stblock
.st_mode
& S_IFMT
) == S_IFREG
) {
299 return strdup(origname
);
302 /* not a block or character device */