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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <fcntl.h> 28 #include <errno.h> 29 #include <sys/stat.h> 30 #include <sys/dkio.h> 31 #include <unistd.h> 32 #include <dirent.h> 33 #include <string.h> 34 #include <stdlib.h> 35 #include <libintl.h> 36 #include <limits.h> 37 #include <dbus/dbus.h> 38 #include <hal/libhal.h> 39 40 #include "transport.h" 41 #include "mmc.h" 42 #include "device.h" 43 #include "util.h" 44 #include "msgs.h" 45 #include "misc_scsi.h" 46 #include "toshiba.h" 47 #include "main.h" 48 49 /* 50 * Old sun drives have a vendor specific mode page for setting/getting speed. 51 * Also they use a different method for extracting audio. 52 * We have the device inquiry strings at this time. This is used to enable 53 * us to use older sun drives to extract audio. 54 */ 55 static int 56 is_old_sun_drive(cd_device *dev) 57 { 58 /* 59 * If we have a SONY CDU 561, CDU 8012, or TOSHIBA model with XMa we 60 * need to handle these drives a bit differently. 61 */ 62 if (strncmp("SONY", (const char *)&dev->d_inq[8], 4) == 0) { 63 if (strncmp("CDU 561", (const char *)&dev->d_inq[16], 7) == 0) 64 return (1); 65 if (strncmp("CDU-8012", (const char *)&dev->d_inq[16], 8) == 0) 66 return (1); 67 } 68 69 if ((strncmp("TOSHIBA", (const char *)&dev->d_inq[8], 7) == 0) && 70 (strncmp("XM", (const char *)&dev->d_inq[16], 2) == 0)) { 71 72 char product_id[17]; 73 74 /* Changing speed is not allowed for 32X TOSHIBA drives */ 75 if (strncmp("SUN32XCD", (const char *)&dev->d_inq[24], 8) == 0) 76 dev->d_cap |= DEV_CAP_SETTING_SPEED_NOT_ALLOWED; 77 (void) strncpy(product_id, (const char *)&dev->d_inq[16], 16); 78 product_id[16] = 0; 79 if (strstr(product_id, "SUN") != NULL) 80 return (1); 81 } 82 return (0); 83 } 84 85 /* 86 * returns a cd_device handle for a node returned by lookup_device() 87 * also takes the user supplied name and stores it inside the node 88 */ 89 cd_device * 90 get_device(char *user_supplied, char *node) 91 { 92 cd_device *dev; 93 int fd; 94 uchar_t *cap; 95 char devnode[PATH_MAX]; 96 int size; 97 struct dk_minfo mediainfo; 98 int use_cd_speed = 0; 99 100 /* 101 * we need to resolve any link paths to avoid fake files 102 * such as /dev/rdsk/../../export/file. 103 */ 104 105 TRACE(traceall_msg("get_device(%s, %s)\n", user_supplied ? 106 user_supplied : "<nil>", node ? node : "<nil>")); 107 108 size = resolvepath(node, devnode, PATH_MAX); 109 if ((size <= 0) || (size >= (PATH_MAX - 1))) 110 return (NULL); 111 112 /* resolvepath may not return a null terminated string */ 113 devnode[size] = '\0'; 114 115 116 /* the device node must be in /devices/ or /vol/dev/rdsk */ 117 118 if ((strncmp(devnode, "/devices/", 9) != 0) && 119 (strncmp(devnode, "/vol/dev/rdsk", 13) != 0)) 120 return (NULL); 121 /* 122 * Since we are currently running with the user euid it is 123 * safe to try to open the file without checking access. 124 */ 125 126 fd = open(devnode, O_RDONLY|O_NDELAY); 127 128 if (fd < 0) { 129 TRACE(traceall_msg("Cannot open %s: %s\n", node, 130 strerror(errno))); 131 return (NULL); 132 } 133 134 dev = (cd_device *)my_zalloc(sizeof (cd_device)); 135 136 dev->d_node = (char *)my_zalloc(strlen(devnode) + 1); 137 (void) strcpy(dev->d_node, devnode); 138 139 dev->d_fd = fd; 140 141 dev->d_inq = (uchar_t *)my_zalloc(INQUIRY_DATA_LENGTH); 142 143 if (!inquiry(fd, dev->d_inq)) { 144 TRACE(traceall_msg("Inquiry failed on device %s\n", node)); 145 if (debug) { 146 (void) printf("USCSI ioctl failed %d\n", 147 uscsi_error); 148 } 149 free(dev->d_inq); 150 free(dev->d_node); 151 (void) close(dev->d_fd); 152 free(dev); 153 return (NULL); 154 } 155 156 if (debug) { 157 cap = (uchar_t *)my_zalloc(18); 158 (void) printf("Checking device type\n"); 159 if (get_mode_page(fd, 0x2A, 0, 8, cap)) { 160 if (cap[2] & 0x10) 161 (void) printf("DVD-R read support\n"); 162 if (cap[3] & 0x10) 163 (void) printf("DVD-R write support\n"); 164 if (cap[5] & 0x4) 165 (void) printf("R-W supported\n"); 166 if (cap[2] & 0x20) 167 (void) printf("DVD-RAM read supported\n"); 168 if (cap[3] & 0x20) 169 (void) printf("DVD-RAM write supported\n"); 170 } else { 171 (void) printf("Could not read mode page 2A! \n"); 172 } 173 free(cap); 174 } 175 176 /* Detect if it's a Lite-ON drive with a streaming CD problem */ 177 if ((strncmp("LITE-ON", (const char *)&dev->d_inq[8], 7) == 0) && 178 (strncmp("LTR-48", (const char *)&dev->d_inq[16], 6) == 0)) { 179 use_cd_speed = 1; 180 } 181 182 /* 183 * a workaround for the firmware problem in LITE-ON COMBO drives. 184 * streaming for these drives sets it only to max speed regardless 185 * of requested speed. cd_speed_ctrl allow speeds less than max 186 * to be set but not max thus the code below. (x48 is max speed 187 * for these drives). 188 */ 189 if ((strncmp("LITE-ON", (const char *)&dev->d_inq[8], 7) == 0) && 190 (strncmp("COMBO SOHC-4836VS", 191 (const char *)&dev->d_inq[16], 17) == 0)) 192 if (requested_speed < 48) 193 use_cd_speed = 1; 194 195 cap = (uchar_t *)my_zalloc(8); 196 if (is_old_sun_drive(dev)) { 197 dev->d_read_audio = toshiba_read_audio; 198 dev->d_speed_ctrl = toshiba_speed_ctrl; 199 } else { 200 /* 201 * If the CD Read Feature is supported, READ CD will work 202 * and will return jitter free audio data. Otherwise, look 203 * at Page Code 2A for this information. 204 */ 205 if (ftr_supported(fd, MMC_FTR_CD_READ) == 1) { 206 dev->d_read_audio = read_audio_through_read_cd; 207 dev->d_cap |= DEV_CAP_ACCURATE_CDDA; 208 } else if (get_mode_page(fd, 0x2A, 0, 8, cap)) { 209 if (cap[5] & 1) { 210 dev->d_read_audio = read_audio_through_read_cd; 211 if (cap[5] & 2) 212 dev->d_cap |= DEV_CAP_ACCURATE_CDDA; 213 } 214 } 215 /* 216 * If the Real Time Streaming Feature is supported then 217 * Real-time streaming commands can be used for speed control 218 * (except when we want to use cd_speed_ctrl explicitly which 219 * is specified by setting use_cd_speed to 1). 220 * Otherwise try SET CD SPEED. 221 */ 222 if ((ftr_supported(fd, MMC_FTR_RT_STREAM) == 1) && 223 !use_cd_speed) { 224 dev->d_speed_ctrl = rt_streaming_ctrl; 225 if (debug) 226 (void) printf("using rt speed ctrl\n"); 227 } else { 228 dev->d_speed_ctrl = cd_speed_ctrl; 229 if (debug) 230 (void) printf("using cd speed ctrl\n"); 231 } 232 } 233 if (dev->d_read_audio != NULL) 234 dev->d_cap |= DEV_CAP_EXTRACT_CDDA; 235 236 dev->d_blksize = 0; 237 238 /* 239 * Find the block size of the device so we can translate 240 * the reads/writes to the device blocksize. 241 */ 242 243 if (ioctl(fd, DKIOCGMEDIAINFO, &mediainfo) < 0) { 244 /* 245 * If DKIOCGMEDIAINFO fails we'll try to get 246 * the blocksize from the device itself. 247 */ 248 if (debug) 249 (void) printf("DKIOCGMEDIAINFO failed\n"); 250 if (read_capacity(fd, cap)) 251 dev->d_blksize = read_scsi32(cap + 4); 252 } else { 253 254 dev->d_blksize = mediainfo.dki_lbsize; 255 } 256 257 if (debug) { 258 uint_t bsize; 259 260 (void) printf("blocksize = %d\n", dev->d_blksize); 261 (void) printf("read_format_capacity = %d \n", 262 read_format_capacity(fd, &bsize)); 263 } 264 265 /* 266 * Some devices will return invalid blocksizes. ie. Toshiba 267 * drives will return 2352 when an audio CD is inserted. 268 * Older Sun drives will use 512 byte block sizes. All newer 269 * drives should have 2k blocksizes. 270 */ 271 if (((dev->d_blksize != 512) && (dev->d_blksize != 2048))) { 272 if (is_old_sun_drive(dev)) { 273 dev->d_blksize = 512; 274 } else { 275 dev->d_blksize = 2048; 276 } 277 if (debug) 278 (void) printf(" switching to %d\n", dev->d_blksize); 279 } 280 281 free(cap); 282 if (user_supplied) { 283 dev->d_name = (char *)my_zalloc(strlen(user_supplied) + 1); 284 (void) strcpy(dev->d_name, user_supplied); 285 } 286 TRACE(traceall_msg("Got device %s\n", node)); 287 return (dev); 288 } 289 290 void 291 fini_device(cd_device *dev) 292 { 293 free(dev->d_inq); 294 free(dev->d_node); 295 (void) close(dev->d_fd); 296 if (dev->d_name) 297 free(dev->d_name); 298 free(dev); 299 } 300 301 /* 302 * Given a /dev path resolve that path to a symbolic 303 * name such as cdrom0 if hald is running. If hald is 304 * not running, or does not have a symbolic name for the 305 * the specified /dev path return NULL. 306 */ 307 static char * 308 hald_symname(char *path) 309 { 310 LibHalContext *ctx = NULL; 311 DBusError error; 312 313 char **udi, *p = NULL; 314 int ndevs = 0, i; 315 316 /* Make sure hald is running */ 317 if (vol_running == 0) 318 return (p); 319 320 dbus_error_init(&error); 321 322 if ((ctx = attach_to_hald()) == NULL) 323 return (p); 324 325 if ((udi = libhal_manager_find_device_string_match(ctx, 326 HAL_RDSK_PROP, path, &ndevs, &error)) == NULL) 327 goto done; 328 329 /* Look for the node that contains the valid (non-null) symdev */ 330 for (i = 0; i < ndevs; i++) { 331 if ((p = libhal_device_get_property_string(ctx, udi[i], 332 HAL_SYMDEV_PROP, NULL)) != NULL) 333 break; 334 else 335 libhal_free_string(p); 336 } 337 338 done: 339 if (udi != NULL) 340 libhal_free_string_array(udi); 341 if (dbus_error_is_set(&error)) 342 dbus_error_free(&error); 343 detach_from_hald(ctx, HAL_INITIALIZED); 344 return (p); 345 } 346 347 /* 348 * Given a name resolve that name to a raw device in the case 349 * that it is a symbolic name or just return what is given if 350 * we are given a /dev path or hald is not running. 351 */ 352 static char * 353 hald_findname(char *symname) 354 { 355 LibHalContext *ctx = NULL; 356 DBusError error; 357 358 char **udi, *path = NULL; 359 int ndevs = 0, i; 360 361 /* 362 * We already have a raw path lets return it in a copied buffer 363 * as our caller assumes that they need to free memory. 364 */ 365 if (symname[0] == '/') { 366 path = my_zalloc(strlen(symname) + 1); 367 (void) strlcpy(path, symname, (strlen(symname) + 1)); 368 return (path); 369 } 370 371 /* Get the raw device from the hal record */ 372 if (vol_running != 0) { 373 dbus_error_init(&error); 374 375 if ((ctx = attach_to_hald()) == NULL) 376 return (path); 377 378 if ((udi = libhal_manager_find_device_string_match(ctx, 379 HAL_SYMDEV_PROP, symname, &ndevs, 380 &error)) == NULL) 381 goto done; 382 383 /* 384 * Loop over the returned UDIs to access the raw 385 * device path. 386 */ 387 for (i = 0; i < ndevs; i++) { 388 if ((path = libhal_device_get_property_string(ctx, 389 udi[i], HAL_RDSK_PROP, NULL)) != NULL) 390 break; 391 else 392 libhal_free_string(path); 393 } 394 395 done: 396 if (udi != NULL) 397 libhal_free_string_array(udi); 398 if (dbus_error_is_set(&error)) 399 dbus_error_free(&error); 400 detach_from_hald(ctx, HAL_INITIALIZED); 401 return (path); 402 } else { 403 return (NULL); 404 } 405 } 406 407 static int 408 vol_name_to_dev_node(char *vname, char *found) 409 { 410 struct stat statbuf; 411 char *p1; 412 int i; 413 414 if (vname == NULL) 415 return (0); 416 417 p1 = hald_findname(vname); 418 419 if (p1 == NULL) 420 return (0); 421 if (stat(p1, &statbuf) < 0) { 422 libhal_free_string(p1); 423 return (0); 424 } 425 if (S_ISDIR(statbuf.st_mode)) { 426 for (i = 0; i < 16; i++) { 427 (void) snprintf(found, PATH_MAX, "%s/s%d", p1, i); 428 if (access(found, F_OK) >= 0) 429 break; 430 } 431 if (i == 16) { 432 libhal_free_string(p1); 433 return (0); 434 } 435 } else { 436 (void) strlcpy(found, p1, PATH_MAX); 437 } 438 libhal_free_string(p1); 439 return (1); 440 } 441 442 /* 443 * Builds an open()able device path from a user supplied node which can be 444 * of the * form of /dev/[r]dsk/cxtxdx[sx] or cxtxdx[sx] or volmgt-name like 445 * cdrom[n] 446 * returns the path found in 'found' and returns 1. Otherwise returns 0. 447 */ 448 int 449 lookup_device(char *supplied, char *found) 450 { 451 struct stat statbuf; 452 int fd; 453 char tmpstr[PATH_MAX]; 454 455 /* If everything is fine and proper, no need to analyze */ 456 if ((stat(supplied, &statbuf) == 0) && S_ISCHR(statbuf.st_mode) && 457 ((fd = open(supplied, O_RDONLY|O_NDELAY)) >= 0)) { 458 (void) close(fd); 459 (void) strlcpy(found, supplied, PATH_MAX); 460 return (1); 461 } 462 463 /* 464 * Hal only allows access to a device when the user is 465 * on the console, therefore if hal is running and we can't 466 * open the /dev/rdsk or /dev/removable-media/rdsk device 467 * file we will return 0 marking this device as not avaiable. 468 */ 469 if (fd < 0 && ((strncmp(supplied, "/dev/rdsk/", 10) == 0) || 470 (strncmp(supplied, "/dev/removable-media/rdsk/", 26) == 0))) 471 return (0); 472 473 if ((strncmp(supplied, "/dev/dsk/", 9) == 0) || 474 (strncmp(supplied, "/dev/removable-media/dsk/", 25) == 0)) { 475 (void) snprintf(tmpstr, PATH_MAX, "/dev/rdsk/%s", 476 (char *)strrchr(supplied, '/')); 477 478 if ((fd = open(tmpstr, O_RDONLY|O_NDELAY)) >= 0) { 479 (void) close(fd); 480 (void) strlcpy(found, supplied, PATH_MAX); 481 return (1); 482 } 483 484 /* This device can't be opened mark it as unavailable. */ 485 return (0); 486 } 487 if ((strncmp(supplied, "cdrom", 5) != 0) && 488 (strlen(supplied) < 32)) { 489 (void) snprintf(tmpstr, sizeof (tmpstr), "/dev/rdsk/%s", 490 supplied); 491 if (access(tmpstr, F_OK) < 0) { 492 (void) strcat(tmpstr, "s2"); 493 } 494 if ((fd = open(tmpstr, O_RDONLY|O_NDELAY)) >= 0) { 495 (void) close(fd); 496 (void) strlcpy(found, tmpstr, PATH_MAX); 497 return (1); 498 } 499 500 /* This device can't be opened mark it as unavailable. */ 501 return (0); 502 } 503 return (vol_name_to_dev_node(supplied, found)); 504 } 505 506 /* 507 * Opens the device node name passed and returns 1 (true) if the 508 * device is a CD. 509 */ 510 511 static int 512 is_cd(char *node) 513 { 514 int fd; 515 struct dk_cinfo cinfo; 516 int ret = 1; 517 518 fd = open(node, O_RDONLY|O_NDELAY); 519 if (fd < 0) { 520 ret = 0; 521 } else if (ioctl(fd, DKIOCINFO, &cinfo) < 0) { 522 ret = 0; 523 } else if (cinfo.dki_ctype != DKC_CDROM) { 524 ret = 0; 525 } 526 527 if (fd >= 0) { 528 (void) close(fd); 529 } 530 return (ret); 531 } 532 533 static void 534 print_header(void) 535 { 536 /* l10n_NOTE : Column spacing should be kept same */ 537 (void) printf(gettext(" Node Connected Device")); 538 /* l10n_NOTE : Column spacing should be kept same */ 539 (void) printf(gettext(" Device type\n")); 540 (void) printf( 541 "----------------------+--------------------------------"); 542 (void) printf("+-----------------\n"); 543 } 544 545 /* 546 * returns the number of writers or CD/DVD-roms found and the path of 547 * the first device found depending on the mode argument. 548 * possible mode values are: 549 * SCAN_ALL_CDS Scan all CD/DVD devices. Return first CD-RW found. 550 * SCAN_WRITERS Scan all CD-RW devices. Return first one found. 551 * SCAN_LISTDEVS List all devices found. 552 */ 553 int 554 scan_for_cd_device(int mode, cd_device **found) 555 { 556 DIR *dir; 557 struct dirent *dirent; 558 char sdev[PATH_MAX], dev[PATH_MAX]; 559 cd_device *t_dev; 560 int writers_found = 0; 561 int header_printed = 0; 562 int is_writer; 563 int total_devices_found; 564 565 TRACE(traceall_msg("scan_for_cd_devices (mode=%d) called\n", mode)); 566 567 if (mode) { 568 (void) printf(gettext("Looking for CD devices...\n")); 569 } 570 571 dir = opendir("/dev/rdsk"); 572 if (dir == NULL) 573 return (0); 574 575 writers_found = 0; 576 total_devices_found = 0; 577 while ((dirent = readdir(dir)) != NULL) { 578 if (dirent->d_name[0] == '.') 579 continue; 580 (void) snprintf(sdev, PATH_MAX, "/dev/rdsk/%s", 581 dirent->d_name); 582 if (strcmp("s2", (char *)strrchr(sdev, 's')) != 0) 583 continue; 584 if (!lookup_device(sdev, dev)) 585 continue; 586 if (!is_cd(dev)) 587 continue; 588 if ((t_dev = get_device(NULL, dev)) == NULL) { 589 continue; 590 } 591 total_devices_found++; 592 593 is_writer = !(check_device(t_dev, CHECK_DEVICE_NOT_WRITABLE)); 594 595 if (is_writer) { 596 writers_found++; 597 598 if ((writers_found == 1) && (mode != SCAN_LISTDEVS)) { 599 *found = t_dev; 600 } 601 602 } else if ((mode == SCAN_ALL_CDS) && (writers_found == 0) && 603 (total_devices_found == 1) && found) { 604 605 /* We found a CD-ROM or DVD-ROM */ 606 *found = t_dev; 607 } 608 609 if (mode == SCAN_LISTDEVS) { 610 char *sn; 611 612 sn = hald_symname(sdev); 613 if (!header_printed) { 614 print_header(); 615 header_printed = 1; 616 } 617 /* show vendor, model, firmware rev and device type */ 618 (void) printf(" %-21.21s| %.8s %.16s %.4s | %s%s\n", 619 sn ? sn : sdev, &t_dev->d_inq[8], 620 &t_dev->d_inq[16], &t_dev->d_inq[32], 621 gettext("CD Reader"), 622 is_writer ? gettext("/Writer") : ""); 623 if (sn) 624 free(sn); 625 } 626 if ((found != NULL) && ((*found) != t_dev)) 627 fini_device(t_dev); 628 } 629 630 (void) closedir(dir); 631 632 if ((mode & SCAN_WRITERS) || writers_found) 633 return (writers_found); 634 else 635 return (total_devices_found); 636 } 637 638 /* 639 * Check device for various conditions/capabilities 640 * If EXIT_IF_CHECK_FAILED set in cond then it will also exit after 641 * printing a message. 642 */ 643 int 644 check_device(cd_device *dev, int cond) 645 { 646 uchar_t *disc_info, disc_status = 0, erasable = 0; 647 uchar_t page_code[4]; 648 char *errmsg = NULL; 649 650 if ((errmsg == NULL) && (cond & CHECK_TYPE_NOT_CDROM) && 651 ((dev->d_inq[0] & 0x1f) != 5)) { 652 errmsg = 653 gettext("Specified device does not appear to be a CDROM"); 654 } 655 656 if ((errmsg == NULL) && (cond & CHECK_DEVICE_NOT_READY) && 657 !test_unit_ready(dev->d_fd)) { 658 errmsg = gettext("Device not ready"); 659 } 660 661 /* Look at the capabilities page for this information */ 662 if ((errmsg == NULL) && (cond & CHECK_DEVICE_NOT_WRITABLE)) { 663 if (!get_mode_page(dev->d_fd, 0x2a, 0, 4, page_code) || 664 ((page_code[3] & 1) == 0)) { 665 errmsg = gettext("Target device is not a CD writer"); 666 } 667 } 668 669 if ((errmsg == NULL) && (cond & CHECK_NO_MEDIA)) { 670 if (!test_unit_ready(dev->d_fd) && (uscsi_status == 2) && 671 ((RQBUFLEN - rqresid) >= 14) && 672 ((SENSE_KEY(rqbuf) & 0x0f) == 2) && (ASC(rqbuf) == 0x3A) && 673 ((ASCQ(rqbuf) == 0) || (ASCQ(rqbuf) == 1) || 674 (ASCQ(rqbuf) == 2))) { 675 /* medium not present */ 676 errmsg = gettext("No media in device"); 677 } 678 } 679 680 681 682 /* Issue READ DISC INFORMATION mmc command */ 683 if ((errmsg == NULL) && ((cond & CHECK_MEDIA_IS_NOT_BLANK) || 684 (cond & CHECK_MEDIA_IS_NOT_WRITABLE) || 685 (cond & CHECK_MEDIA_IS_NOT_ERASABLE))) { 686 687 disc_info = (uchar_t *)my_zalloc(DISC_INFO_BLOCK_SIZE); 688 if (!read_disc_info(dev->d_fd, disc_info)) { 689 errmsg = gettext("Cannot obtain disc information"); 690 } else { 691 disc_status = disc_info[2] & 0x03; 692 erasable = disc_info[2] & 0x10; 693 } 694 free(disc_info); 695 if (errmsg == NULL) { 696 if (!erasable && (cond & CHECK_MEDIA_IS_NOT_ERASABLE)) 697 errmsg = gettext( 698 "Media in the device is not erasable"); 699 else if ((disc_status != 0) && 700 (cond & CHECK_MEDIA_IS_NOT_BLANK)) 701 errmsg = gettext( 702 "Media in the device is not blank"); 703 else if ((disc_status == 2) && 704 (cond & CHECK_MEDIA_IS_NOT_WRITABLE) && 705 ((device_type != DVD_PLUS_W) && 706 (device_type != DVD_PLUS))) 707 errmsg = gettext( 708 "Media in the device is not writable"); 709 } 710 } 711 712 if (errmsg) { 713 if (cond & EXIT_IF_CHECK_FAILED) { 714 err_msg("%s.\n", errmsg); 715 exit(1); 716 } 717 return (1); 718 } 719 return (0); 720 } 721 722 /* 723 * Generic routine for writing whatever the next track is and taking 724 * care of the progress bar. Mode tells the track type (audio or data). 725 * Data from track is taken from the byte stream h 726 */ 727 void 728 write_next_track(int mode, bstreamhandle h) 729 { 730 struct track_info *ti; 731 struct trackio_error *te; 732 off_t size; 733 734 ti = (struct track_info *)my_zalloc(sizeof (*ti)); 735 if ((build_track_info(target, -1, ti) == 0) || 736 ((ti->ti_flags & TI_NWA_VALID) == 0)) { 737 if ((device_type == DVD_PLUS) || (device_type == 738 DVD_PLUS_W)) { 739 ti->ti_flags |= TI_NWA_VALID; 740 } else { 741 err_msg(gettext( 742 "Cannot get writable address for the media.\n")); 743 exit(1); 744 } 745 } 746 if (ti->ti_nwa != ti->ti_start_address) { 747 err_msg(gettext( 748 "Media state is not suitable for this write mode.\n")); 749 exit(1); 750 } 751 if (mode == TRACK_MODE_DATA) { 752 if (!(ti->ti_track_mode & 4)) { 753 /* Write track depends upon this bit */ 754 ti->ti_track_mode |= TRACK_MODE_DATA; 755 } 756 } 757 size = 0; 758 h->bstr_size(h, &size); 759 h->bstr_rewind(h); 760 te = (struct trackio_error *)my_zalloc(sizeof (*te)); 761 762 print_n_flush(gettext("Writing track %d..."), (int)ti->ti_track_no); 763 init_progress(); 764 if (!write_track(target, ti, h, progress, size, te)) { 765 if (te->err_type == TRACKIO_ERR_USER_ABORT) { 766 (void) str_print(gettext("Aborted.\n"), progress_pos); 767 } else { 768 if (device_type != DVD_PLUS_W) { 769 /* l10n_NOTE : 'failed' as in Writing Track...failed */ 770 (void) str_print(gettext("failed.\n"), 771 progress_pos); 772 } 773 } 774 } 775 /* l10n_NOTE : 'done' as in "Writing track 1...done" */ 776 (void) str_print(gettext("done.\n"), progress_pos); 777 free(ti); 778 free(te); 779 } 780 781 void 782 list(void) 783 { 784 if (scan_for_cd_device(SCAN_LISTDEVS, NULL) == 0) { 785 if (vol_running) { 786 err_msg(gettext( 787 "No CD writers found, no media in the drive " 788 "or not on the console.\n")); 789 } else { 790 if (cur_uid != 0) { 791 err_msg(gettext( 792 "Volume manager is not running.\n")); 793 err_msg(gettext( 794 "Please start volume manager or run cdrw as root to access all devices.\n")); 795 } else { 796 err_msg(gettext("No CD writers found.\n")); 797 } 798 } 799 } 800 exit(0); 801 } 802 803 void 804 get_media_type(int fd) 805 { 806 uchar_t *cap = (uchar_t *)my_zalloc(MMC_FTR_HDR_LEN); 807 808 if (get_configuration(fd, MMC_FTR_PRFL_LIST, 809 MMC_FTR_HDR_LEN, cap)) { 810 if (debug) 811 (void) print_profile_list(fd); 812 switch (read_scsi16(&cap[6])) { 813 case 0x8: /* CD-ROM */ 814 if (debug) 815 (void) printf("CD-ROM found\n"); 816 /* 817 * To avoid regression issues, treat as 818 * A cdrw, we will check the writable 819 * mode page to see if the media is 820 * actually writable. 821 */ 822 device_type = CD_RW; 823 break; 824 825 case 0x9: /* CD-R */ 826 if (debug) 827 (void) printf("CD-R found\n"); 828 device_type = CD_RW; 829 break; 830 831 case 0x10: /* DVD-ROM */ 832 /* 833 * Have seen drives return DVD+RW media 834 * DVD-ROM, so try treating it as a DVD+RW 835 * profile. checking for writable media 836 * is done through mode page 5. 837 */ 838 if (debug) 839 (void) printf("DVD-ROM found\n"); 840 device_type = DVD_PLUS_W; 841 break; 842 843 case 0xA: /* CD-RW */ 844 if (debug) 845 (void) printf("CD-RW found\n"); 846 device_type = CD_RW; 847 break; 848 849 case 0x11: /* DVD-R */ 850 if (debug) 851 (void) printf("DVD-R found\n"); 852 device_type = DVD_MINUS; 853 break; 854 855 case 0x12: /* DVD-RAM */ 856 if (debug) 857 (void) printf("DVD-RAM found\n"); 858 /* treat as CD-RW, may be a legacy drive */ 859 device_type = CD_RW; 860 break; 861 862 case 0x13: /* DVD-RW restricted overwrite */ 863 case 0x14: /* DVD-RW sequential */ 864 if (debug) 865 (void) printf("DVD-RW found\n"); 866 device_type = DVD_MINUS; 867 break; 868 869 case 0x15: /* DVD-R Dual Layer Sequential Recording */ 870 case 0x16: /* DVD-R Dual Layer Jump Recording */ 871 if (debug) 872 (void) printf("DVD-R DL found\n"); 873 device_type = DVD_MINUS; 874 break; 875 876 case 0x17: /* DVD-RW Dual Layer */ 877 if (debug) 878 (void) printf("DVD-RW DL found\n"); 879 device_type = DVD_MINUS; 880 break; 881 882 case 0x1A: /* DVD+RW */ 883 if (debug) 884 (void) printf("DVD+RW found\n"); 885 886 device_type = DVD_PLUS_W; 887 break; 888 889 case 0x1B: /* DVD+R */ 890 if (debug) 891 (void) printf("DVD+R found\n"); 892 device_type = DVD_PLUS; 893 break; 894 895 case 0x2A: /* DVD+RW Dual Layer */ 896 if (debug) 897 (void) printf("DVD+RW DL found\n"); 898 device_type = DVD_PLUS_W; 899 break; 900 901 case 0x2B: /* DVD+R Dual Layer */ 902 if (debug) 903 (void) printf("DVD+R DL found\n"); 904 device_type = DVD_PLUS; 905 break; 906 907 default: 908 if (debug) 909 (void) printf( 910 "unknown drive found\n type = 0x%x", 911 cap[7]); 912 /* 913 * Treat as CD_RW to avoid regression, may 914 * be a legacy drive. 915 */ 916 device_type = CD_RW; 917 } 918 } 919 free(cap); 920 } 921 922 /* Translate a transfer rate (eg, KB/s) into a Speed (eg, "2X") */ 923 uint_t 924 cdrw_bandwidth_to_x(uint_t rate) 925 { 926 switch (device_type) { 927 case DVD_PLUS_W: 928 case DVD_MINUS: 929 case DVD_PLUS: 930 return (DVD_RATE_TO_X(rate)); 931 932 default: 933 case CD_RW: 934 return (CD_RATE_TO_X(rate)); 935 } 936 } 937 938 /* Translate a Speed (eg, "2X") into a transfer rate (eg, KB/s) */ 939 uint_t 940 cdrw_x_to_bandwidth(uint_t x) 941 { 942 switch (device_type) { 943 case DVD_PLUS_W: 944 case DVD_MINUS: 945 case DVD_PLUS: 946 return (DVD_X_TO_RATE(x)); 947 948 default: 949 case CD_RW: 950 return (CD_X_TO_RATE(x)); 951 } 952 } 953