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