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