xref: /illumos-gate/usr/src/cmd/fs.d/hsfs/fstyp/fstyp.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * libfstyp module for hsfs
28  */
29 #include <unistd.h>
30 #include <stropts.h>
31 #include <fcntl.h>
32 #include <stdio.h>
33 #include <strings.h>
34 #include <sys/param.h>
35 #include <sys/stat.h>
36 #include <sys/time.h>
37 #include <sys/types.h>
38 #include <sys/file.h>
39 #include <sys/cdio.h>
40 #include <sys/dkio.h>
41 #include <libnvpair.h>
42 #include <libfstyp_module.h>
43 
44 #include <sys/fs/hsfs_spec.h>
45 #include <sys/fs/hsfs_isospec.h>
46 
47 typedef struct fstyp_hsfs {
48 	int		fd;
49 	nvlist_t	*attr;
50 	char		hs_buf[ISO_SECTOR_SIZE];
51 	int		hs_pvd_sec_no;
52 	char		iso_buf[ISO_SECTOR_SIZE];
53 	int		iso_pvd_sec_no;
54 	char		unix_buf[ISO_SECTOR_SIZE];
55 	int		unix_pvd_sec_no;
56 	int		cdroff;
57 	int		cd_type;
58 } fstyp_hsfs_t;
59 
60 #define	GETCDSECTOR(h, buf, secno, nosec) (getdisk(h, buf, \
61 	((secno)+(h)->cdroff)*ISO_SECTOR_SIZE, \
62 	(nosec)*ISO_SECTOR_SIZE))
63 
64 #define	NELEM(a)	sizeof (a) / sizeof (*(a))
65 
66 static int	ckvoldesc(fstyp_hsfs_t *h, int *cd_type);
67 static int	findhsvol(fstyp_hsfs_t *h, char *volp);
68 static int	findisovol(fstyp_hsfs_t *h, char *volp);
69 static int	findunixvol(fstyp_hsfs_t *h, char *volp);
70 static char	*get_old_name(char *new);
71 static int	rdev_is_a_cd(int rdevfd);
72 static int	getdisk(fstyp_hsfs_t *h, char *buf, int daddr, int size);
73 static void	copy_string(char *d, char *s, int maxlen);
74 static int	is_hsfs(fstyp_hsfs_t *h);
75 static int	get_attr(fstyp_hsfs_t *h);
76 
77 int	fstyp_mod_init(int fd, off_t offset, fstyp_mod_handle_t *handle);
78 void	fstyp_mod_fini(fstyp_mod_handle_t handle);
79 int	fstyp_mod_ident(fstyp_mod_handle_t handle);
80 int	fstyp_mod_get_attr(fstyp_mod_handle_t handle, nvlist_t **attrp);
81 int	fstyp_mod_dump(fstyp_mod_handle_t handle, FILE *fout, FILE *ferr);
82 
83 
84 int
85 fstyp_mod_init(int fd, off_t offset, fstyp_mod_handle_t *handle)
86 {
87 	fstyp_hsfs_t	*h = (fstyp_hsfs_t *)handle;
88 
89 	if (offset != 0) {
90 		return (FSTYP_ERR_OFFSET);
91 	}
92 
93 	if ((h = calloc(1, sizeof (fstyp_hsfs_t))) == NULL) {
94 		return (FSTYP_ERR_NOMEM);
95 	}
96 	h->fd = fd;
97 
98 	*handle = (fstyp_mod_handle_t)h;
99 	return (0);
100 }
101 
102 void
103 fstyp_mod_fini(fstyp_mod_handle_t handle)
104 {
105 	fstyp_hsfs_t	*h = (fstyp_hsfs_t *)handle;
106 
107 	if (h->attr == NULL) {
108 		nvlist_free(h->attr);
109 		h->attr = NULL;
110 	}
111 	free(h);
112 }
113 
114 int
115 fstyp_mod_ident(fstyp_mod_handle_t handle)
116 {
117 	fstyp_hsfs_t *h = (fstyp_hsfs_t *)handle;
118 
119 	return (is_hsfs(h));
120 }
121 
122 int
123 fstyp_mod_get_attr(fstyp_mod_handle_t handle, nvlist_t **attrp)
124 {
125 	fstyp_hsfs_t	*h = (fstyp_hsfs_t *)handle;
126 	int error;
127 
128 	if (h->attr == NULL) {
129 		if (nvlist_alloc(&h->attr, NV_UNIQUE_NAME_TYPE, 0)) {
130 			return (FSTYP_ERR_NOMEM);
131 		}
132 		if ((error = get_attr(h)) != 0) {
133 			nvlist_free(h->attr);
134 			h->attr = NULL;
135 			return (error);
136 		}
137 	}
138 
139 	*attrp = h->attr;
140 	return (0);
141 }
142 
143 /* ARGSUSED */
144 int
145 fstyp_mod_dump(fstyp_mod_handle_t handle, FILE *fout, FILE *ferr)
146 {
147 	int		error;
148 	nvlist_t	*attr;
149 	nvpair_t	*elem = NULL;
150 	char		*str_value;
151 	uint64_t	uint64_value;
152 	char		*name;
153 
154 	if ((error = fstyp_mod_get_attr(handle, &attr)) != 0) {
155 		return (error);
156 	}
157 	while ((elem = nvlist_next_nvpair(attr, elem)) != NULL) {
158 		/* format is special */
159 		if (strcmp(nvpair_name(elem), "format") == 0) {
160 			(void) nvpair_value_string(elem, &str_value);
161 			if (strcmp(str_value,
162 			    "ISO 9660 with UNIX extension") == 0) {
163 				(void) fprintf(fout,
164 				    "CD-ROM is in ISO 9660 format with"
165 				    " UNIX extension\n");
166 			} else {
167 				(void) fprintf(fout, "CD-ROM is in %s"
168 				    " format\n", str_value);
169 			}
170 			continue;
171 		}
172 		if ((name = get_old_name(nvpair_name(elem))) == NULL) {
173 			continue;
174 		}
175 		if (nvpair_type(elem) == DATA_TYPE_STRING) {
176 			(void) nvpair_value_string(elem, &str_value);
177 			(void) fprintf(fout, "%s: %s\n", name, str_value);
178 		} else if (nvpair_type(elem) == DATA_TYPE_UINT64) {
179 			(void) nvpair_value_uint64(elem, &uint64_value);
180 			(void) fprintf(fout, "%s %llu\n",
181 			    name, (u_longlong_t)uint64_value);
182 		}
183 	}
184 
185 	return (0);
186 }
187 
188 static char *
189 get_old_name(char *new)
190 {
191 	static char	*map[] = {
192 		"system_id",		"System id",
193 		"volume_id",		"Volume id",
194 		"volume_set_id",	"Volume set id",
195 		"publisher_id",		"Publisher id",
196 		"data_preparer_id",	"Data preparer id",
197 		"application_id",	"Application id",
198 		"copyright_file_id",	"Copyright File id",
199 		"abstract_file_id",	"Abstract File id",
200 		"bibliographic_file_id", "Bibliographic File id",
201 		"volume_set_size",	"Volume set size is",
202 		"volume_set_sequence_number", "Volume set sequence number is",
203 		"logical_block_size",	"Logical block size is",
204 		"volume_size",		"Volume size is"
205 	};
206 	int	i;
207 	char	*old = NULL;
208 
209 	for (i = 0; i < NELEM(map) / 2; i++) {
210 		if (strcmp(new, map[i * 2]) == 0) {
211 			old = map[i * 2 + 1];
212 			break;
213 		}
214 	}
215 	return (old);
216 }
217 
218 /*
219  * findhsvol: check if the disk is in high sierra format
220  *            return(1) if found, (0) otherwise
221  *	      if found, volp will point to the descriptor
222  *
223  */
224 static int
225 findhsvol(fstyp_hsfs_t *h, char *volp)
226 {
227 	int secno;
228 	int i;
229 	int err;
230 
231 	secno = HS_VOLDESC_SEC;
232 	if ((err = GETCDSECTOR(h, volp, secno++, 1)) != 0) {
233 		return (err);
234 	}
235 	while (HSV_DESC_TYPE(volp) != VD_EOV) {
236 		for (i = 0; i < HSV_ID_STRLEN; i++)
237 			if (HSV_STD_ID(volp)[i] != HSV_ID_STRING[i])
238 				goto cantfind;
239 		if (HSV_STD_VER(volp) != HSV_ID_VER)
240 			goto cantfind;
241 		switch (HSV_DESC_TYPE(volp)) {
242 		case VD_SFS:
243 			h->hs_pvd_sec_no = secno-1;
244 			return (0);
245 		case VD_EOV:
246 			goto cantfind;
247 		}
248 		if ((err = GETCDSECTOR(h, volp, secno++, 1)) != 0) {
249 			return (err);
250 		}
251 	}
252 cantfind:
253 	return (FSTYP_ERR_NO_MATCH);
254 }
255 
256 /*
257  * findisovol: check if the disk is in ISO 9660 format
258  *            return(1) if found, (0) otherwise
259  *	      if found, volp will point to the descriptor
260  *
261  */
262 static int
263 findisovol(fstyp_hsfs_t *h, char *volp)
264 {
265 	int secno;
266 	int i;
267 	int err;
268 
269 	secno = ISO_VOLDESC_SEC;
270 	if ((err = GETCDSECTOR(h, volp, secno++, 1)) != 0) {
271 		return (err);
272 	}
273 	while (ISO_DESC_TYPE(volp) != ISO_VD_EOV) {
274 		for (i = 0; i < ISO_ID_STRLEN; i++)
275 			if (ISO_STD_ID(volp)[i] != ISO_ID_STRING[i])
276 				goto cantfind;
277 		if (ISO_STD_VER(volp) != ISO_ID_VER)
278 			goto cantfind;
279 		switch (ISO_DESC_TYPE(volp)) {
280 		case ISO_VD_PVD:
281 			h->iso_pvd_sec_no = secno-1;
282 			return (0);
283 		case ISO_VD_EOV:
284 			goto cantfind;
285 		}
286 		if ((err = GETCDSECTOR(h, volp, secno++, 1)) != 0) {
287 			return (err);
288 		}
289 	}
290 cantfind:
291 	return (FSTYP_ERR_NO_MATCH);
292 }
293 
294 /*
295  * findunixvol: check if the disk is in UNIX extension format
296  *            return(1) if found, (0) otherwise
297  *	      if found, volp will point to the descriptor
298  *
299  */
300 static int
301 findunixvol(fstyp_hsfs_t *h, char *volp)
302 {
303 	int secno;
304 	int i;
305 	int err;
306 
307 	secno = ISO_VOLDESC_SEC;
308 	if ((err = GETCDSECTOR(h, volp, secno++, 1)) != 0) {
309 		return (err);
310 	}
311 	while (ISO_DESC_TYPE(volp) != ISO_VD_EOV) {
312 		for (i = 0; i < ISO_ID_STRLEN; i++)
313 			if (ISO_STD_ID(volp)[i] != ISO_ID_STRING[i])
314 				goto cantfind;
315 		if (ISO_STD_VER(volp) != ISO_ID_VER)
316 			goto cantfind;
317 		switch (ISO_DESC_TYPE(volp)) {
318 		case ISO_VD_UNIX:
319 			h->unix_pvd_sec_no = secno-1;
320 			return (0);
321 		case ISO_VD_EOV:
322 			goto cantfind;
323 		}
324 		if ((err = GETCDSECTOR(h, volp, secno++, 1)) != 0) {
325 			return (err);
326 		}
327 	}
328 cantfind:
329 	return (FSTYP_ERR_NO_MATCH);
330 }
331 
332 static int
333 ckvoldesc(fstyp_hsfs_t *h, int *cd_type)
334 {
335 	int	err;
336 
337 	if ((err = findhsvol(h, h->hs_buf)) == 0) {
338 		*cd_type = 0;
339 	} else if ((err = findisovol(h, h->iso_buf)) == 0) {
340 		if (findunixvol(h, h->unix_buf) == 0) {
341 			*cd_type = 2;
342 		} else {
343 			*cd_type = 1;
344 		}
345 	} else {
346 		*cd_type = -1;
347 	}
348 
349 	return (err);
350 }
351 
352 static int
353 is_hsfs(fstyp_hsfs_t *h)
354 {
355 #ifdef CDROMREADOFFSET
356 	int err;
357 
358 	if (rdev_is_a_cd(h->fd)) {
359 		err = ioctl(h->fd, CDROMREADOFFSET, &h->cdroff);
360 		if (err == -1)
361 			/*
362 			 *  This device doesn't support this ioctl.
363 			 *  That's OK.
364 			 */
365 			h->cdroff = 0;
366 	}
367 #endif
368 	/* check volume descriptor */
369 	return (ckvoldesc(h, &h->cd_type));
370 }
371 
372 #define	ADD_STRING(h, name, value) \
373 	if (nvlist_add_string(h->attr, name, value) != 0) { \
374 		return (FSTYP_ERR_NOMEM); \
375 	}
376 
377 #define	ADD_UINT64(h, name, value) \
378 	if (nvlist_add_uint64(h->attr, name, value) != 0) { \
379 		return (FSTYP_ERR_NOMEM); \
380 	}
381 
382 #define	ADD_BOOL(h, name, value) \
383 	if (nvlist_add_boolean_value(h->attr, name, value) != 0) { \
384 		return (FSTYP_ERR_NOMEM); \
385 	}
386 
387 static int
388 get_attr(fstyp_hsfs_t *h)
389 {
390 	char *sysid;
391 	char *volid;
392 	char *volsetid;
393 	char *pubid;
394 	char *prepid;
395 	char *applid;
396 	char *copyfile;
397 	char *absfile;
398 	char *bibfile;
399 	int volsetsize;
400 	int volsetseq;
401 	int blksize;
402 	int volsize;
403 	char s[256];
404 
405 	switch (h->cd_type) {
406 	case 0:
407 		ADD_STRING(h, "format", "High Sierra");
408 		ADD_STRING(h, "gen_version", "High Sierra");
409 		sysid = (char *)HSV_sys_id(h->hs_buf);
410 		volid = (char *)HSV_vol_id(h->hs_buf);
411 		volsetid = (char *)HSV_vol_set_id(h->hs_buf);
412 		pubid = (char *)HSV_pub_id(h->hs_buf);
413 		prepid = (char *)HSV_prep_id(h->hs_buf);
414 		applid = (char *)HSV_appl_id(h->hs_buf);
415 		copyfile = (char *)HSV_copyr_id(h->hs_buf);
416 		absfile = (char *)HSV_abstr_id(h->hs_buf);
417 		bibfile = NULL;
418 		volsetsize = HSV_SET_SIZE(h->hs_buf);
419 		volsetseq = HSV_SET_SEQ(h->hs_buf);
420 		blksize = HSV_BLK_SIZE(h->hs_buf);
421 		volsize = HSV_VOL_SIZE(h->hs_buf);
422 		break;
423 	case 1:
424 		ADD_STRING(h, "format", "ISO 9660");
425 		ADD_STRING(h, "gen_version", "ISO 9660");
426 		sysid = (char *)ISO_sys_id(h->iso_buf);
427 		volid = (char *)ISO_vol_id(h->iso_buf);
428 		volsetid = (char *)ISO_vol_set_id(h->iso_buf);
429 		pubid = (char *)ISO_pub_id(h->iso_buf);
430 		prepid = (char *)ISO_prep_id(h->iso_buf);
431 		applid = (char *)ISO_appl_id(h->iso_buf);
432 		copyfile = (char *)ISO_copyr_id(h->iso_buf);
433 		absfile = (char *)ISO_abstr_id(h->iso_buf);
434 		bibfile = (char *)ISO_bibli_id(h->iso_buf);
435 		volsetsize = ISO_SET_SIZE(h->iso_buf);
436 		volsetseq = ISO_SET_SEQ(h->iso_buf);
437 		blksize = ISO_BLK_SIZE(h->iso_buf);
438 		volsize = ISO_VOL_SIZE(h->iso_buf);
439 		break;
440 	case 2:
441 		ADD_STRING(h, "format", "ISO 9660 with UNIX extension");
442 		ADD_STRING(h, "gen_version", "ISO 9660 with UNIX extension");
443 		sysid = (char *)ISO_sys_id(h->unix_buf);
444 		volid = (char *)ISO_vol_id(h->unix_buf);
445 		volsetid = (char *)ISO_vol_set_id(h->unix_buf);
446 		pubid = (char *)ISO_pub_id(h->unix_buf);
447 		prepid = (char *)ISO_prep_id(h->unix_buf);
448 		applid = (char *)ISO_appl_id(h->unix_buf);
449 		copyfile = (char *)ISO_copyr_id(h->unix_buf);
450 		absfile = (char *)ISO_abstr_id(h->unix_buf);
451 		bibfile = (char *)ISO_bibli_id(h->unix_buf);
452 		volsetsize = ISO_SET_SIZE(h->unix_buf);
453 		volsetseq = ISO_SET_SEQ(h->unix_buf);
454 		blksize = ISO_BLK_SIZE(h->unix_buf);
455 		volsize = ISO_VOL_SIZE(h->unix_buf);
456 		break;
457 	default:
458 		return (FSTYP_ERR_NO_MATCH);
459 	}
460 
461 	copy_string(s, sysid, 32);
462 	ADD_STRING(h, "system_id", s);
463 	copy_string(s, volid, 32);
464 	ADD_STRING(h, "volume_id", s);
465 	ADD_STRING(h, "gen_volume_label", s);
466 	copy_string(s, volsetid, 128);
467 	ADD_STRING(h, "volume_set_id", s);
468 	copy_string(s, pubid, 128);
469 	ADD_STRING(h, "publisher_id", s);
470 	copy_string(s, prepid, 128);
471 	ADD_STRING(h, "data_preparer_id", s);
472 	copy_string(s, applid, 128);
473 	ADD_STRING(h, "application_id", s);
474 	copy_string(s, copyfile, 37);
475 	ADD_STRING(h, "copyright_file_id", s);
476 	copy_string(s, absfile, 37);
477 	ADD_STRING(h, "abstract_file_id", s);
478 	copy_string(s, bibfile, 37);
479 	ADD_STRING(h, "bibliographic_file_id", s);
480 	ADD_UINT64(h, "volume_set_size", volsetsize);
481 	ADD_UINT64(h, "volume_set_sequence_number", volsetseq);
482 	ADD_UINT64(h, "logical_block_size", blksize);
483 	ADD_UINT64(h, "volume_size", volsize);
484 	ADD_BOOL(h, "gen_clean", B_TRUE);
485 
486 	return (0);
487 }
488 
489 static void
490 copy_string(char *d, char *s, int maxlen)
491 {
492 	int i;
493 
494 	/* strip off trailing zeros */
495 	for (i = maxlen-1; i >= 0; i--) {
496 		if (s[i] != ' ') {
497 			break;
498 		}
499 	}
500 
501 	maxlen = i+1;
502 	for (i = 0; i < maxlen; i++) {
503 		*d++ = s[i];
504 	}
505 	*d++ = '\0';
506 }
507 
508 /* readdisk - read from cdrom image file */
509 static int
510 getdisk(fstyp_hsfs_t *h, char *buf, int daddr, int size)
511 {
512 	if (lseek(h->fd, daddr, L_SET) == -1) {
513 		return (FSTYP_ERR_IO);
514 	}
515 	if (read(h->fd, buf, size) != size) {
516 		return (FSTYP_ERR_IO);
517 	}
518 	return (0);
519 }
520 
521 /*
522  * rdev_is_a_cd  - return TRUE if the raw device identified by
523  *		      a file descriptor is a CDROM device.
524  *
525  *		      return FALSE if the device can't be accessed
526  *		      or is not a CDROM.
527  */
528 static int
529 rdev_is_a_cd(int rdevfd)
530 {
531 	struct dk_cinfo dkc;
532 
533 	if (ioctl(rdevfd, DKIOCINFO, &dkc) < 0)
534 		return (0);
535 	if (dkc.dki_ctype == DKC_CDROM)
536 		return (1);
537 	else
538 		return (0);
539 }
540