Thu Jan 2 08:52:42 2020 UTC ()
fstyp: Fix "exfat: iconv_open UCS-2LE: Invalid argument" failure

Fix below error for the time being.
The removed code is only relevant to Capsicum.

$ fstyp -l /dev/wd1
fstyp: exfat: iconv_open UCS-2LE: Invalid argument


(tkusumi)
diff -r1.11 -r1.12 src/usr.sbin/fstyp/fstyp.c

cvs diff -r1.11 -r1.12 src/usr.sbin/fstyp/fstyp.c (switch to unified diff)

--- src/usr.sbin/fstyp/fstyp.c 2020/01/01 12:47:19 1.11
+++ src/usr.sbin/fstyp/fstyp.c 2020/01/02 08:52:42 1.12
@@ -1,311 +1,295 @@ @@ -1,311 +1,295 @@
1/* $NetBSD: fstyp.c,v 1.11 2020/01/01 12:47:19 tkusumi Exp $ */ 1/* $NetBSD: fstyp.c,v 1.12 2020/01/02 08:52:42 tkusumi Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2017 The NetBSD Foundation, Inc. 4 * Copyright (c) 2017 The NetBSD Foundation, Inc.
5 * Copyright (c) 2016 The DragonFly Project 5 * Copyright (c) 2016 The DragonFly Project
6 * Copyright (c) 2014 The FreeBSD Foundation 6 * Copyright (c) 2014 The FreeBSD Foundation
7 * All rights reserved. 7 * All rights reserved.
8 * 8 *
9 * This code is derived from software contributed to The NetBSD Foundation 9 * This code is derived from software contributed to The NetBSD Foundation
10 * by Tomohiro Kusumi <kusumi.tomohiro@gmail.com>. 10 * by Tomohiro Kusumi <kusumi.tomohiro@gmail.com>.
11 * 11 *
12 * This software was developed by Edward Tomasz Napierala under sponsorship 12 * This software was developed by Edward Tomasz Napierala under sponsorship
13 * from the FreeBSD Foundation. 13 * from the FreeBSD Foundation.
14 * 14 *
15 * Redistribution and use in source and binary forms, with or without 15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions 16 * modification, are permitted provided that the following conditions
17 * are met: 17 * are met:
18 * 1. Redistributions of source code must retain the above copyright 18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer. 19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright 20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the 21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution. 22 * documentation and/or other materials provided with the distribution.
23 * 23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 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 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 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 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 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE. 34 * SUCH DAMAGE.
35 * 35 *
36 */ 36 */
37#include <sys/cdefs.h> 37#include <sys/cdefs.h>
38__RCSID("$NetBSD: fstyp.c,v 1.11 2020/01/01 12:47:19 tkusumi Exp $"); 38__RCSID("$NetBSD: fstyp.c,v 1.12 2020/01/02 08:52:42 tkusumi Exp $");
39 39
40#include <sys/param.h> 40#include <sys/param.h>
41#include <sys/disklabel.h> 41#include <sys/disklabel.h>
42#include <sys/dkio.h> 42#include <sys/dkio.h>
43#include <sys/ioctl.h> 43#include <sys/ioctl.h>
44#include <sys/stat.h> 44#include <sys/stat.h>
45#include <err.h> 45#include <err.h>
46#include <errno.h> 46#include <errno.h>
47#include <iconv.h> 47#include <iconv.h>
48#include <locale.h> 48#include <locale.h>
49#include <stdbool.h> 49#include <stdbool.h>
50#include <stddef.h> 50#include <stddef.h>
51#include <stdio.h> 51#include <stdio.h>
52#include <stdlib.h> 52#include <stdlib.h>
53#include <string.h> 53#include <string.h>
54#include <unistd.h> 54#include <unistd.h>
55#include <vis.h> 55#include <vis.h>
56 56
57#include "fstyp.h" 57#include "fstyp.h"
58 58
59#define LABEL_LEN 512 59#define LABEL_LEN 512
60 60
61bool show_label = false; 61bool show_label = false;
62 62
63typedef int (*fstyp_function)(FILE *, char *, size_t); 63typedef int (*fstyp_function)(FILE *, char *, size_t);
64typedef int (*fsvtyp_function)(const char *, char *, size_t); 64typedef int (*fsvtyp_function)(const char *, char *, size_t);
65 65
66static struct { 66static struct {
67 const char *name; 67 const char *name;
68 fstyp_function function; 68 fstyp_function function;
69 bool unmountable; 69 bool unmountable;
70 const char *precache_encoding; 70 const char *precache_encoding;
71} fstypes[] = { 71} fstypes[] = {
72 { "apfs", &fstyp_apfs, true, NULL }, 72 { "apfs", &fstyp_apfs, true, NULL },
73 { "cd9660", &fstyp_cd9660, false, NULL }, 73 { "cd9660", &fstyp_cd9660, false, NULL },
74 { "exfat", &fstyp_exfat, false, EXFAT_ENC }, 74 { "exfat", &fstyp_exfat, false, EXFAT_ENC },
75 { "ext2fs", &fstyp_ext2fs, false, NULL }, 75 { "ext2fs", &fstyp_ext2fs, false, NULL },
76 { "hfs+", &fstyp_hfsp, false, NULL }, 76 { "hfs+", &fstyp_hfsp, false, NULL },
77 { "msdosfs", &fstyp_msdosfs, false, NULL }, 77 { "msdosfs", &fstyp_msdosfs, false, NULL },
78 { "ntfs", &fstyp_ntfs, false, NTFS_ENC }, 78 { "ntfs", &fstyp_ntfs, false, NTFS_ENC },
79 { "ufs", &fstyp_ufs, false, NULL }, 79 { "ufs", &fstyp_ufs, false, NULL },
80 { "hammer", &fstyp_hammer, false, NULL }, 80 { "hammer", &fstyp_hammer, false, NULL },
81 { "hammer2", &fstyp_hammer2, false, NULL }, 81 { "hammer2", &fstyp_hammer2, false, NULL },
82#ifdef HAVE_ZFS 82#ifdef HAVE_ZFS
83 { "zfs", &fstyp_zfs, true, NULL }, 83 { "zfs", &fstyp_zfs, true, NULL },
84#endif 84#endif
85 { NULL, NULL, NULL, NULL } 85 { NULL, NULL, NULL, NULL }
86}; 86};
87 87
88static struct { 88static struct {
89 const char *name; 89 const char *name;
90 fsvtyp_function function; 90 fsvtyp_function function;
91 bool unmountable; 91 bool unmountable;
92 const char *precache_encoding; 92 const char *precache_encoding;
93} fsvtypes[] = { 93} fsvtypes[] = {
94 { "hammer", &fsvtyp_hammer, false, NULL }, /* Must be before partial */ 94 { "hammer", &fsvtyp_hammer, false, NULL }, /* Must be before partial */
95 { "hammer(partial)", &fsvtyp_hammer_partial, true, NULL }, 95 { "hammer(partial)", &fsvtyp_hammer_partial, true, NULL },
96 { NULL, NULL, NULL, NULL } 96 { NULL, NULL, NULL, NULL }
97}; 97};
98 98
99void * 99void *
100read_buf(FILE *fp, off_t off, size_t len) 100read_buf(FILE *fp, off_t off, size_t len)
101{ 101{
102 int error; 102 int error;
103 size_t nread; 103 size_t nread;
104 void *buf; 104 void *buf;
105 105
106 error = fseeko(fp, off, SEEK_SET); 106 error = fseeko(fp, off, SEEK_SET);
107 if (error != 0) { 107 if (error != 0) {
108 warn("cannot seek to %jd", (uintmax_t)off); 108 warn("cannot seek to %jd", (uintmax_t)off);
109 return NULL; 109 return NULL;
110 } 110 }
111 111
112 buf = malloc(len); 112 buf = malloc(len);
113 if (buf == NULL) { 113 if (buf == NULL) {
114 warn("cannot malloc %zd bytes of memory", len); 114 warn("cannot malloc %zd bytes of memory", len);
115 return NULL; 115 return NULL;
116 } 116 }
117 117
118 nread = fread(buf, len, 1, fp); 118 nread = fread(buf, len, 1, fp);
119 if (nread != 1) { 119 if (nread != 1) {
120 free(buf); 120 free(buf);
121 if (feof(fp) == 0) 121 if (feof(fp) == 0)
122 warn("fread"); 122 warn("fread");
123 return NULL; 123 return NULL;
124 } 124 }
125 125
126 return buf; 126 return buf;
127} 127}
128 128
129char * 129char *
130checked_strdup(const char *s) 130checked_strdup(const char *s)
131{ 131{
132 char *c; 132 char *c;
133 133
134 c = strdup(s); 134 c = strdup(s);
135 if (c == NULL) 135 if (c == NULL)
136 err(EXIT_FAILURE, "strdup"); 136 err(EXIT_FAILURE, "strdup");
137 return c; 137 return c;
138} 138}
139 139
140void 140void
141rtrim(char *label, size_t size) 141rtrim(char *label, size_t size)
142{ 142{
143 for (size_t i = size; i > 0; i--) { 143 for (size_t i = size; i > 0; i--) {
144 size_t j = i - 1; 144 size_t j = i - 1;
145 if (label[j] == '\0') 145 if (label[j] == '\0')
146 continue; 146 continue;
147 else if (label[j] == ' ') 147 else if (label[j] == ' ')
148 label[j] = '\0'; 148 label[j] = '\0';
149 else 149 else
150 break; 150 break;
151 } 151 }
152} 152}
153 153
154__dead static void 154__dead static void
155usage(void) 155usage(void)
156{ 156{
157 157
158 fprintf(stderr, "Usage: %s [-l] [-s] [-u] special\n", getprogname()); 158 fprintf(stderr, "Usage: %s [-l] [-s] [-u] special\n", getprogname());
159 exit(EXIT_FAILURE); 159 exit(EXIT_FAILURE);
160} 160}
161 161
162static void 162static void
163type_check(const char *path, FILE *fp) 163type_check(const char *path, FILE *fp)
164{ 164{
165 int error, fd; 165 int error, fd;
166 struct stat sb; 166 struct stat sb;
167 struct disklabel dl; 167 struct disklabel dl;
168 168
169 fd = fileno(fp); 169 fd = fileno(fp);
170 170
171 error = fstat(fd, &sb); 171 error = fstat(fd, &sb);
172 if (error != 0) 172 if (error != 0)
173 err(EXIT_FAILURE, "%s: fstat", path); 173 err(EXIT_FAILURE, "%s: fstat", path);
174 174
175 if (S_ISREG(sb.st_mode)) 175 if (S_ISREG(sb.st_mode))
176 return; 176 return;
177 177
178 error = ioctl(fd, DIOCGDINFO, &dl); 178 error = ioctl(fd, DIOCGDINFO, &dl);
179 if (error != 0) 179 if (error != 0)
180 errx(EXIT_FAILURE, "%s: not a disk", path); 180 errx(EXIT_FAILURE, "%s: not a disk", path);
181} 181}
182 182
183int 183int
184main(int argc, char **argv) 184main(int argc, char **argv)
185{ 185{
186 int ch, error, i, nbytes; 186 int ch, error, i, nbytes;
187 bool ignore_type = false, show_unmountable = false; 187 bool ignore_type = false, show_unmountable = false;
188 char label[LABEL_LEN + 1], strvised[LABEL_LEN * 4 + 1]; 188 char label[LABEL_LEN + 1], strvised[LABEL_LEN * 4 + 1];
189 char fdpath[MAXPATHLEN]; 189 char fdpath[MAXPATHLEN];
190 char *p; 190 char *p;
191 const char *path; 191 const char *path;
192 const char *name = NULL; 192 const char *name = NULL;
193 FILE *fp; 193 FILE *fp;
194 fstyp_function fstyp_f; 194 fstyp_function fstyp_f;
195 fsvtyp_function fsvtyp_f; 195 fsvtyp_function fsvtyp_f;
196 196
197 while ((ch = getopt(argc, argv, "lsu")) != -1) { 197 while ((ch = getopt(argc, argv, "lsu")) != -1) {
198 switch (ch) { 198 switch (ch) {
199 case 'l': 199 case 'l':
200 show_label = true; 200 show_label = true;
201 break; 201 break;
202 case 's': 202 case 's':
203 ignore_type = true; 203 ignore_type = true;
204 break; 204 break;
205 case 'u': 205 case 'u':
206 show_unmountable = true; 206 show_unmountable = true;
207 break; 207 break;
208 default: 208 default:
209 usage(); 209 usage();
210 } 210 }
211 } 211 }
212 212
213 argc -= optind; 213 argc -= optind;
214 argv += optind; 214 argv += optind;
215 if (argc != 1) 215 if (argc != 1)
216 usage(); 216 usage();
217 217
218 path = argv[0]; 218 path = argv[0];
219 219
220 if (setlocale(LC_CTYPE, "") == NULL) 220 if (setlocale(LC_CTYPE, "") == NULL)
221 err(1, "setlocale"); 221 err(1, "setlocale");
222 222
223 /* Cache iconv conversion data before entering capability mode. */ 
224 if (show_label) { 
225 for (i = 0; i < (int)__arraycount(fstypes); i++) { 
226 iconv_t cd; 
227 
228 if (fstypes[i].precache_encoding == NULL) 
229 continue; 
230 cd = iconv_open("", fstypes[i].precache_encoding); 
231 if (cd == (iconv_t)-1) 
232 err(1, "%s: iconv_open %s", fstypes[i].name, 
233 fstypes[i].precache_encoding); 
234 /* Iconv keeps a small cache of unused encodings. */ 
235 iconv_close(cd); 
236 } 
237 } 
238 
239 /* 223 /*
240 * DragonFly: Filesystems may have syntax to decorate path. 224 * DragonFly: Filesystems may have syntax to decorate path.
241 * Make a wild guess. 225 * Make a wild guess.
242 * XXX devpath is unsupported in NetBSD, but at least parse '@' for fp. 226 * XXX devpath is unsupported in NetBSD, but at least parse '@' for fp.
243 */ 227 */
244 strlcpy(fdpath, path, sizeof(fdpath)); 228 strlcpy(fdpath, path, sizeof(fdpath));
245 p = strchr(fdpath, '@'); 229 p = strchr(fdpath, '@');
246 if (p) 230 if (p)
247 *p = '\0'; 231 *p = '\0';
248 232
249 fp = fopen(fdpath, "r"); 233 fp = fopen(fdpath, "r");
250 if (fp == NULL) { 234 if (fp == NULL) {
251 if (strcmp(path, fdpath)) 235 if (strcmp(path, fdpath))
252 fp = fopen(path, "r"); 236 fp = fopen(path, "r");
253 if (fp == NULL) 237 if (fp == NULL)
254 goto fsvtyp; /* DragonFly */ 238 goto fsvtyp; /* DragonFly */
255 else 239 else
256 strlcpy(fdpath, path, sizeof(fdpath)); 240 strlcpy(fdpath, path, sizeof(fdpath));
257 } 241 }
258 242
259 if (ignore_type == false) 243 if (ignore_type == false)
260 type_check(fdpath, fp); 244 type_check(fdpath, fp);
261 245
262 memset(label, '\0', sizeof(label)); 246 memset(label, '\0', sizeof(label));
263 247
264 for (i = 0;; i++) { 248 for (i = 0;; i++) {
265 if (!show_unmountable && fstypes[i].unmountable) 249 if (!show_unmountable && fstypes[i].unmountable)
266 continue; 250 continue;
267 fstyp_f = fstypes[i].function; 251 fstyp_f = fstypes[i].function;
268 if (fstyp_f == NULL) 252 if (fstyp_f == NULL)
269 break; 253 break;
270 254
271 error = fstyp_f(fp, label, sizeof(label)); 255 error = fstyp_f(fp, label, sizeof(label));
272 if (error == 0) { 256 if (error == 0) {
273 name = fstypes[i].name; 257 name = fstypes[i].name;
274 goto done; 258 goto done;
275 } 259 }
276 } 260 }
277fsvtyp: 261fsvtyp:
278 for (i = 0;; i++) { 262 for (i = 0;; i++) {
279 if (!show_unmountable && fsvtypes[i].unmountable) 263 if (!show_unmountable && fsvtypes[i].unmountable)
280 continue; 264 continue;
281 fsvtyp_f = fsvtypes[i].function; 265 fsvtyp_f = fsvtypes[i].function;
282 if (fsvtyp_f == NULL) 266 if (fsvtyp_f == NULL)
283 break; 267 break;
284 268
285 error = fsvtyp_f(path, label, sizeof(label)); 269 error = fsvtyp_f(path, label, sizeof(label));
286 if (error == 0) { 270 if (error == 0) {
287 name = fsvtypes[i].name; 271 name = fsvtypes[i].name;
288 goto done; 272 goto done;
289 } 273 }
290 } 274 }
291 275
292 err(EXIT_FAILURE, "%s: filesystem not recognized", path); 276 err(EXIT_FAILURE, "%s: filesystem not recognized", path);
293 /*NOTREACHED*/ 277 /*NOTREACHED*/
294done: 278done:
295 if (show_label && label[0] != '\0') { 279 if (show_label && label[0] != '\0') {
296 /* 280 /*
297 * XXX: I'd prefer VIS_HTTPSTYLE, but it unconditionally 281 * XXX: I'd prefer VIS_HTTPSTYLE, but it unconditionally
298 * encodes spaces. 282 * encodes spaces.
299 */ 283 */
300 nbytes = strsnvis(strvised, sizeof(strvised), label, 284 nbytes = strsnvis(strvised, sizeof(strvised), label,
301 VIS_GLOB | VIS_NL, "\"'$"); 285 VIS_GLOB | VIS_NL, "\"'$");
302 if (nbytes == -1) 286 if (nbytes == -1)
303 err(EXIT_FAILURE, "strsnvis"); 287 err(EXIT_FAILURE, "strsnvis");
304 288
305 printf("%s %s\n", name, strvised); 289 printf("%s %s\n", name, strvised);
306 } else { 290 } else {
307 printf("%s\n", name); 291 printf("%s\n", name);
308 } 292 }
309 293
310 return EXIT_SUCCESS; 294 return EXIT_SUCCESS;
311} 295}