aboutsummaryrefslogtreecommitdiffstats
path: root/diskdev_cmds/fstyp.tproj
diff options
context:
space:
mode:
Diffstat (limited to 'diskdev_cmds/fstyp.tproj')
-rw-r--r--diskdev_cmds/fstyp.tproj/fstyp.841
-rw-r--r--diskdev_cmds/fstyp.tproj/fstyp.c167
-rw-r--r--diskdev_cmds/fstyp.tproj/fstyp_msdos.841
-rw-r--r--diskdev_cmds/fstyp.tproj/fstyp_msdos.c213
-rw-r--r--diskdev_cmds/fstyp.tproj/fstyp_ntfs.841
-rw-r--r--diskdev_cmds/fstyp.tproj/fstyp_ntfs.c206
-rw-r--r--diskdev_cmds/fstyp.tproj/fstyp_udf.840
-rw-r--r--diskdev_cmds/fstyp.tproj/fstyp_udf.c306
8 files changed, 1055 insertions, 0 deletions
diff --git a/diskdev_cmds/fstyp.tproj/fstyp.8 b/diskdev_cmds/fstyp.tproj/fstyp.8
new file mode 100644
index 0000000..fdc6ca2
--- /dev/null
+++ b/diskdev_cmds/fstyp.tproj/fstyp.8
@@ -0,0 +1,41 @@
+.\"
+.\" (c) 2005 Apple Computer, Inc. All rights reserved.
+.\"
+.\" @APPLE_LICENSE_HEADER_START@
+.\"
+.\" The contents of this file constitute Original Code as defined in and
+.\" are subject to the Apple Public Source License Version 1.1 (the
+.\" "License"). You may not use this file except in compliance with the
+.\" License. Please obtain a copy of the License at
+.\" http://www.apple.com/publicsource and read it before using this file.
+.\"
+.\" This Original Code and all software distributed under the License are
+.\" distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+.\" License for the specific language governing rights and limitations
+.\" under the License.
+.\"
+.\" @APPLE_LICENSE_HEADER_END@
+.\"
+.Dd August 15, 2005
+.Dt FSTYP 8
+.Os
+.Sh NAME
+.Nm fstyp
+.Nd identify a file system
+.Sh SYNOPSIS
+.Nm
+.Ar device
+.Sh DESCRIPTION
+The
+.Nm
+utility attempts to determine what sort of volume is present on the given
+device.
+It operates by iterating over directories that are typically part of the path,
+searching for files matching the pattern fstyp_* and running them.
+If it finds a match, it will print out the file system type name and exit with
+a return value of 1.
+If it does not find a match, it will not print out anything, and the return
+value will be 0.
diff --git a/diskdev_cmds/fstyp.tproj/fstyp.c b/diskdev_cmds/fstyp.tproj/fstyp.c
new file mode 100644
index 0000000..840c4aa
--- /dev/null
+++ b/diskdev_cmds/fstyp.tproj/fstyp.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sysexits.h>
+
+#define FSTYP_PREFIX "fstyp_"
+#define MAX_PATH_LEN 80
+#define MAX_CMD_LEN (MAX_PATH_LEN * 2)
+#define NULL_REDIRECTION ">/dev/null 2>&1"
+
+void usage(void);
+int select_fstyp(const struct dirent * dp);
+int test(const char *dir, const struct dirent * dp, const char *dev);
+void dealloc(struct dirent ** dpp, int numElems);
+
+char *progname;
+
+/*
+ * The fstyp command iterates through the binary directories to look for
+ * commands of the form fstyp_* and runs them, trying to find one that
+ * matches the given device. Once one of the returns success, fstyp
+ * prints out that file system type name and terminates. 1 is returned
+ * if any match is found, and 0 is returned if no match is found.
+ */
+
+int
+main(int argc, char *argv[])
+{
+ /* NULL-terminated list of directories to search for fstyp_* commands */
+ const char *DIRS[] = { "/bin/",
+ "/sbin/",
+ "/usr/bin/",
+ "/usr/sbin/",
+ "/usr/local/bin/",
+ "/usr/local/sbin/",
+ NULL};
+
+ int numMatches, i, j, found;
+ struct stat sb;
+ struct dirent **dpp;
+
+ numMatches = 0;
+ i = 0;
+ j = 0;
+ found = 0;
+
+ if ((progname = strrchr(*argv, '/')))
+ ++progname;
+ else
+ progname = *argv;
+
+ if (argc != 2) {
+ usage();
+ return EX_USAGE;
+ }
+ if (0 == stat(argv[1], &sb)) {
+ for (i = 0; (!found && (NULL != DIRS[i])); i++) {
+ /*
+ * scan DIRS[i] for files that start with
+ * "fstyp_"
+ */
+ numMatches = scandir(DIRS[i], &dpp, select_fstyp, NULL);
+
+ if (numMatches >= 0) {
+ for (j = 0; (!found && (j < numMatches)); j++) {
+ if (test(DIRS[i], dpp[j], argv[1]) == 1) {
+ puts(dpp[j]->d_name + 6);
+
+ found = 1;
+ }
+ }
+
+ dealloc(dpp, numMatches);
+ dpp = NULL;
+ }
+ }
+ }
+ return found;
+}
+
+int
+select_fstyp(const struct dirent * dp)
+{
+ return ((dp != NULL) &&
+ ((dp->d_type == DT_REG) || (dp->d_type == DT_LNK)) &&
+ (dp->d_namlen > strlen(FSTYP_PREFIX)) &&
+ (!strncmp(FSTYP_PREFIX, dp->d_name, strlen(FSTYP_PREFIX))));
+}
+
+/* return dp if successful, else return NULL */
+int
+test(const char *dir, const struct dirent * dp, const char *dev)
+{
+ char cmd[MAX_CMD_LEN + 1] = {0};
+ int status;
+ FILE *fileptr;
+
+ status = 0;
+
+ /* + 1 for white space */
+ if ((strlen(dir) + dp->d_namlen + 1 + strlen(dev) +
+ strlen(NULL_REDIRECTION)) > MAX_CMD_LEN) {
+ return 0;
+ }
+ snprintf(cmd, sizeof(cmd), "%s%s %s", dir, dp->d_name, dev);
+
+ if ((fileptr = popen(cmd, "r")) != NULL) {
+ status = pclose(fileptr);
+
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) == 1) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+void
+dealloc(struct dirent ** dpp, int numElems)
+{
+ int i;
+
+ for (i = 0; i < numElems; i++) {
+ free(dpp[i]);
+ dpp[i] = NULL;
+ }
+
+ free(dpp);
+
+ return;
+}
+
+
+void
+usage(void)
+{
+ fprintf(stdout, "usage: %s device\n", progname);
+ return;
+}
diff --git a/diskdev_cmds/fstyp.tproj/fstyp_msdos.8 b/diskdev_cmds/fstyp.tproj/fstyp_msdos.8
new file mode 100644
index 0000000..940bc78
--- /dev/null
+++ b/diskdev_cmds/fstyp.tproj/fstyp_msdos.8
@@ -0,0 +1,41 @@
+.\"
+.\" (c) 2005 Apple Computer, Inc. All rights reserved.
+.\"
+.\" @APPLE_LICENSE_HEADER_START@
+.\"
+.\" The contents of this file constitute Original Code as defined in and
+.\" are subject to the Apple Public Source License Version 1.1 (the
+.\" "License"). You may not use this file except in compliance with the
+.\" License. Please obtain a copy of the License at
+.\" http://www.apple.com/publicsource and read it before using this file.
+.\"
+.\" This Original Code and all software distributed under the License are
+.\" distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+.\" License for the specific language governing rights and limitations
+.\" under the License.
+.\"
+.\" @APPLE_LICENSE_HEADER_END@
+.\"
+.Dd August 15, 2005
+.Dt FSTYP_MSDOS 8
+.Os
+.Sh NAME
+.Nm fstyp_msdos
+.Nd check for an MSDOS FAT volume
+.Sh SYNOPSIS
+.Nm
+.Ar device
+.Sh DESCRIPTION
+The
+.Nm
+utility is not intended to be run directly, but rather called by
+.Xr fstyp 8
+while it is trying to determine which file system type is present on the
+given device.
+It returns 1 if it thinks the device contains an MSDOS FAT volume, and 0
+otherwise.
+.Sh SEE ALSO
+.Xr fstyp 8
diff --git a/diskdev_cmds/fstyp.tproj/fstyp_msdos.c b/diskdev_cmds/fstyp.tproj/fstyp_msdos.c
new file mode 100644
index 0000000..edf4551
--- /dev/null
+++ b/diskdev_cmds/fstyp.tproj/fstyp_msdos.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/disk.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+
+/* copied from diskdev_cmds/fsck_msdos/dosfs.h */
+#define DOSBOOTBLOCKSIZE 512
+#define MAX_SECTOR_SIZE 4096
+
+#define E_OPENDEV -1
+#define E_READ -5
+
+void usage(void);
+char *rawname(char *name);
+char *unrawname(char *name);
+int checkVolHdr(const unsigned char *volhdr);
+char *blockcheck(char *origname);
+
+char *progname;
+
+/*
+ * prefer to use raw device. TODO: suppose block device is valid but
+ * the corresponding raw device is not valid, then we fail. this is
+ * probably no the desired behavior.
+ */
+
+int
+main(int argc, char **argv)
+{
+ unsigned char volhdr[MAX_SECTOR_SIZE] = {0};
+ int fd, retval;
+ char *devname;
+
+ fd = -1;
+ retval = 0;
+
+ if ((progname = strrchr(*argv, '/')))
+ ++progname;
+ else
+ progname = *argv;
+
+ if (argc != 2) {
+ usage();
+ } else {
+ devname = blockcheck(argv[1]);
+
+ if (devname != NULL) {
+ if ((fd = open(devname, O_RDONLY, 0)) < 0) {
+ retval = E_OPENDEV;
+ } else if (read(fd, volhdr, MAX_SECTOR_SIZE) != MAX_SECTOR_SIZE) {
+ retval = E_READ;
+ } else {
+ retval = checkVolHdr(volhdr);
+ }
+
+ if (-1 != fd) {
+ close(fd);
+ fd = -1;
+ }
+ }
+ }
+
+ return retval;
+}
+
+void
+usage(void)
+{
+ fprintf(stdout, "usage: %s device\n", progname);
+ return;
+}
+
+/* copied from diskdev_cmds/fsck_hfs/utilities.c */
+char *
+rawname(char *name)
+{
+ static char rawbuf[32];
+ char *dp;
+
+ if ((dp = strrchr(name, '/')) == 0)
+ return (0);
+ *dp = 0;
+ (void) strlcpy(rawbuf, name, sizeof(rawbuf));
+ *dp = '/';
+ (void) strlcat(rawbuf, "/r", sizeof(rawbuf));
+ (void) strlcat(rawbuf, &dp[1], sizeof(rawbuf));
+
+ return (rawbuf);
+}
+
+/* copied from diskdev_cmds/fsck_hfs/utilities.c */
+char *
+unrawname(char *name)
+{
+ char *dp;
+ struct stat stb;
+ size_t dp_len;
+
+ if ((dp = strrchr(name, '/')) == 0)
+ return (name);
+ if (stat(name, &stb) < 0)
+ return (name);
+ if ((stb.st_mode & S_IFMT) != S_IFCHR)
+ return (name);
+ if (dp[1] != 'r')
+ return (name);
+ dp_len = strlen(&dp[2]) + 1;
+ (void)memmove(&dp[1], &dp[2], dp_len);
+
+ return (name);
+}
+
+/*
+ * copied from diskdev_cmds/fsck_hfs/utilities.c, and modified:
+ * 1) remove "hotroot"
+ * 2) if error, return NULL
+ * 3) if not a char device, return NULL (effectively, this is treated
+ * as error even if accessing the block device might have been OK)
+ */
+char *
+blockcheck(char *origname)
+{
+ struct stat stblock, stchar;
+ char *newname, *raw;
+ int retried;
+
+ retried = 0;
+ newname = origname;
+retry:
+ if (stat(newname, &stblock) < 0) {
+ perror(newname);
+ fprintf(stderr, "Can't stat %s\n", newname);
+ return NULL;
+ }
+ if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
+ raw = rawname(newname);
+ if (stat(raw, &stchar) < 0) {
+ perror(raw);
+ fprintf(stderr, "Can't stat %s\n", raw);
+ return NULL;
+ }
+ if ((stchar.st_mode & S_IFMT) == S_IFCHR) {
+ return (raw);
+ } else {
+ fprintf(stderr, "%s is not a character device\n", raw);
+ return NULL;
+ }
+ } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) {
+ newname = unrawname(newname);
+ retried++;
+ goto retry;
+ }
+ /* not a block or character device */
+ return NULL;
+}
+
+/*
+ * (sanity) check the volume header in volhdr
+ *
+ * return 1 if volhdr is a FAT volhdr, 0 otherwise
+ */
+int
+checkVolHdr(const unsigned char *volhdr)
+{
+ /* NTFS volumes have an OEMid of NTFS followed by four spaces. */
+ const char *ntfs_oemid = "NTFS ";
+ int retval;
+
+ retval = 1;
+
+ /* copied from diskdev_cmds/fsck_msdos/boot.c */
+
+ /*
+ * [2699033]
+ *
+ * The first three bytes are an Intel x86 jump instruction. It should
+ * be one of the following forms: 0xE9 0x?? 0x?? 0xEC 0x?? 0x90 where
+ * 0x?? means any byte value is OK.
+ */
+ if (volhdr[0] != 0xE9 && (volhdr[0] != 0xEB || volhdr[2] != 0x90)) {
+ retval = 0;
+ }
+ if (!memcmp(ntfs_oemid, volhdr + 3, 8))
+ retval = 0;
+ return retval;
+}
diff --git a/diskdev_cmds/fstyp.tproj/fstyp_ntfs.8 b/diskdev_cmds/fstyp.tproj/fstyp_ntfs.8
new file mode 100644
index 0000000..e5efa90
--- /dev/null
+++ b/diskdev_cmds/fstyp.tproj/fstyp_ntfs.8
@@ -0,0 +1,41 @@
+.\"
+.\" (c) 2006 Apple Computer, Inc. All rights reserved.
+.\"
+.\" @APPLE_LICENSE_HEADER_START@
+.\"
+.\" The contents of this file constitute Original Code as defined in and
+.\" are subject to the Apple Public Source License Version 1.1 (the
+.\" "License"). You may not use this file except in compliance with the
+.\" License. Please obtain a copy of the License at
+.\" http://www.apple.com/publicsource and read it before using this file.
+.\"
+.\" This Original Code and all software distributed under the License are
+.\" distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+.\" License for the specific language governing rights and limitations
+.\" under the License.
+.\"
+.\" @APPLE_LICENSE_HEADER_END@
+.\"
+.Dd September 30, 2006
+.Dt FSTYP_NTFS 8
+.Os
+.Sh NAME
+.Nm fstyp_ntfs
+.Nd check for a Windows NT File System (NTFS) volume
+.Sh SYNOPSIS
+.Nm
+.Ar device
+.Sh DESCRIPTION
+The
+.Nm
+utility is not intended to be run directly, but rather called by
+.Xr fstyp 8
+while it is trying to determine which file system type is present on the
+given device.
+It returns 1 if it thinks the device contains a Windows NT File System (NTFS)
+volume, and 0 otherwise.
+.Sh SEE ALSO
+.Xr fstyp 8
diff --git a/diskdev_cmds/fstyp.tproj/fstyp_ntfs.c b/diskdev_cmds/fstyp.tproj/fstyp_ntfs.c
new file mode 100644
index 0000000..88e7568
--- /dev/null
+++ b/diskdev_cmds/fstyp.tproj/fstyp_ntfs.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/disk.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+
+/* copied from diskdev_cmds/fsck_msdos/dosfs.h */
+#define DOSBOOTBLOCKSIZE 512
+#define MAX_SECTOR_SIZE 4096
+
+#define E_OPENDEV -1
+#define E_READ -5
+
+void usage(void);
+char *rawname(char *name);
+char *unrawname(char *name);
+int checkVolHdr(const unsigned char *volhdr);
+char *blockcheck(char *origname);
+
+char *progname;
+
+/*
+ * prefer to use raw device. TODO: suppose block device is valid but
+ * the corresponding raw device is not valid, then we fail. this is
+ * probably no the desired behavior.
+ */
+
+int
+main(int argc, char **argv)
+{
+ unsigned char volhdr[MAX_SECTOR_SIZE] = {0};
+ int fd, retval;
+ char *devname;
+
+ fd = -1;
+ retval = 0;
+
+ if ((progname = strrchr(*argv, '/')))
+ ++progname;
+ else
+ progname = *argv;
+
+ if (argc != 2) {
+ usage();
+ } else {
+ devname = blockcheck(argv[1]);
+
+ if (devname != NULL) {
+ if ((fd = open(devname, O_RDONLY, 0)) < 0) {
+ retval = E_OPENDEV;
+ } else if (read(fd, volhdr, MAX_SECTOR_SIZE) != MAX_SECTOR_SIZE) {
+ retval = E_READ;
+ } else {
+ retval = checkVolHdr(volhdr);
+ }
+
+ if (-1 != fd) {
+ close(fd);
+ fd = -1;
+ }
+ }
+ }
+
+ return retval;
+}
+
+void
+usage(void)
+{
+ fprintf(stdout, "usage: %s device\n", progname);
+ return;
+}
+
+/* copied from diskdev_cmds/fsck_hfs/utilities.c */
+char *
+rawname(char *name)
+{
+ static char rawbuf[32];
+ char *dp;
+
+ if ((dp = strrchr(name, '/')) == 0)
+ return (0);
+ *dp = 0;
+ (void) strlcpy(rawbuf, name, sizeof(rawbuf));
+ *dp = '/';
+ (void) strlcat(rawbuf, "/r", sizeof(rawbuf));
+ (void) strlcat(rawbuf, &dp[1], sizeof(rawbuf));
+
+ return (rawbuf);
+}
+
+/* copied from diskdev_cmds/fsck_hfs/utilities.c */
+char *
+unrawname(char *name)
+{
+ char *dp;
+ struct stat stb;
+ size_t dp_len;
+
+ if ((dp = strrchr(name, '/')) == 0)
+ return (name);
+ if (stat(name, &stb) < 0)
+ return (name);
+ if ((stb.st_mode & S_IFMT) != S_IFCHR)
+ return (name);
+ if (dp[1] != 'r')
+ return (name);
+ dp_len = strlen(&dp[2]) + 1;
+ (void)memmove(&dp[1], &dp[2], dp_len);
+
+ return (name);
+}
+
+/*
+ * copied from diskdev_cmds/fsck_hfs/utilities.c, and modified:
+ * 1) remove "hotroot"
+ * 2) if error, return NULL
+ * 3) if not a char device, return NULL (effectively, this is treated
+ * as error even if accessing the block device might have been OK)
+ */
+char *
+blockcheck(char *origname)
+{
+ struct stat stblock, stchar;
+ char *newname, *raw;
+ int retried;
+
+ retried = 0;
+ newname = origname;
+retry:
+ if (stat(newname, &stblock) < 0) {
+ perror(newname);
+ fprintf(stderr, "Can't stat %s\n", newname);
+ return NULL;
+ }
+ if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
+ raw = rawname(newname);
+ if (stat(raw, &stchar) < 0) {
+ perror(raw);
+ fprintf(stderr, "Can't stat %s\n", raw);
+ return NULL;
+ }
+ if ((stchar.st_mode & S_IFMT) == S_IFCHR) {
+ return (raw);
+ } else {
+ fprintf(stderr, "%s is not a character device\n", raw);
+ return NULL;
+ }
+ } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) {
+ newname = unrawname(newname);
+ retried++;
+ goto retry;
+ }
+ /* not a block or character device */
+ return NULL;
+}
+
+/*
+ * (sanity) check the volume header in volhdr
+ *
+ * return 1 if volhdr is a NTFS volhdr, 0 otherwise
+ */
+int
+checkVolHdr(const unsigned char *volhdr)
+{
+ /* NTFS volumes have an OEMid of NTFS followed by four spaces. */
+ const char *ntfs_oemid = "NTFS ";
+ int retval;
+
+ retval = 1;
+
+ /*
+ * Only check the OEMid. This should be sufficiently specific so it
+ * does not match anything else. If it ever does it would be easy to
+ * check more bootsector fields for validity...
+ */
+ if (memcmp(ntfs_oemid, volhdr + 3, 8))
+ retval = 0;
+ return retval;
+}
diff --git a/diskdev_cmds/fstyp.tproj/fstyp_udf.8 b/diskdev_cmds/fstyp.tproj/fstyp_udf.8
new file mode 100644
index 0000000..00efe55
--- /dev/null
+++ b/diskdev_cmds/fstyp.tproj/fstyp_udf.8
@@ -0,0 +1,40 @@
+.\"
+.\" (c) 2005 Apple Computer, Inc. All rights reserved.
+.\"
+.\" @APPLE_LICENSE_HEADER_START@
+.\"
+.\" The contents of this file constitute Original Code as defined in and
+.\" are subject to the Apple Public Source License Version 1.1 (the
+.\" "License"). You may not use this file except in compliance with the
+.\" License. Please obtain a copy of the License at
+.\" http://www.apple.com/publicsource and read it before using this file.
+.\"
+.\" This Original Code and all software distributed under the License are
+.\" distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+.\" License for the specific language governing rights and limitations
+.\" under the License.
+.\"
+.\" @APPLE_LICENSE_HEADER_END@
+.\"
+.Dd August 15, 2005
+.Dt FSTYP_UDF 8
+.Os
+.Sh NAME
+.Nm fstyp_udf
+.Nd check for a UDF volume
+.Sh SYNOPSIS
+.Nm
+.Ar device
+.Sh DESCRIPTION
+The
+.Nm
+utility is not intended to be run directly, but rather called by
+.Xr fstyp 8
+while it is trying to determine which file system type is present on the
+given device.
+It returns 1 if it thinks the device contains a UDF volume, and 0 otherwise.
+.Sh SEE ALSO
+.Xr fstyp 8
diff --git a/diskdev_cmds/fstyp.tproj/fstyp_udf.c b/diskdev_cmds/fstyp.tproj/fstyp_udf.c
new file mode 100644
index 0000000..7526524
--- /dev/null
+++ b/diskdev_cmds/fstyp.tproj/fstyp_udf.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fstab.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/disk.h>
+
+#define E_OPENDEV -1
+#define E_READ -5
+
+/*
+ * We don't have a (non-C++) standard header for UDF (yet?), so
+ * let's define the basic structures and constants we'll be using.
+ */
+
+typedef struct UDFVolumeSequenceDescriptor {
+ unsigned char type;
+ unsigned char id[5];
+ unsigned char version;
+ unsigned char data[2041];
+} udfVSD;
+
+#define UDFSTART (32*1024) /* First 32k is unused */
+
+void usage(void);
+char *rawname(char *name);
+char *unrawname(char *name);
+int CheckUDF(int, int);
+char *blockcheck(char *origname);
+
+char *progname;
+
+/*
+ * prefer to use raw device. TODO: suppose block device is valid but
+ * the corresponding raw device is not valid, then we fail. this is
+ * probably no the desired behavior.
+ */
+
+int
+main(int argc, char **argv)
+{
+ char *devname = NULL;
+ int fd, retval;
+
+ retval = 0;
+ fd = -1;
+
+ if ((progname = strrchr(*argv, '/')))
+ ++progname;
+ else
+ progname = *argv;
+
+ if (argc != 2) {
+ usage();
+ } else {
+ devname = blockcheck(argv[1]);
+ if (devname != NULL) {
+ if ((fd = open(devname, O_RDONLY, 0)) < 0) {
+ retval = E_OPENDEV;
+ } else {
+ int bsize;
+ if (ioctl(fd, DKIOCGETBLOCKSIZE, (char*)&bsize) == -1) {
+#ifdef DEBUG
+ warn("DKIOCGETBLOCKSIZE ioctl failed for %s", devname);
+#endif
+ bsize = 2048; /* A standard default size */
+ }
+ retval = CheckUDF(fd, bsize) == 1;
+ if (retval == 0 && bsize != 2048) {
+ retval = CheckUDF(fd, 2048) == 1;
+ }
+ }
+ }
+ }
+
+ return retval;
+}
+
+static int
+IsVSD(udfVSD *vsd) {
+ int retval = memcmp(vsd->id, "BEA01", 5)==0 ||
+ memcmp(vsd->id, "BOOT2", 5)==0 ||
+ memcmp(vsd->id, "NSR02", 5)==0 ||
+ memcmp(vsd->id, "NSR03", 5)==0 ||
+ memcmp(vsd->id, "TEA01", 5)==0 ||
+ memcmp(vsd->id, "CDW02", 5)==0 ||
+ memcmp(vsd->id, "CD001", 5)==0;
+#ifdef DEBUG
+ fprintf(stderr, "IsVSD: Returning %d\n", retval);
+#endif
+ return retval;
+}
+
+/*
+ * This is inspired by the udf25 kext code.
+ * It concludes that a device has a UDF filesystem
+ * if:
+ * 1) It has a Volume Sequence Descriptor;
+ * 2) That VSD has a "BEA01" in it;
+ * 3) That VSD has an "NSR02" or "NSR03" in it before the terminating one.
+ *
+ * It may be necessary to check the AVDP(s), as well.
+ */
+
+int
+CheckUDF(int fd, int blockSize) {
+ ssize_t err;
+ char buf[blockSize];
+ off_t curr, max;
+ char found = 0;
+
+ curr = UDFSTART;
+ max = curr + (512 * blockSize);
+ if (lseek(fd, curr, SEEK_SET) == -1) {
+ warn("Cannot seek to %llu", curr);
+ return -1;
+ }
+
+ while (curr < max) {
+ udfVSD *vsd;
+ err = read(fd, buf, sizeof(buf));
+ if (err != sizeof(buf)) {
+ if (err == -1) {
+ warn("Cannot read %zu bytes", sizeof(buf));
+ } else {
+ warn("Cannot read %zd bytes, only read %zd", sizeof(buf), err);
+ }
+ return -1;
+ }
+ vsd = (udfVSD*)buf;
+ if (!IsVSD(vsd)) {
+ break;
+ }
+ if (vsd->type == 0 &&
+ memcmp(vsd->id, "BEA01", 5) == 0 &&
+ vsd->version == 1) {
+ found = 1;
+ break;
+ }
+ curr += blockSize;
+ }
+ if (found == 0)
+ return 0;
+
+ found = 0;
+
+ while (curr < max) {
+ udfVSD *vsd;
+ err = read(fd, buf, sizeof(buf));
+ if (err != sizeof(buf)) {
+ if (err == -1) {
+ warn("Cannot read %zu bytes", sizeof(buf));
+ } else {
+ warn("Cannot read %zu bytes, only read %zd", sizeof(buf), err);
+ }
+ return -1;
+ }
+ vsd = (udfVSD*)buf;
+ if (!IsVSD(vsd)) {
+ break;
+ }
+ if (vsd->type == 0 &&
+ memcmp(vsd->id, "TEA01", 5) == 0 &&
+ vsd->version == 1) {
+ /* we're at the end */
+ break;
+ } else if (memcmp(vsd->id, "NSR02", 5) == 0 ||
+ memcmp(vsd->id, "NSR03", 5) == 0) {
+ found = 1;
+ break;
+ }
+ curr += blockSize;
+ }
+
+ return found;
+}
+
+void
+usage(void)
+{
+ fprintf(stdout, "usage: %s device\n", progname);
+ return;
+}
+
+/* copied from diskdev_cmds/fsck_hfs/utilities.c */
+char *
+rawname(char *name)
+{
+ static char rawbuf[32];
+ char *dp;
+
+ if ((dp = strrchr(name, '/')) == 0)
+ return (0);
+ *dp = 0;
+ (void) strlcpy(rawbuf, name, sizeof(rawbuf));
+ *dp = '/';
+ (void) strlcat(rawbuf, "/r", sizeof(rawbuf));
+ (void) strlcat(rawbuf, &dp[1], sizeof(rawbuf));
+
+ return (rawbuf);
+}
+
+/* copied from diskdev_cmds/fsck_hfs/utilities.c */
+char *
+unrawname(char *name)
+{
+ char *dp;
+ struct stat stb;
+ size_t dp_len;
+
+ if ((dp = strrchr(name, '/')) == 0)
+ return (name);
+ if (stat(name, &stb) < 0)
+ return (name);
+ if ((stb.st_mode & S_IFMT) != S_IFCHR)
+ return (name);
+ if (dp[1] != 'r')
+ return (name);
+ dp_len = strlen(&dp[2]) + 1;
+ (void)memmove(&dp[1], &dp[2], dp_len);
+
+ return (name);
+}
+
+/*
+ * copied from diskdev_cmds/fsck_hfs/utilities.c, and modified:
+ * 1) remove "hotroot"
+ * 2) if error, return NULL
+ * 3) if not a char device, return NULL (effectively, this is treated
+ * as error even if accessing the block device might have been OK)
+ */
+char *
+blockcheck(char *origname)
+{
+ struct stat stblock, stchar;
+ char *newname, *raw;
+ int retried = 0;
+
+ newname = origname;
+retry:
+ if (stat(newname, &stblock) < 0) {
+ perror(newname);
+ fprintf(stderr, "Can't stat %s\n", newname);
+ return NULL;
+ }
+ if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
+ raw = rawname(newname);
+ if (stat(raw, &stchar) < 0) {
+ perror(raw);
+ fprintf(stderr, "Can't stat %s\n", raw);
+ return NULL;
+ }
+ if ((stchar.st_mode & S_IFMT) == S_IFCHR) {
+ return (raw);
+ } else {
+ fprintf(stderr, "%s is not a character device\n", raw);
+ return NULL;
+ }
+ } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) {
+ newname = unrawname(newname);
+ retried++;
+ goto retry;
+ }
+#ifdef DEBUG
+ else if ((stblock.st_mode & S_IFMT) == S_IFREG) {
+ return strdup(origname);
+ }
+#endif
+ /* not a block or character device */
+ return NULL;
+}
+
+