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
read_data_track(cd_device * dev,struct track_info * ti,bstreamhandle h)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
ensure_media_space(uint32_t total_nblks,uchar_t end_tno)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
copy_cd(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