From 3e3c248f832f796881ac2ce0d45049552e8d9a9b Mon Sep 17 00:00:00 2001 From: trasz Date: Wed, 10 Dec 2014 14:14:16 +0000 Subject: Add fstyp(8). This utility, named after its SVR4 counterpart, detects filesystems. It differs from file(1) in that it gives machine-parseable output, it outputs filesystem labels, doesn't get confused by other formats metadata, and runs in Capsicum sandbox. Differential Revision: https://reviews.freebsd.org/D1255 Relnotes: yes Sponsored by: The FreeBSD Foundation --- contrib/file/doc/file.man | 3 +- sbin/mount/mount.8 | 3 +- usr.sbin/Makefile | 1 + usr.sbin/fstyp/Makefile | 9 ++ usr.sbin/fstyp/cd9660.c | 72 ++++++++++++++++ usr.sbin/fstyp/ext2fs.c | 90 ++++++++++++++++++++ usr.sbin/fstyp/fstyp.8 | 97 +++++++++++++++++++++ usr.sbin/fstyp/fstyp.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++ usr.sbin/fstyp/fstyp.h | 46 ++++++++++ usr.sbin/fstyp/msdosfs.c | 183 ++++++++++++++++++++++++++++++++++++++++ usr.sbin/fstyp/msdosfs.h | 140 +++++++++++++++++++++++++++++++ usr.sbin/fstyp/ntfs.c | 165 ++++++++++++++++++++++++++++++++++++ usr.sbin/fstyp/ufs.c | 109 ++++++++++++++++++++++++ 13 files changed, 1126 insertions(+), 2 deletions(-) create mode 100644 usr.sbin/fstyp/Makefile create mode 100644 usr.sbin/fstyp/cd9660.c create mode 100644 usr.sbin/fstyp/ext2fs.c create mode 100644 usr.sbin/fstyp/fstyp.8 create mode 100644 usr.sbin/fstyp/fstyp.c create mode 100644 usr.sbin/fstyp/fstyp.h create mode 100644 usr.sbin/fstyp/msdosfs.c create mode 100644 usr.sbin/fstyp/msdosfs.h create mode 100644 usr.sbin/fstyp/ntfs.c create mode 100644 usr.sbin/fstyp/ufs.c diff --git a/contrib/file/doc/file.man b/contrib/file/doc/file.man index 361188e..8e403be 100644 --- a/contrib/file/doc/file.man +++ b/contrib/file/doc/file.man @@ -1,5 +1,5 @@ .\" $File: file.man,v 1.106 2014/03/07 23:11:51 christos Exp $ -.Dd January 30, 2014 +.Dd December 3, 2014 .Dt FILE __CSECTION__ .Os .Sh NAME @@ -385,6 +385,7 @@ options. .Xr hexdump 1 , .Xr od 1 , .Xr strings 1 , +.Xr fstyp 8 .Sh STANDARDS CONFORMANCE This program is believed to exceed the System V Interface Definition of FILE(CMD), as near as one can determine from the vague language diff --git a/sbin/mount/mount.8 b/sbin/mount/mount.8 index 12c25ad..aa7acfd 100644 --- a/sbin/mount/mount.8 +++ b/sbin/mount/mount.8 @@ -28,7 +28,7 @@ .\" @(#)mount.8 8.8 (Berkeley) 6/16/94 .\" $FreeBSD$ .\" -.Dd November 22, 2014 +.Dd December 3, 2014 .Dt MOUNT 8 .Os .Sh NAME @@ -549,6 +549,7 @@ support for a particular file system might be provided either on a static .Xr fstab 5 , .Xr procfs 5 , .Xr automount 8 , +.Xr fstyp 8 , .Xr kldload 8 , .Xr mount_cd9660 8 , .Xr mount_msdosfs 8 , diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index df9f867..7c44481 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -29,6 +29,7 @@ SUBDIR= adduser \ extattr \ extattrctl \ fifolog \ + fstyp \ fwcontrol \ getfmac \ getpmac \ diff --git a/usr.sbin/fstyp/Makefile b/usr.sbin/fstyp/Makefile new file mode 100644 index 0000000..d0b14d1 --- /dev/null +++ b/usr.sbin/fstyp/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +PROG= fstyp +SRCS= fstyp.c ext2fs.c cd9660.c msdosfs.c ntfs.c ufs.c +MAN= fstyp.8 + +WARNS= 6 + +.include diff --git a/usr.sbin/fstyp/cd9660.c b/usr.sbin/fstyp/cd9660.c new file mode 100644 index 0000000..26ea694 --- /dev/null +++ b/usr.sbin/fstyp/cd9660.c @@ -0,0 +1,72 @@ +/*- + * Copyright (c) 2004 Pawel Jakub Dawidek + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Edward Tomasz Napierala under sponsorship + * from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include "fstyp.h" + +#define G_LABEL_ISO9660_DIR "iso9660" + +#define ISO9660_MAGIC "\x01" "CD001" "\x01\x00" +#define ISO9660_OFFSET 0x8000 +#define VOLUME_LEN 32 + +int +fstyp_cd9660(FILE *fp, char *label, size_t size) +{ + char *sector, *volume; + int i; + + sector = read_buf(fp, ISO9660_OFFSET, 512); + if (sector == NULL) + return (1); + if (bcmp(sector, ISO9660_MAGIC, sizeof(ISO9660_MAGIC) - 1) != 0) { + free(sector); + return (1); + } + volume = sector + 0x28; + bzero(label, size); + strlcpy(label, volume, MIN(size, VOLUME_LEN)); + free(sector); + for (i = size - 1; i > 0; i--) { + if (label[i] == '\0') + continue; + else if (label[i] == ' ') + label[i] = '\0'; + else + break; + } + return (0); +} diff --git a/usr.sbin/fstyp/ext2fs.c b/usr.sbin/fstyp/ext2fs.c new file mode 100644 index 0000000..df9e66e --- /dev/null +++ b/usr.sbin/fstyp/ext2fs.c @@ -0,0 +1,90 @@ +/*- + * Copyright (c) 2005 Stanislav Sedov + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Edward Tomasz Napierala under sponsorship + * from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include "fstyp.h" + +#define EXT2FS_SB_OFFSET 1024 +#define EXT2_SUPER_MAGIC 0xef53 +#define EXT2_DYNAMIC_REV 1 + +typedef struct e2sb { + uint8_t fake1[56]; + uint16_t s_magic; + uint8_t fake2[18]; + uint32_t s_rev_level; + uint8_t fake3[40]; + char s_volume_name[16]; +} e2sb_t; + +int +fstyp_ext2fs(FILE *fp, char *label, size_t size) +{ + e2sb_t *fs; + char *s_volume_name; + + fs = (e2sb_t *)read_buf(fp, EXT2FS_SB_OFFSET, 512); + if (fs == NULL) + return (1); + + /* Check for magic and versio n*/ + if (fs->s_magic == EXT2_SUPER_MAGIC && + fs->s_rev_level == EXT2_DYNAMIC_REV) { + //G_LABEL_DEBUG(1, "ext2fs file system detected on %s.", + // pp->name); + } else { + free(fs); + return (1); + } + + s_volume_name = fs->s_volume_name; + /* Terminate label */ + s_volume_name[sizeof(fs->s_volume_name) - 1] = '\0'; + + if (s_volume_name[0] == '/') + s_volume_name += 1; + + /* Check for volume label */ + if (s_volume_name[0] == '\0') { + free(fs); + return (1); + } + + strlcpy(label, s_volume_name, size); + + return (0); +} diff --git a/usr.sbin/fstyp/fstyp.8 b/usr.sbin/fstyp/fstyp.8 new file mode 100644 index 0000000..a2594c5 --- /dev/null +++ b/usr.sbin/fstyp/fstyp.8 @@ -0,0 +1,97 @@ +.\" Copyright (c) 2014 The FreeBSD Foundation +.\" All rights reserved. +.\" +.\" This software was developed by Edward Tomasz Napierala under sponsorship +.\" from the FreeBSD Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd December 6, 2014 +.Dt FSTYP 8 +.Os +.Sh NAME +.Nm fstyp +.Nd determine filesystem type +.Sh SYNOPSIS +.Nm +.Op Fl l +.Op Fl s +.Ar special +.Sh DESCRIPTION +The +.Nm +utility is used to determine the filesystem type on a given device. +It can recognize ISO-9660, Ext2, FAT, NTFS, and UFS filesystems. +The filesystem name is printed to the standard output +as, respectively, +.Li cd9660 , +.Li ext2fs , +.Li msdosfs , +.Li ntfs , +or +.Li ufs . +.Pp +Because +.Nm +is built specifically to detect filesystem types, it differs from +.Xr file 1 +in several ways. +The output is machine-parsable, filesystem labels are supported, +and only filesystems are identified. +Security is improved with +.Xr capsicum 4 . +.Pp +These options are available: +.Bl -tag -width ".Fl l" +.It Fl l +In addition to filesystem type, print filesystem label if available. +.It Fl s +Ignore file type. +By default, +.Nm +only works on regular files and disk-like device nodes. +Trying to read other file types might have unexpected consequences or hang +indefinitely. +.El +.Sh EXIT STATUS +The +.Nm +utility exits 0 on success, and >0 if an error occurs or the filesystem +type is not recognized. +.Sh SEE ALSO +.Xr file 1 , +.Xr capsicum 4 , +.Xr glabel 8 , +.Xr mount 8 +.Sh HISTORY +The +.Nm +command appeared in +.Fx 11.0 . +.Sh AUTHORS +The +.Nm +utility was developed by +.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org +under sponsorship from the FreeBSD Foundation. diff --git a/usr.sbin/fstyp/fstyp.c b/usr.sbin/fstyp/fstyp.c new file mode 100644 index 0000000..d6a48f6 --- /dev/null +++ b/usr.sbin/fstyp/fstyp.c @@ -0,0 +1,210 @@ +/*- + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Edward Tomasz Napierala under sponsorship + * from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fstyp.h" + +#define LABEL_LEN 256 + +typedef int (*fstyp_function)(FILE *, char *, size_t); + +static struct { + const char *name; + fstyp_function function; +} fstypes[] = { + { "cd9660", &fstyp_cd9660 }, + { "ext2fs", &fstyp_ext2fs }, + { "msdosfs", &fstyp_msdosfs }, + { "ntfs", &fstyp_ntfs }, + { "ufs", &fstyp_ufs }, + { NULL, NULL } +}; + +void * +read_buf(FILE *fp, off_t off, size_t len) +{ + int error; + size_t nread; + void *buf; + + error = fseek(fp, off, SEEK_SET); + if (error != 0) { + warn("cannot seek to %jd", (uintmax_t)off); + return (NULL); + } + + buf = malloc(len); + if (buf == 0) { + warn("cannot malloc %zd bytes of memory", len); + return (NULL); + } + + nread = fread(buf, len, 1, fp); + if (nread != 1) { + free(buf); + if (feof(fp) == 0) + warn("fread"); + return (NULL); + } + + return (buf); +} + +char * +checked_strdup(const char *s) +{ + char *c; + + c = strdup(s); + if (c == NULL) + err(1, "strdup"); + return (c); +} + +static void +usage(void) +{ + + fprintf(stderr, "usage: fstyp [-l][-s] special\n"); + exit(1); +} + +static void +type_check(const char *path, FILE *fp) +{ + int error, fd; + off_t mediasize; + struct stat sb; + + fd = fileno(fp); + + error = fstat(fd, &sb); + if (error != 0) + err(1, "%s: fstat", path); + + if (S_ISREG(sb.st_mode)) + return; + + error = ioctl(fd, DIOCGMEDIASIZE, &mediasize); + if (error != 0) + errx(1, "%s: not a disk", path); +} + +int +main(int argc, char **argv) +{ + int ch, error, i, nbytes; + bool ignore_type = false, show_label = false; + char label[LABEL_LEN + 1], strvised[LABEL_LEN * 4 + 1]; + char *path; + FILE *fp; + fstyp_function fstyp_f; + + while ((ch = getopt(argc, argv, "ls")) != -1) { + switch (ch) { + case 'l': + show_label = true; + break; + case 's': + ignore_type = true; + break; + default: + usage(); + } + } + + argc -= optind; + argv += optind; + if (argc != 1) + usage(); + + path = argv[0]; + + fp = fopen(path, "r"); + if (fp == NULL) + err(1, "%s", path); + + error = cap_enter(); + if (error != 0 && errno != ENOSYS) + err(1, "cap_enter"); + + if (ignore_type == false) + type_check(path, fp); + + memset(label, '\0', sizeof(label)); + + for (i = 0;; i++) { + fstyp_f = fstypes[i].function; + if (fstyp_f == NULL) + break; + + error = fstyp_f(fp, label, sizeof(label)); + if (error == 0) + break; + } + + if (fstypes[i].name == NULL) { + warnx("%s: filesystem not recognized", path); + return (1); + } + + if (show_label && label[0] != '\0') { + /* + * XXX: I'd prefer VIS_HTTPSTYLE, but it unconditionally + * encodes spaces. + */ + nbytes = strsnvis(strvised, sizeof(strvised), label, + VIS_GLOB | VIS_NL, "\"'$"); + if (nbytes == -1) + err(1, "strsnvis"); + + printf("%s %s\n", fstypes[i].name, strvised); + } else { + printf("%s\n", fstypes[i].name); + } + + return (0); +} diff --git a/usr.sbin/fstyp/fstyp.h b/usr.sbin/fstyp/fstyp.h new file mode 100644 index 0000000..4474ffe --- /dev/null +++ b/usr.sbin/fstyp/fstyp.h @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Edward Tomasz Napierala under sponsorship + * from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef FSTYP_H +#define FSTYP_H + +#define MIN(a,b) (((a)<(b))?(a):(b)) + +void *read_buf(FILE *fp, off_t off, size_t len); +char *checked_strdup(const char *s); + +int fstyp_cd9660(FILE *fp, char *label, size_t size); +int fstyp_ext2fs(FILE *fp, char *label, size_t size); +int fstyp_msdosfs(FILE *fp, char *label, size_t size); +int fstyp_ntfs(FILE *fp, char *label, size_t size); +int fstyp_ufs(FILE *fp, char *label, size_t size); + +#endif /* !FSTYP_H */ diff --git a/usr.sbin/fstyp/msdosfs.c b/usr.sbin/fstyp/msdosfs.c new file mode 100644 index 0000000..b299243 --- /dev/null +++ b/usr.sbin/fstyp/msdosfs.c @@ -0,0 +1,183 @@ +/*- + * Copyright (c) 2004 Pawel Jakub Dawidek + * Copyright (c) 2006 Tobias Reifenberger + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Edward Tomasz Napierala under sponsorship + * from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include "fstyp.h" +#include "msdosfs.h" + +#define LABEL_NO_NAME "NO NAME " + +int +fstyp_msdosfs(FILE *fp, char *label, size_t size) +{ + FAT_BSBPB *pfat_bsbpb; + FAT32_BSBPB *pfat32_bsbpb; + FAT_DES *pfat_entry; + uint8_t *sector0, *sector; + uint32_t i; + + sector0 = NULL; + sector = NULL; + + /* Load 1st sector with boot sector and boot parameter block. */ + sector0 = (uint8_t *)read_buf(fp, 0, 512); + if (sector0 == NULL) + return (1); + + /* Check for the FAT boot sector signature. */ + if (sector0[510] != 0x55 || sector0[511] != 0xaa) { + goto error; + } + + /* + * Test if this is really a FAT volume and determine the FAT type. + */ + + pfat_bsbpb = (FAT_BSBPB *)sector0; + pfat32_bsbpb = (FAT32_BSBPB *)sector0; + + if (UINT16BYTES(pfat_bsbpb->BPB_FATSz16) != 0) { + /* + * If the BPB_FATSz16 field is not zero and the string "FAT" is + * at the right place, this should be a FAT12 or FAT16 volume. + */ + if (strncmp(pfat_bsbpb->BS_FilSysType, "FAT", 3) != 0) { + goto error; + } + + /* A volume with no name should have "NO NAME " as label. */ + if (strncmp(pfat_bsbpb->BS_VolLab, LABEL_NO_NAME, + sizeof(pfat_bsbpb->BS_VolLab)) == 0) { + goto endofchecks; + } + strlcpy(label, pfat_bsbpb->BS_VolLab, + MIN(size, sizeof(pfat_bsbpb->BS_VolLab) + 1)); + } else if (UINT32BYTES(pfat32_bsbpb->BPB_FATSz32) != 0) { + uint32_t fat_FirstDataSector, fat_BytesPerSector, offset; + + /* + * If the BPB_FATSz32 field is not zero and the string "FAT" is + * at the right place, this should be a FAT32 volume. + */ + if (strncmp(pfat32_bsbpb->BS_FilSysType, "FAT", 3) != 0) { + goto error; + } + + /* + * If the volume label is not "NO NAME " we're done. + */ + if (strncmp(pfat32_bsbpb->BS_VolLab, LABEL_NO_NAME, + sizeof(pfat32_bsbpb->BS_VolLab)) != 0) { + strlcpy(label, pfat32_bsbpb->BS_VolLab, + MIN(size, sizeof(pfat32_bsbpb->BS_VolLab) + 1)); + goto endofchecks; + } + + /* + * If the volume label "NO NAME " is in the boot sector, the + * label of FAT32 volumes may be stored as a special entry in + * the root directory. + */ + fat_FirstDataSector = + UINT16BYTES(pfat32_bsbpb->BPB_RsvdSecCnt) + + (pfat32_bsbpb->BPB_NumFATs * + UINT32BYTES(pfat32_bsbpb->BPB_FATSz32)); + fat_BytesPerSector = UINT16BYTES(pfat32_bsbpb->BPB_BytsPerSec); + + // fat_FirstDataSector, fat_BytesPerSector); + + for (offset = fat_BytesPerSector * fat_FirstDataSector;; + offset += fat_BytesPerSector) { + sector = (uint8_t *)read_buf(fp, offset, fat_BytesPerSector); + if (sector == NULL) + goto error; + + pfat_entry = (FAT_DES *)sector; + do { + /* No more entries available. */ + if (pfat_entry->DIR_Name[0] == 0) { + goto endofchecks; + } + + /* Skip empty or long name entries. */ + if (pfat_entry->DIR_Name[0] == 0xe5 || + (pfat_entry->DIR_Attr & + FAT_DES_ATTR_LONG_NAME) == + FAT_DES_ATTR_LONG_NAME) { + continue; + } + + /* + * The name of the entry is the volume label if + * ATTR_VOLUME_ID is set. + */ + if (pfat_entry->DIR_Attr & + FAT_DES_ATTR_VOLUME_ID) { + strlcpy(label, pfat_entry->DIR_Name, + MIN(size, + sizeof(pfat_entry->DIR_Name) + 1)); + goto endofchecks; + } + } while((uint8_t *)(++pfat_entry) < + (uint8_t *)(sector + fat_BytesPerSector)); + free(sector); + } + } else { + goto error; + } + +endofchecks: + for (i = size - 1; i > 0; i--) { + if (label[i] == '\0') + continue; + else if (label[i] == ' ') + label[i] = '\0'; + else + break; + } + + free(sector0); + free(sector); + + return (0); + +error: + free(sector0); + free(sector); + + return (1); +} diff --git a/usr.sbin/fstyp/msdosfs.h b/usr.sbin/fstyp/msdosfs.h new file mode 100644 index 0000000..a04b87f --- /dev/null +++ b/usr.sbin/fstyp/msdosfs.h @@ -0,0 +1,140 @@ +/*- + * Copyright (c) 2006 Tobias Reifenberger + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include + +/* + * Conversion macros for little endian encoded unsigned integers + * in byte streams to the local unsigned integer format. + */ +#define UINT16BYTES(p) ((uint32_t)((p)[0] + (256*(p)[1]))) +#define UINT32BYTES(p) ((uint32_t)((p)[0] + (256*(p)[1]) + \ + (65536*(p)[2]) + (16777216*(p)[3]))) + +/* + * All following structures are according to: + * + * Microsoft Extensible Firmware Initiative FAT32 File System Specification + * FAT: General Overview of On-Disk Format + * Version 1.03, December 6, 2000 + * Microsoft Corporation + */ + +/* + * FAT boot sector and boot parameter block for + * FAT12 and FAT16 volumes + */ +typedef struct fat_bsbpb { + /* common fields */ + uint8_t BS_jmpBoot[3]; + uint8_t BS_OEMName[8]; + uint8_t BPB_BytsPerSec[2]; + uint8_t BPB_SecPerClus; + uint8_t BPB_RsvdSecCnt[2]; + uint8_t BPB_NumFATs; + uint8_t BPB_RootEntCnt[2]; + uint8_t BPB_TotSec16[2]; + uint8_t BPB_Media; + uint8_t BPB_FATSz16[2]; + uint8_t BPB_SecPerTrack[2]; + uint8_t BPB_NumHeads[2]; + uint8_t BPB_HiddSec[4]; + uint8_t BPB_TotSec32[4]; + /* FAT12/FAT16 only fields */ + uint8_t BS_DrvNum; + uint8_t BS_Reserved1; + uint8_t BS_BootSig; + uint8_t BS_VolID[4]; + uint8_t BS_VolLab[11]; + uint8_t BS_FilSysType[8]; +} FAT_BSBPB; /* 62 bytes */ + +/* + * FAT boot sector and boot parameter block for + * FAT32 volumes + */ +typedef struct fat32_bsbpb { + /* common fields */ + uint8_t BS_jmpBoot[3]; + uint8_t BS_OEMName[8]; + uint8_t BPB_BytsPerSec[2]; + uint8_t BPB_SecPerClus; + uint8_t BPB_RsvdSecCnt[2]; + uint8_t BPB_NumFATs; + uint8_t BPB_RootEntCnt[2]; + uint8_t BPB_TotSec16[2]; + uint8_t BPB_Media; + uint8_t BPB_FATSz16[2]; + uint8_t BPB_SecPerTrack[2]; + uint8_t BPB_NumHeads[2]; + uint8_t BPB_HiddSec[4]; + uint8_t BPB_TotSec32[4]; + /* FAT32 only fields */ + uint8_t BPB_FATSz32[4]; + uint8_t BPB_ExtFlags[2]; + uint8_t BPB_FSVer[2]; + uint8_t BPB_RootClus[4]; + uint8_t BPB_FSInfo[2]; + uint8_t BPB_BkBootSec[2]; + uint8_t BPB_Reserved[12]; + uint8_t BS_DrvNum; + uint8_t BS_Reserved1; + uint8_t BS_BootSig; + uint8_t BS_VolID[4]; + uint8_t BS_VolLab[11]; + uint8_t BS_FilSysType[8]; +} FAT32_BSBPB; /* 90 bytes */ + +/* + * FAT directory entry structure + */ +#define FAT_DES_ATTR_READ_ONLY 0x01 +#define FAT_DES_ATTR_HIDDEN 0x02 +#define FAT_DES_ATTR_SYSTEM 0x04 +#define FAT_DES_ATTR_VOLUME_ID 0x08 +#define FAT_DES_ATTR_DIRECTORY 0x10 +#define FAT_DES_ATTR_ARCHIVE 0x20 +#define FAT_DES_ATTR_LONG_NAME (FAT_DES_ATTR_READ_ONLY | \ + FAT_DES_ATTR_HIDDEN | \ + FAT_DES_ATTR_SYSTEM | \ + FAT_DES_ATTR_VOLUME_ID) + +typedef struct fat_des { + uint8_t DIR_Name[11]; + uint8_t DIR_Attr; + uint8_t DIR_NTRes; + uint8_t DIR_CrtTimeTenth; + uint8_t DIR_CrtTime[2]; + uint8_t DIR_CrtDate[2]; + uint8_t DIR_LstAccDate[2]; + uint8_t DIR_FstClusHI[2]; + uint8_t DIR_WrtTime[2]; + uint8_t DIR_WrtDate[2]; + uint8_t DIR_FstClusLO[2]; + uint8_t DIR_FileSize[4]; +} FAT_DES; diff --git a/usr.sbin/fstyp/ntfs.c b/usr.sbin/fstyp/ntfs.c new file mode 100644 index 0000000..582f6b9 --- /dev/null +++ b/usr.sbin/fstyp/ntfs.c @@ -0,0 +1,165 @@ +/*- + * Copyright (c) 2005 Takanori Watanabe + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Edward Tomasz Napierala under sponsorship + * from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include "fstyp.h" + +#define NTFS_A_VOLUMENAME 0x60 +#define NTFS_FILEMAGIC ((uint32_t)(0x454C4946)) +#define NTFS_VOLUMEINO 3 + +#define G_LABEL_NTFS_DIR "ntfs" + +struct ntfs_attr { + uint32_t a_type; + uint32_t reclen; + uint8_t a_flag; + uint8_t a_namelen; + uint8_t a_nameoff; + uint8_t reserved1; + uint8_t a_compression; + uint8_t reserved2; + uint16_t a_index; + uint16_t a_datalen; + uint16_t reserved3; + uint16_t a_dataoff; + uint16_t a_indexed; +} __packed; + +struct ntfs_filerec { + uint32_t fr_hdrmagic; + uint16_t fr_hdrfoff; + uint16_t fr_hdrfnum; + uint8_t reserved[8]; + uint16_t fr_seqnum; + uint16_t fr_nlink; + uint16_t fr_attroff; + uint16_t fr_flags; + uint32_t fr_size; + uint32_t fr_allocated; + uint64_t fr_mainrec; + uint16_t fr_attrnum; +} __packed; + +struct ntfs_bootfile { + uint8_t reserved1[3]; + uint8_t bf_sysid[8]; + uint16_t bf_bps; + uint8_t bf_spc; + uint8_t reserved2[7]; + uint8_t bf_media; + uint8_t reserved3[2]; + uint16_t bf_spt; + uint16_t bf_heads; + uint8_t reserver4[12]; + uint64_t bf_spv; + uint64_t bf_mftcn; + uint64_t bf_mftmirrcn; + int8_t bf_mftrecsz; + uint32_t bf_ibsz; + uint32_t bf_volsn; +} __packed; + +int +fstyp_ntfs(FILE *fp, char *label, size_t size) +{ + struct ntfs_bootfile *bf; + struct ntfs_filerec *fr; + struct ntfs_attr *atr; + off_t voloff; + char *filerecp, *ap; + int8_t mftrecsz; + char vnchar; + int recsize, j; + + filerecp = NULL; + + bf = (struct ntfs_bootfile *)read_buf(fp, 0, 512); + if (bf == NULL || strncmp(bf->bf_sysid, "NTFS ", 8) != 0) + return (1); + + mftrecsz = bf->bf_mftrecsz; + recsize = (mftrecsz > 0) ? (mftrecsz * bf->bf_bps * bf->bf_spc) : (1 << -mftrecsz); + + voloff = bf->bf_mftcn * bf->bf_spc * bf->bf_bps + + recsize * NTFS_VOLUMEINO; + + filerecp = read_buf(fp, voloff, recsize); + if (filerecp == NULL) + goto fail; + fr = (struct ntfs_filerec *)filerecp; + + if (fr->fr_hdrmagic != NTFS_FILEMAGIC) + goto fail; + + for (ap = filerecp + fr->fr_attroff; + atr = (struct ntfs_attr *)ap, (int)atr->a_type != -1; + ap += atr->reclen) { + if (atr->a_type == NTFS_A_VOLUMENAME) { + if(atr->a_datalen >= size *2){ + goto fail; + } + /* + *UNICODE to ASCII. + * Should we need to use iconv(9)? + */ + for (j = 0; j < atr->a_datalen; j++) { + vnchar = *(ap + atr->a_dataoff + j); + if (j & 1) { + if (vnchar) { + goto fail; + } + } else { + label[j / 2] = vnchar; + } + } + label[j / 2] = 0; + break; + } + } + + free(bf); + free(filerecp); + + return (0); + +fail: + free(bf); + free(filerecp); + + return (1); +} diff --git a/usr.sbin/fstyp/ufs.c b/usr.sbin/fstyp/ufs.c new file mode 100644 index 0000000..8b27ca0 --- /dev/null +++ b/usr.sbin/fstyp/ufs.c @@ -0,0 +1,109 @@ +/*- + * Copyright (c) 2002, 2003 Gordon Tetlow + * Copyright (c) 2006 Pawel Jakub Dawidek + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Edward Tomasz Napierala under sponsorship + * from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include +#include + +#include "fstyp.h" + +static const int superblocks[] = SBLOCKSEARCH; + +int +fstyp_ufs(FILE *fp, char *label, size_t labelsize) +{ + int sb, superblock; + struct fs *fs; + + /* + * Walk through the standard places that superblocks hide and look + * for UFS magic. If we find magic, then check that the size in the + * superblock corresponds to the size of the underlying provider. + * Finally, look for a volume label and create an appropriate + * provider based on that. + */ + for (sb = 0; (superblock = superblocks[sb]) != -1; sb++) { + fs = (struct fs *)read_buf(fp, superblock, SBLOCKSIZE); + if (fs == NULL) + continue; + /* + * Check for magic. We also need to check if file system size is equal + * to providers size, because sysinstall(8) used to bogusly put first + * partition at offset 0 instead of 16, and glabel/ufs would find file + * system on slice instead of partition. + */ +#ifdef notyet + if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_fsize > 0 && + ((pp->mediasize / fs->fs_fsize == fs->fs_old_size) || + (pp->mediasize / fs->fs_fsize == fs->fs_providersize))) { + /* Valid UFS1. */ + } else if (fs->fs_magic == FS_UFS2_MAGIC && fs->fs_fsize > 0 && + ((pp->mediasize / fs->fs_fsize == fs->fs_size) || + (pp->mediasize / fs->fs_fsize == fs->fs_providersize))) { + /* Valid UFS2. */ + } else { + g_free(fs); + continue; + } +#else + if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_fsize > 0) { + /* Valid UFS1. */ + } else if (fs->fs_magic == FS_UFS2_MAGIC && fs->fs_fsize > 0) { + /* Valid UFS2. */ + } else { + free(fs); + continue; + } +#endif + + if (fs->fs_sblockloc != superblock || fs->fs_ncg < 1 || + fs->fs_bsize < MINBSIZE || + (size_t)fs->fs_bsize < sizeof(struct fs)) { + free(fs); + continue; + } + + strlcpy(label, fs->fs_volname, labelsize); + + free(fs); + return (0); + } + + return (1); +} -- cgit v1.1