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