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