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