1275680Strasz/*- 2275680Strasz * Copyright (c) 2014 The FreeBSD Foundation 3275680Strasz * All rights reserved. 4275680Strasz * 5275680Strasz * This software was developed by Edward Tomasz Napierala under sponsorship 6275680Strasz * from the FreeBSD Foundation. 7275680Strasz * 8275680Strasz * Redistribution and use in source and binary forms, with or without 9275680Strasz * modification, are permitted provided that the following conditions 10275680Strasz * are met: 11275680Strasz * 1. Redistributions of source code must retain the above copyright 12275680Strasz * notice, this list of conditions and the following disclaimer. 13275680Strasz * 2. Redistributions in binary form must reproduce the above copyright 14275680Strasz * notice, this list of conditions and the following disclaimer in the 15275680Strasz * documentation and/or other materials provided with the distribution. 16275680Strasz * 17275680Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18275680Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19275680Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20275680Strasz * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21275680Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22275680Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23275680Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24275680Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25275680Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26275680Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27275680Strasz * SUCH DAMAGE. 28275680Strasz * 29275680Strasz */ 30275680Strasz 31275680Strasz#include <sys/cdefs.h> 32275680Strasz__FBSDID("$FreeBSD$"); 33275680Strasz 34277434Strasz#include <sys/capability.h> 35275680Strasz#include <sys/disk.h> 36275680Strasz#include <sys/ioctl.h> 37275680Strasz#include <sys/stat.h> 38275680Strasz#include <err.h> 39275680Strasz#include <errno.h> 40275680Strasz#include <stdbool.h> 41286193Strasz#include <stddef.h> 42275680Strasz#include <stdio.h> 43275680Strasz#include <stdlib.h> 44275680Strasz#include <string.h> 45275680Strasz#include <unistd.h> 46275680Strasz#include <vis.h> 47275680Strasz 48275680Strasz#include "fstyp.h" 49275680Strasz 50275680Strasz#define LABEL_LEN 256 51275680Strasz 52275680Strasztypedef int (*fstyp_function)(FILE *, char *, size_t); 53275680Strasz 54275680Straszstatic struct { 55275680Strasz const char *name; 56275680Strasz fstyp_function function; 57293776Sallanjude bool unmountable; 58275680Strasz} fstypes[] = { 59293776Sallanjude { "cd9660", &fstyp_cd9660, false }, 60293776Sallanjude { "ext2fs", &fstyp_ext2fs, false }, 61293776Sallanjude { "geli", &fstyp_geli, true }, 62293776Sallanjude { "msdosfs", &fstyp_msdosfs, false }, 63293776Sallanjude { "ntfs", &fstyp_ntfs, false }, 64293776Sallanjude { "ufs", &fstyp_ufs, false }, 65293776Sallanjude#ifdef HAVE_ZFS 66293776Sallanjude { "zfs", &fstyp_zfs, true }, 67293776Sallanjude#endif 68293776Sallanjude { NULL, NULL, NULL } 69275680Strasz}; 70275680Strasz 71275680Straszvoid * 72275680Straszread_buf(FILE *fp, off_t off, size_t len) 73275680Strasz{ 74275680Strasz int error; 75275680Strasz size_t nread; 76275680Strasz void *buf; 77275680Strasz 78275680Strasz error = fseek(fp, off, SEEK_SET); 79275680Strasz if (error != 0) { 80275680Strasz warn("cannot seek to %jd", (uintmax_t)off); 81275680Strasz return (NULL); 82275680Strasz } 83275680Strasz 84275680Strasz buf = malloc(len); 85275680Strasz if (buf == 0) { 86275680Strasz warn("cannot malloc %zd bytes of memory", len); 87275680Strasz return (NULL); 88275680Strasz } 89275680Strasz 90275680Strasz nread = fread(buf, len, 1, fp); 91275680Strasz if (nread != 1) { 92275680Strasz free(buf); 93275680Strasz if (feof(fp) == 0) 94275680Strasz warn("fread"); 95275680Strasz return (NULL); 96275680Strasz } 97275680Strasz 98275680Strasz return (buf); 99275680Strasz} 100275680Strasz 101275680Straszchar * 102275680Straszchecked_strdup(const char *s) 103275680Strasz{ 104275680Strasz char *c; 105275680Strasz 106275680Strasz c = strdup(s); 107275680Strasz if (c == NULL) 108275680Strasz err(1, "strdup"); 109275680Strasz return (c); 110275680Strasz} 111275680Strasz 112286193Straszvoid 113286193Straszrtrim(char *label, size_t size) 114286193Strasz{ 115286193Strasz ptrdiff_t i; 116286193Strasz 117286193Strasz for (i = size - 1; i >= 0; i--) { 118286193Strasz if (label[i] == '\0') 119286193Strasz continue; 120286193Strasz else if (label[i] == ' ') 121286193Strasz label[i] = '\0'; 122286193Strasz else 123286193Strasz break; 124286193Strasz } 125286193Strasz} 126286193Strasz 127275680Straszstatic void 128275680Straszusage(void) 129275680Strasz{ 130275680Strasz 131293776Sallanjude fprintf(stderr, "usage: fstyp [-l] [-s] [-u] special\n"); 132275680Strasz exit(1); 133275680Strasz} 134275680Strasz 135275680Straszstatic void 136275680Strasztype_check(const char *path, FILE *fp) 137275680Strasz{ 138275680Strasz int error, fd; 139275680Strasz off_t mediasize; 140275680Strasz struct stat sb; 141275680Strasz 142275680Strasz fd = fileno(fp); 143275680Strasz 144275680Strasz error = fstat(fd, &sb); 145275680Strasz if (error != 0) 146275680Strasz err(1, "%s: fstat", path); 147275680Strasz 148275680Strasz if (S_ISREG(sb.st_mode)) 149275680Strasz return; 150275680Strasz 151275680Strasz error = ioctl(fd, DIOCGMEDIASIZE, &mediasize); 152275680Strasz if (error != 0) 153275680Strasz errx(1, "%s: not a disk", path); 154275680Strasz} 155275680Strasz 156275680Straszint 157275680Straszmain(int argc, char **argv) 158275680Strasz{ 159275680Strasz int ch, error, i, nbytes; 160293776Sallanjude bool ignore_type = false, show_label = false, show_unmountable = false; 161275680Strasz char label[LABEL_LEN + 1], strvised[LABEL_LEN * 4 + 1]; 162275680Strasz char *path; 163275680Strasz FILE *fp; 164275680Strasz fstyp_function fstyp_f; 165275680Strasz 166293776Sallanjude while ((ch = getopt(argc, argv, "lsu")) != -1) { 167275680Strasz switch (ch) { 168275680Strasz case 'l': 169275680Strasz show_label = true; 170275680Strasz break; 171275680Strasz case 's': 172275680Strasz ignore_type = true; 173275680Strasz break; 174293776Sallanjude case 'u': 175293776Sallanjude show_unmountable = true; 176293776Sallanjude break; 177275680Strasz default: 178275680Strasz usage(); 179275680Strasz } 180275680Strasz } 181275680Strasz 182275680Strasz argc -= optind; 183275680Strasz argv += optind; 184275680Strasz if (argc != 1) 185275680Strasz usage(); 186275680Strasz 187275680Strasz path = argv[0]; 188275680Strasz 189275680Strasz fp = fopen(path, "r"); 190275680Strasz if (fp == NULL) 191275680Strasz err(1, "%s", path); 192275680Strasz 193275680Strasz error = cap_enter(); 194275680Strasz if (error != 0 && errno != ENOSYS) 195275680Strasz err(1, "cap_enter"); 196275680Strasz 197275680Strasz if (ignore_type == false) 198275680Strasz type_check(path, fp); 199275680Strasz 200275680Strasz memset(label, '\0', sizeof(label)); 201275680Strasz 202275680Strasz for (i = 0;; i++) { 203293776Sallanjude if (show_unmountable == false && fstypes[i].unmountable == true) 204293776Sallanjude continue; 205275680Strasz fstyp_f = fstypes[i].function; 206275680Strasz if (fstyp_f == NULL) 207275680Strasz break; 208275680Strasz 209275680Strasz error = fstyp_f(fp, label, sizeof(label)); 210275680Strasz if (error == 0) 211275680Strasz break; 212275680Strasz } 213275680Strasz 214275680Strasz if (fstypes[i].name == NULL) { 215275680Strasz warnx("%s: filesystem not recognized", path); 216275680Strasz return (1); 217275680Strasz } 218275680Strasz 219275680Strasz if (show_label && label[0] != '\0') { 220275680Strasz /* 221275680Strasz * XXX: I'd prefer VIS_HTTPSTYLE, but it unconditionally 222275680Strasz * encodes spaces. 223275680Strasz */ 224275680Strasz nbytes = strsnvis(strvised, sizeof(strvised), label, 225275680Strasz VIS_GLOB | VIS_NL, "\"'$"); 226275680Strasz if (nbytes == -1) 227275680Strasz err(1, "strsnvis"); 228275680Strasz 229275680Strasz printf("%s %s\n", fstypes[i].name, strvised); 230275680Strasz } else { 231275680Strasz printf("%s\n", fstypes[i].name); 232275680Strasz } 233275680Strasz 234275680Strasz return (0); 235275680Strasz} 236