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