1/*- 2 * Copyright (c) 2014 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Edward Tomasz Napierala under sponsorship 6 * from the FreeBSD Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD$"); 33 34#include <sys/capsicum.h> 35#include <sys/disk.h> 36#include <sys/ioctl.h> 37#include <sys/stat.h> 38#include <capsicum_helpers.h> 39#include <err.h> 40#include <errno.h> 41#ifdef WITH_ICONV 42#include <iconv.h> 43#endif 44#include <locale.h> 45#include <stdbool.h> 46#include <stddef.h> 47#include <stdio.h> 48#include <stdlib.h> 49#include <string.h> 50#include <unistd.h> 51#include <vis.h> 52 53#include "fstyp.h" 54 55#define LABEL_LEN 256 56 57bool show_label = false; 58 59typedef int (*fstyp_function)(FILE *, char *, size_t); 60 61static struct { 62 const char *name; 63 fstyp_function function; 64 bool unmountable; 65 char *precache_encoding; 66} fstypes[] = { 67 { "cd9660", &fstyp_cd9660, false, NULL }, 68 { "exfat", &fstyp_exfat, false, EXFAT_ENC }, 69 { "ext2fs", &fstyp_ext2fs, false, NULL }, 70 { "geli", &fstyp_geli, true, NULL }, 71 { "msdosfs", &fstyp_msdosfs, false, NULL }, 72 { "ntfs", &fstyp_ntfs, false, NULL }, 73 { "ufs", &fstyp_ufs, false, NULL }, 74#ifdef HAVE_ZFS 75 { "zfs", &fstyp_zfs, true, NULL }, 76#endif 77 { NULL, NULL, NULL, NULL } 78}; 79 80void * 81read_buf(FILE *fp, off_t off, size_t len) 82{ 83 int error; 84 size_t nread; 85 void *buf; 86 87 error = fseek(fp, off, SEEK_SET); 88 if (error != 0) { 89 warn("cannot seek to %jd", (uintmax_t)off); 90 return (NULL); 91 } 92 93 buf = malloc(len); 94 if (buf == NULL) { 95 warn("cannot malloc %zd bytes of memory", len); 96 return (NULL); 97 } 98 99 nread = fread(buf, len, 1, fp); 100 if (nread != 1) { 101 free(buf); 102 if (feof(fp) == 0) 103 warn("fread"); 104 return (NULL); 105 } 106 107 return (buf); 108} 109 110char * 111checked_strdup(const char *s) 112{ 113 char *c; 114 115 c = strdup(s); 116 if (c == NULL) 117 err(1, "strdup"); 118 return (c); 119} 120 121void 122rtrim(char *label, size_t size) 123{ 124 ptrdiff_t i; 125 126 for (i = size - 1; i >= 0; i--) { 127 if (label[i] == '\0') 128 continue; 129 else if (label[i] == ' ') 130 label[i] = '\0'; 131 else 132 break; 133 } 134} 135 136static void 137usage(void) 138{ 139 140 fprintf(stderr, "usage: fstyp [-l] [-s] [-u] special\n"); 141 exit(1); 142} 143 144static void 145type_check(const char *path, FILE *fp) 146{ 147 int error, fd; 148 off_t mediasize; 149 struct stat sb; 150 151 fd = fileno(fp); 152 153 error = fstat(fd, &sb); 154 if (error != 0) 155 err(1, "%s: fstat", path); 156 157 if (S_ISREG(sb.st_mode)) 158 return; 159 160 error = ioctl(fd, DIOCGMEDIASIZE, &mediasize); 161 if (error != 0) 162 errx(1, "%s: not a disk", path); 163} 164 165int 166main(int argc, char **argv) 167{ 168 int ch, error, i, nbytes; 169 bool ignore_type = false, show_unmountable = false; 170 char label[LABEL_LEN + 1], strvised[LABEL_LEN * 4 + 1]; 171 char *path; 172 FILE *fp; 173 fstyp_function fstyp_f; 174 175 while ((ch = getopt(argc, argv, "lsu")) != -1) { 176 switch (ch) { 177 case 'l': 178 show_label = true; 179 break; 180 case 's': 181 ignore_type = true; 182 break; 183 case 'u': 184 show_unmountable = true; 185 break; 186 default: 187 usage(); 188 } 189 } 190 191 argc -= optind; 192 argv += optind; 193 if (argc != 1) 194 usage(); 195 196 path = argv[0]; 197 198 if (setlocale(LC_CTYPE, "") == NULL) 199 err(1, "setlocale"); 200 caph_cache_catpages(); 201 202#ifdef WITH_ICONV 203 /* Cache iconv conversion data before entering capability mode. */ 204 if (show_label) { 205 for (i = 0; i < nitems(fstypes); i++) { 206 iconv_t cd; 207 208 if (fstypes[i].precache_encoding == NULL) 209 continue; 210 cd = iconv_open("", fstypes[i].precache_encoding); 211 if (cd == (iconv_t)-1) 212 err(1, "%s: iconv_open %s", fstypes[i].name, 213 fstypes[i].precache_encoding); 214 /* Iconv keeps a small cache of unused encodings. */ 215 iconv_close(cd); 216 } 217 } 218#endif 219 220 fp = fopen(path, "r"); 221 if (fp == NULL) 222 err(1, "%s", path); 223 224 if (caph_enter() < 0) 225 err(1, "cap_enter"); 226 227 if (ignore_type == false) 228 type_check(path, fp); 229 230 memset(label, '\0', sizeof(label)); 231 232 for (i = 0;; i++) { 233 if (show_unmountable == false && fstypes[i].unmountable == true) 234 continue; 235 fstyp_f = fstypes[i].function; 236 if (fstyp_f == NULL) 237 break; 238 239 error = fstyp_f(fp, label, sizeof(label)); 240 if (error == 0) 241 break; 242 } 243 244 if (fstypes[i].name == NULL) { 245 warnx("%s: filesystem not recognized", path); 246 return (1); 247 } 248 249 if (show_label && label[0] != '\0') { 250 /* 251 * XXX: I'd prefer VIS_HTTPSTYLE, but it unconditionally 252 * encodes spaces. 253 */ 254 nbytes = strsnvis(strvised, sizeof(strvised), label, 255 VIS_GLOB | VIS_NL, "\"'$"); 256 if (nbytes == -1) 257 err(1, "strsnvis"); 258 259 printf("%s %s\n", fstypes[i].name, strvised); 260 } else { 261 printf("%s\n", fstypes[i].name); 262 } 263 264 return (0); 265} 266