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
fstyp_mod_init(int fd,off_t offset,fstyp_mod_handle_t * handle)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
fstyp_mod_fini(fstyp_mod_handle_t handle)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
fstyp_mod_ident(fstyp_mod_handle_t handle)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
fstyp_mod_get_attr(fstyp_mod_handle_t handle,nvlist_t ** attrp)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
fstyp_mod_dump(fstyp_mod_handle_t handle,FILE * fout,FILE * ferr)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 *
get_old_name(char * new)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
findhsvol(fstyp_hsfs_t * h,char * volp)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
findisovol(fstyp_hsfs_t * h,char * volp)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
findunixvol(fstyp_hsfs_t * h,char * volp)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
ckvoldesc(fstyp_hsfs_t * h,int * cd_type)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
is_hsfs(fstyp_hsfs_t * h)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
get_attr(fstyp_hsfs_t * h)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
copy_string(char * d,char * s,int maxlen)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
getdisk(fstyp_hsfs_t * h,char * buf,int daddr,int size)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
rdev_is_a_cd(int rdevfd)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