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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <sys/types.h> 29 #include <errno.h> 30 #include <limits.h> 31 #include <unistd.h> 32 #include <libintl.h> 33 #include <string.h> 34 35 #include "main.h" 36 #include "util.h" 37 #include "misc_scsi.h" 38 #include "mmc.h" 39 #include "bstream.h" 40 #include "device.h" 41 #include "msgs.h" 42 #include "transport.h" 43 44 struct t_data { 45 bstreamhandle h; 46 struct track_info ti; 47 }; 48 49 int read_audio_track(cd_device *dev, struct track_info *ti, bstreamhandle h); 50 51 #define READ_BURST 24 /* < 64K in all cases */ 52 53 /* 54 * This reads the data off of a cd while updating the progress indicator. 55 * We want to do this in smaller chunks since some CD drives have 56 * problems with larger reads. 57 */ 58 static int 59 read_data_track(cd_device *dev, struct track_info *ti, bstreamhandle h) 60 { 61 int blksize; 62 uint32_t blks_read, cblk, read_chunk, read_size; 63 uchar_t *buf; 64 int ret, sav; 65 int link_blks_count; 66 67 buf = NULL; 68 ret = 0; 69 70 /* 71 * the last link_blks_count blocks may not exist or be completely 72 * filled. We need to record the amount to avoid bailing out if 73 * they cannot be read. 74 */ 75 76 if (dev->d_blksize == 512) { 77 blksize = 512; 78 link_blks_count = 8; 79 } else { 80 blksize = 2048; 81 link_blks_count = 2; 82 } 83 84 buf = (uchar_t *)my_zalloc(READ_BURST * blksize); 85 86 print_n_flush(gettext("Reading track %d..."), ti->ti_track_no); 87 88 if (verbose) 89 print_n_flush("Track size is %u...", ti->ti_track_size); 90 91 init_progress(); 92 cblk = ti->ti_start_address; 93 blks_read = 0; 94 while (blks_read < ti->ti_track_size) { 95 /* Last few are special */ 96 read_chunk = ti->ti_track_size - blks_read - link_blks_count; 97 read_chunk = (read_chunk > READ_BURST) ? READ_BURST : 98 read_chunk; 99 if (read_chunk == 0) { 100 /* Time for last link blocks */ 101 read_chunk = link_blks_count; 102 } 103 read_size = read_chunk * blksize; 104 if (read10(dev->d_fd, cblk, read_chunk, buf, read_size)) { 105 if (h->bstr_write(h, buf, read_size) != read_size) { 106 goto read_data_track_failed; 107 } 108 } else { 109 if (blks_read != 110 (ti->ti_track_size - link_blks_count)) { 111 goto read_data_track_failed; 112 } else { 113 /* Read can fail for last link sectors */ 114 errno = 0; 115 } 116 } 117 blks_read += read_chunk; 118 cblk += read_chunk; 119 (void) progress((ti->ti_track_size), blks_read); 120 } 121 /* l10n_NOTE : 'done' as in "Reading track 1...done" */ 122 (void) str_print(gettext("done.\n"), progress_pos); 123 ret = 1; 124 read_data_track_failed: 125 sav = errno; 126 127 free(buf); 128 errno = sav; 129 return (ret); 130 } 131 132 static void 133 ensure_media_space(uint32_t total_nblks, uchar_t end_tno) 134 { 135 uint32_t nblks_avail; 136 uint_t bsize; 137 uint_t leadin_size = 0; 138 139 get_media_type(target->d_fd); 140 141 if (device_type == CD_RW) { 142 nblks_avail = get_last_possible_lba(target); 143 144 if (nblks_avail == 0) { 145 146 /* most newer drives use READ FORMAT CAPACITY */ 147 nblks_avail = read_format_capacity(target->d_fd, 148 &bsize); 149 150 /* if both methods fail, fall back on defaults */ 151 if (nblks_avail == 0) { 152 err_msg(gettext("Unable to determine media " 153 "capacity. Defaulting to 650 MB (74 minute)" 154 " disc.\n")); 155 nblks_avail = MAX_CD_BLKS; 156 } 157 leadin_size = end_tno*300; 158 } 159 } else { 160 /* 161 * For DVD drives use read_format_capacity as default 162 * retrieve the media size, it can be 3.6, 3.9, 4.2, 163 * 4.7, or 9.2 GB 164 */ 165 nblks_avail = read_format_capacity(target->d_fd, &bsize); 166 167 /* sanity check. if not reasonable default to 4.7 GB */ 168 if (nblks_avail < MAX_CD_BLKS) { 169 nblks_avail = MAX_DVD_BLKS; 170 } 171 } 172 173 if ((total_nblks + leadin_size) > nblks_avail) { 174 err_msg(gettext("Not enough space on the media.\n")); 175 if (debug) { 176 (void) printf("Need %u only found %u \n", 177 (total_nblks + leadin_size), 178 (uint32_t)nblks_avail); 179 } 180 181 exit(1); 182 } 183 } 184 185 /* 186 * This copies both audio and data CDs. It first reads the TOC of the source CD 187 * and creates a temp file with the CD image. After this is completed it creates 188 * the target CD using TAO mode. 189 */ 190 void 191 copy_cd(void) 192 { 193 cd_device *src; 194 char *p; 195 uchar_t *toc, end_tno; 196 int blksize, i; 197 int audio_cd, data_cd; 198 uint32_t total_nblks; 199 int ret; 200 struct t_data *tlist; 201 202 print_n_flush(gettext("Analyzing source CD...")); 203 (void) check_device(target, 204 CHECK_DEVICE_NOT_WRITABLE|EXIT_IF_CHECK_FAILED); 205 206 /* if source drive is specified on the command line */ 207 208 if (copy_src) { 209 p = my_zalloc(PATH_MAX); 210 if (lookup_device(copy_src, p) == 0) { 211 err_msg(gettext("Cannot find device %s"), copy_src); 212 err_msg(gettext(" or no media in the drive\n")); 213 exit(1); 214 } 215 src = get_device(copy_src, p); 216 if (src == NULL) { 217 err_msg(gettext("Unable to open %s\n"), copy_src); 218 exit(1); 219 } 220 free(p); 221 } else { 222 /* source is same as target drive */ 223 src = target; 224 } 225 226 (void) check_device(src, CHECK_TYPE_NOT_CDROM | CHECK_NO_MEDIA | 227 CHECK_DEVICE_NOT_READY | EXIT_IF_CHECK_FAILED); 228 229 /* What type of media are we working with? */ 230 get_media_type(src->d_fd); 231 232 toc = (uchar_t *)my_zalloc(4); 233 if (!read_toc(src->d_fd, 0, 0, 4, toc)) { 234 err_msg(gettext("Cannot read table of contents\n")); 235 exit(1); 236 } 237 end_tno = toc[3]; 238 free(toc); 239 tlist = (struct t_data *)my_zalloc(end_tno * sizeof (struct t_data)); 240 241 audio_cd = data_cd = 0; 242 total_nblks = 0; 243 244 /* build track information so we can copy it over */ 245 for (i = 1; i <= end_tno; i++) { 246 struct track_info *ti; 247 248 ti = &tlist[i - 1].ti; 249 if (!build_track_info(src, i, ti)) { 250 err_msg(gettext( 251 "Cannot get information for track %d\n"), i); 252 exit(1); 253 } 254 total_nblks += ti->ti_track_size; 255 if (ti->ti_track_mode & 4) 256 data_cd = 1; 257 else 258 audio_cd = 1; 259 260 /* Now some sanity checks on the track information */ 261 if ((ti->ti_flags & TI_SESSION_NO_VALID) && 262 (ti->ti_session_no != 1)) { 263 err_msg( 264 gettext("Copying multisession CD is not supported\n")); 265 exit(1); 266 } 267 if ((ti->ti_flags & TI_BLANK_TRACK) || 268 (ti->ti_flags & TI_DAMAGED_TRACK) || 269 (data_cd && audio_cd) || (ti->ti_data_mode == 2)) { 270 271 err_msg(gettext("CD format is not supported\n")); 272 exit(1); 273 } 274 if ((ti->ti_flags & TI_NWA_VALID) && 275 (ti->ti_nwa != 0xffffffff)) { 276 err_msg(gettext("Cannot copy incomplete discs\n")); 277 exit(1); 278 } 279 } 280 /* l10n_NOTE : 'done' as in "Analyzing source CD...done" */ 281 (void) printf(gettext("done.\n")); 282 283 if (data_cd) { 284 blksize = 2048; 285 } else { 286 /* audio cd */ 287 blksize = 2352; 288 } 289 290 /* In case of audio CDs, build_track_info() returns 2352 sized nblks */ 291 if (src->d_blksize == 512 && data_cd) { 292 total_nblks /= 4; 293 } 294 (void) printf(gettext("\nCopying %d %s track%s : %ld kbytes\n\n"), 295 end_tno, (audio_cd == 1) ? gettext("audio") : gettext("data"), 296 (end_tno > 1) ? "s" : "", (long)((total_nblks*blksize)/1024)); 297 298 if ((ret = check_avail_temp_space(total_nblks*blksize)) != 0) { 299 err_msg(gettext("Cannot use temporary directory : %s\n"), 300 strerror(ret)); 301 err_msg(gettext("Use -m to specify alternate" 302 " temporary directory\n")); 303 exit(1); 304 } 305 306 /* 307 * If we can check available space on the target media at this 308 * Stage, then it is always better. We cannot check DVD+R(W) 309 * as this media may be formatted and not blank. 310 */ 311 if (target && (src != target) && (device_type != DVD_PLUS) && 312 (device_type != DVD_PLUS_W) && (!check_device(target, 313 CHECK_NO_MEDIA|CHECK_MEDIA_IS_NOT_BLANK))) { 314 ensure_media_space(total_nblks, end_tno); 315 } 316 317 /* for each track */ 318 for (i = 1; i <= end_tno; i++) { 319 tlist[i - 1].h = open_temp_file_stream(); 320 if (tlist[i - 1].h == NULL) { 321 err_msg(gettext("Cannot create temporary file : %s\n"), 322 get_err_str()); 323 exit(1); 324 } 325 326 if (audio_cd) 327 ret = read_audio_track(src, &tlist[i - 1].ti, 328 tlist[i - 1].h); 329 else 330 ret = read_data_track(src, &tlist[i - 1].ti, 331 tlist[i - 1].h); 332 if (ret == 0) { 333 err_msg(gettext("Error reading track %d : %s\n"), i, 334 get_err_str()); 335 if (debug) 336 (void) printf("%x %x %x %x\n", uscsi_status, 337 SENSE_KEY(rqbuf), ASC(rqbuf), ASCQ(rqbuf)); 338 exit(1); 339 } 340 } 341 342 /* 343 * We've finished copying the CD. If source and destination are the same 344 * or they where not specified then eject the disk and wait for a new 345 * disk to be inserted. 346 * 347 * Since, DVD+RWs are not blanked just reformated, allow the insertion 348 * of a DVD+RW to be the only condition necessary to complete copying. 349 */ 350 351 do { 352 if (target != NULL) { 353 (void) eject_media(target); 354 } 355 356 (void) printf("\n"); 357 print_n_flush( 358 gettext("Insert a blank media in the drive and press Enter.")); 359 (void) fflush(stdin); 360 if (target) { 361 fini_device(target); 362 target = NULL; 363 } 364 (void) getchar(); 365 (void) sleep(4); 366 (void) setup_target(SCAN_WRITERS); 367 if (target) 368 get_media_type(target->d_fd); 369 } while ((target == NULL) || 370 ((device_type == DVD_PLUS_W)? check_device(target, CHECK_NO_MEDIA): 371 check_device(target, CHECK_NO_MEDIA|CHECK_MEDIA_IS_NOT_BLANK))); 372 373 (void) printf("\n"); 374 (void) setreuid(ruid, 0); 375 376 if ((device_type != DVD_PLUS) && (device_type != DVD_PLUS_W)) { 377 ensure_media_space(total_nblks, end_tno); 378 write_init(audio_cd ? TRACK_MODE_AUDIO : TRACK_MODE_DATA); 379 } 380 381 /* 382 * Simulation writing can't happen on DVD+RW's 383 * or DVD+R's. According to the MMC spec this 384 * operation is not supported. So we should 385 * bail out if the user tries to do a simulation 386 * write. 387 */ 388 if (simulation && (device_type == DVD_PLUS_W || 389 device_type == DVD_PLUS)) { 390 err_msg(gettext("Media does not support simulated writing.\n")); 391 exit(1); 392 } 393 394 if (device_type == DVD_PLUS_W) { 395 /* 396 * DVD+RW requires that we format the media before 397 * writing. 398 */ 399 (void) print_n_flush(gettext("Formatting media...")); 400 if (!format_media(target->d_fd)) { 401 (void) printf(gettext( 402 "Could not format media\n")); 403 exit(1); 404 } else { 405 int counter; 406 uchar_t *di; 407 408 /* poll until format is done */ 409 di = (uchar_t *)my_zalloc(DISC_INFO_BLOCK_SIZE); 410 (void) sleep(10); 411 for (counter = 0; counter < 200; counter++) { 412 ret = read_disc_info(target->d_fd, di); 413 if ((SENSE_KEY(rqbuf) == 2) && 414 (ASC(rqbuf) == 4)) { 415 (void) print_n_flush("."); 416 (void) sleep(5); 417 } else { 418 break; 419 } 420 } 421 } 422 } 423 424 /* for each track */ 425 for (i = 0; i < end_tno; i++) { 426 /* 427 * DVD's dont contain tracks and need to be written in DAO 428 * mode. 429 */ 430 if (device_type != CD_RW) { 431 if (end_tno > 1) { 432 err_msg(gettext( 433 "Media state is not suitable for this" 434 " write mode.\n")); 435 } 436 write_mode = DAO_MODE; 437 438 /* 439 * DVD-R(W) and DVD+R needs to have space reserved 440 * prior to writing. 441 */ 442 if ((device_type == DVD_MINUS) || 443 (device_type == DVD_PLUS)) { 444 if (!set_reservation(target->d_fd, 445 total_nblks + 1)) { 446 (void) printf(gettext( 447 "Setting reservation failed\n")); 448 exit(1); 449 } 450 } 451 } 452 453 write_next_track(audio_cd ? TRACK_MODE_AUDIO : TRACK_MODE_DATA, 454 tlist[i].h); 455 456 /* 457 * Running in simulation mode and writing several tracks is 458 * useless so bail after the first track is done. 459 */ 460 461 if (simulation && (end_tno != 1)) { 462 (void) printf(gettext( 463 "Simulation mode : skipping remaining tracks\n")); 464 break; 465 } 466 } 467 468 write_fini(); 469 /* close the temp file handles */ 470 for (i = 0; i < end_tno; i++) 471 (tlist[i].h)->bstr_close(tlist[i].h); 472 free(tlist); 473 fini_device(target); 474 exit(0); 475 } 476