diff options
Diffstat (limited to 'diskdev_cmds/fstyp.tproj')
-rw-r--r-- | diskdev_cmds/fstyp.tproj/fstyp.8 | 41 | ||||
-rw-r--r-- | diskdev_cmds/fstyp.tproj/fstyp.c | 167 | ||||
-rw-r--r-- | diskdev_cmds/fstyp.tproj/fstyp_msdos.8 | 41 | ||||
-rw-r--r-- | diskdev_cmds/fstyp.tproj/fstyp_msdos.c | 213 | ||||
-rw-r--r-- | diskdev_cmds/fstyp.tproj/fstyp_ntfs.8 | 41 | ||||
-rw-r--r-- | diskdev_cmds/fstyp.tproj/fstyp_ntfs.c | 206 | ||||
-rw-r--r-- | diskdev_cmds/fstyp.tproj/fstyp_udf.8 | 40 | ||||
-rw-r--r-- | diskdev_cmds/fstyp.tproj/fstyp_udf.c | 306 |
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; +} + + |