xref: /freebsd/usr.sbin/fstyp/fstyp.c (revision b740c88bfb6453416926271c089262e7164dace3)
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 <err.h>
39 #include <errno.h>
40 #include <stdbool.h>
41 #include <stdint.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <vis.h>
47 
48 #include "fstyp.h"
49 
50 #define	LABEL_LEN	256
51 
52 typedef int (*fstyp_function)(FILE *, char *, size_t);
53 
54 static struct {
55 	const char	*name;
56 	fstyp_function	function;
57 } fstypes[] = {
58 	{ "cd9660", &fstyp_cd9660 },
59 	{ "ext2fs", &fstyp_ext2fs },
60 	{ "msdosfs", &fstyp_msdosfs },
61 	{ "ntfs", &fstyp_ntfs },
62 	{ "ufs", &fstyp_ufs },
63 	{ NULL, NULL }
64 };
65 
66 void *
67 read_buf(FILE *fp, off_t off, size_t len)
68 {
69 	int error;
70 	size_t nread;
71 	void *buf;
72 
73 	error = fseek(fp, off, SEEK_SET);
74 	if (error != 0) {
75 		warn("cannot seek to %jd", (uintmax_t)off);
76 		return (NULL);
77 	}
78 
79 	buf = malloc(len);
80 	if (buf == 0) {
81 		warn("cannot malloc %zd bytes of memory", len);
82 		return (NULL);
83 	}
84 
85 	nread = fread(buf, len, 1, fp);
86 	if (nread != 1) {
87 		free(buf);
88 		if (feof(fp) == 0)
89 			warn("fread");
90 		return (NULL);
91 	}
92 
93 	return (buf);
94 }
95 
96 char *
97 checked_strdup(const char *s)
98 {
99 	char *c;
100 
101 	c = strdup(s);
102 	if (c == NULL)
103 		err(1, "strdup");
104 	return (c);
105 }
106 
107 static void
108 usage(void)
109 {
110 
111 	fprintf(stderr, "usage: fstyp [-l][-s] special\n");
112 	exit(1);
113 }
114 
115 static void
116 type_check(const char *path, FILE *fp)
117 {
118 	int error, fd;
119 	off_t mediasize;
120 	struct stat sb;
121 
122 	fd = fileno(fp);
123 
124 	error = fstat(fd, &sb);
125 	if (error != 0)
126 		err(1, "%s: fstat", path);
127 
128 	if (S_ISREG(sb.st_mode))
129 		return;
130 
131 	error = ioctl(fd, DIOCGMEDIASIZE, &mediasize);
132 	if (error != 0)
133 		errx(1, "%s: not a disk", path);
134 }
135 
136 int
137 main(int argc, char **argv)
138 {
139 	int ch, error, i, nbytes;
140 	bool ignore_type = false, show_label = false;
141 	char label[LABEL_LEN + 1], strvised[LABEL_LEN * 4 + 1];
142 	char *path;
143 	FILE *fp;
144 	fstyp_function fstyp_f;
145 
146 	while ((ch = getopt(argc, argv, "ls")) != -1) {
147 		switch (ch) {
148 		case 'l':
149 			show_label = true;
150 			break;
151 		case 's':
152 			ignore_type = true;
153 			break;
154 		default:
155 			usage();
156 		}
157 	}
158 
159 	argc -= optind;
160 	argv += optind;
161 	if (argc != 1)
162 		usage();
163 
164 	path = argv[0];
165 
166 	fp = fopen(path, "r");
167 	if (fp == NULL)
168 		err(1, "%s", path);
169 
170 	error = cap_enter();
171 	if (error != 0 && errno != ENOSYS)
172 		err(1, "cap_enter");
173 
174 	if (ignore_type == false)
175 		type_check(path, fp);
176 
177 	memset(label, '\0', sizeof(label));
178 
179 	for (i = 0;; i++) {
180 		fstyp_f = fstypes[i].function;
181 		if (fstyp_f == NULL)
182 			break;
183 
184 		error = fstyp_f(fp, label, sizeof(label));
185 		if (error == 0)
186 			break;
187 	}
188 
189 	if (fstypes[i].name == NULL) {
190 		warnx("%s: filesystem not recognized", path);
191 		return (1);
192 	}
193 
194 	if (show_label && label[0] != '\0') {
195 		/*
196 		 * XXX: I'd prefer VIS_HTTPSTYLE, but it unconditionally
197 		 *      encodes spaces.
198 		 */
199 		nbytes = strsnvis(strvised, sizeof(strvised), label,
200 		    VIS_GLOB | VIS_NL, "\"'$");
201 		if (nbytes == -1)
202 			err(1, "strsnvis");
203 
204 		printf("%s %s\n", fstypes[i].name, strvised);
205 	} else {
206 		printf("%s\n", fstypes[i].name);
207 	}
208 
209 	return (0);
210 }
211