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