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