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