Compare commits

...

219 Commits

Author SHA1 Message Date
0d3a31e3f0 Prepared configure.ac for release 2007-07-31 08:06:07 +00:00
205d5fed7d Documented changes and release timestamp 2007-07-20 18:17:26 +00:00
19c3d448a8 Updated cdrskin tarball generators 2007-07-20 18:15:35 +00:00
89762d91b4 Made number transition to 0.3.8 2007-07-20 18:13:17 +00:00
a6acdc64cc Branched 0.3.8 in preparation for release 2007-07-19 22:45:53 +00:00
7d23984220 Next cdrskin-0.3.7 cycle 2007-07-19 17:49:50 +00:00
aba535d700 Next cdrskin-0.3.7 cycle 2007-07-19 17:30:05 +00:00
203f158f5b Documented option --adjust_speed_to_drive (i.e. it will stay) 2007-07-19 17:27:26 +00:00
e274c90f9d Avoided new track-drive test with option --no_convert_fs_adr 2007-07-19 17:18:12 +00:00
bf25c6edc8 Trying to prevent usage of burn drive as track source 2007-07-19 14:29:59 +00:00
2c467c8378 Removed ban against speed 0 with burn_drive_set_buffer_waiting() 2007-07-19 07:23:01 +00:00
bdadae6ba5 Implemented minimum speed in burn_drive_set_speed() 2007-07-17 08:57:24 +00:00
1087d402f2 Clarification on option speed= 2007-07-17 08:55:10 +00:00
dc97c0d0df Experimental option --adjust_speed_to_drive. Caution: May vanish soon. 2007-07-14 11:23:16 +00:00
8b8afdd59b Only set realistic maximum DVD speeds (for my LG GSA which fails otherwise) 2007-07-14 11:22:01 +00:00
4dd8f098ac New API function burn_drive_get_best_speed() 2007-07-14 11:15:57 +00:00
16b6e1905a New options modesty_on_drive= and minbuf= 2007-07-12 17:31:57 +00:00
22d1d56ebd New API-Function burn_drive_set_buffer_waiting() 2007-07-12 17:17:41 +00:00
0217702b8c Preparations to avoid writing which will not fit in drive buffer 2007-07-12 16:29:29 +00:00
81d68aeb83 Changed "KB" to "kiB" 2007-06-10 08:06:03 +00:00
0e23721f2d Clarified MB to MiB if compatibility allows it (ticket 100) 2007-06-10 07:06:42 +00:00
3a771b3da2 Prevented macro interpretation of text snippet ".wav" 2007-06-08 10:56:15 +00:00
bacb815ecc Took into respect change of logo graphics format 2007-06-08 10:49:17 +00:00
f34d9efdb2 Changed logo graphics format from GIF to PNG 2007-06-08 09:59:29 +00:00
8efb863d5d Next cdrskin-0.3.7 cycle 2007-05-29 16:27:25 +00:00
d7ca1dd333 Fixed low transaction size introduced by cooperation of revisions 855 and 860 2007-05-28 19:25:09 +00:00
ddc2745495 Added check for .might_simulate to burn_write_opts_auto_write_type() 2007-05-28 17:03:12 +00:00
12c4c73535 Forgotten update of error list with revison 857 2007-05-28 16:59:49 +00:00
3326fcdb2d Extended struct burn_multi_caps by .might_simulate 2007-05-28 16:56:58 +00:00
fba8eaef80 Moved general 32 kiB buffer restriction from write.c to os-linux.h 2007-05-28 13:24:33 +00:00
15a70555b2 Added SCSI opcode to output of revision 857 2007-05-22 16:51:15 +00:00
83e196d69f Disabled macro Cdrskin_debug_libdax_msgS. Thus getting unqueued error messages. 2007-05-22 15:46:57 +00:00
c86f5d7cde Report eventual sg_io_hdr_t host_status,driver_status as debug messages 2007-05-22 15:45:57 +00:00
8d7d177ce3 Next cdrskin-0.3.7 cycle 2007-05-21 20:16:34 +00:00
cd7b4e6de4 For Linux 2.4, USB audio : Reduced CD output buffer size to 32 kiB 2007-05-21 19:03:06 +00:00
79adcb520b For Linux 2.4, USB : Carefully avoided to inquire more data than available 2007-05-21 18:57:09 +00:00
41f2a40a58 Prepared fflushing and stderr output of SCSI command log 2007-05-21 18:45:44 +00:00
9b663f15d9 Next cdrskin-0.3.7 cycle 2007-04-23 17:15:29 +00:00
ed9d3e2545 Updated cdrskin tarball generator 2007-04-23 15:48:40 +00:00
ba7cd6d66e Made number transition and activated development documentation 2007-04-23 15:43:51 +00:00
660bf40a3c Changed many /dev/sg to /dev/sr 2007-04-22 13:22:43 +00:00
25ba84a7e2 Repaired autotools bootstrap bug by help of sed 2007-04-22 12:20:33 +00:00
6566771834 Next cdrskin-0.3.5 cycle 2007-04-22 12:18:49 +00:00
2d2a2f8c1b Declared failure of DDLP to entirely solve the concurrency problem 2007-04-21 12:37:24 +00:00
329f266cea Beginning to develop DDLP-B 2007-04-20 21:16:17 +00:00
dce1ba57f3 Clarifications about motivation and duties of the participants 2007-04-19 11:34:54 +00:00
d3f08d4f96 Clarifications about motivation and duties of the participants 2007-04-19 11:31:59 +00:00
ddb63509af Corrected a list of standard paths 2007-04-18 21:48:45 +00:00
96098b3f2d Adaptations to new test results and discussions 2007-04-18 21:31:21 +00:00
256139c9d6 Polished messages, comments and description of DDLP-A 2007-04-18 13:01:21 +00:00
fd5b681bc6 Updated comments about DVD+R 2007-04-18 10:36:35 +00:00
2a38890c5f Progress due to tests with test/open-cd-excl 2007-04-18 10:35:38 +00:00
2ec2a34f51 Allowed for Friendly Programs: O_EXCL | O_RDONLY 2007-04-18 10:34:12 +00:00
10e320911a Program for probing access to device files. By Ted Ts'o with modifications by me. 2007-04-18 10:32:23 +00:00
9699880581 Corrected description of return values 2007-04-16 21:31:23 +00:00
13b9f910e1 Polished txt and finally threw out getter functions 2007-04-16 21:20:39 +00:00
acaba76cda Emerging description of DDLP 2007-04-16 19:45:11 +00:00
927a820aec Finalized DVD+R cookbook 2007-04-16 19:43:42 +00:00
3b9f66a765 Implemented ddlpa_lock_btl() 2007-04-15 20:34:27 +00:00
5d2ad006a4 Began test implementation of DDLP-A 2007-04-15 16:46:47 +00:00
aa03717f24 Made use of fcntl(F_SETLK) switchable (and thus became more free with default) 2007-04-13 17:28:25 +00:00
ab5f39b8bb Switched from O_NONBLOCK to O_NDELAY (see http://lkml.org/lkml/2007/4/11/141) 2007-04-13 17:12:06 +00:00
e1b8edb437 Clarified license. People who object shall please come forward now. 2007-04-12 14:47:59 +00:00
a78e6f9b29 Avoided SIGSEGV with an old SCSI CD-ROM drive and its wild replies 2007-04-10 14:46:46 +00:00
047f9c75f5 Fixed bug in sg_open_scsi_siblings() introduced with revision 802 2007-04-10 08:31:04 +00:00
159715ebaa Used O_EXCL|O_RDWR and fcntl() even within sg_obtain_scsi_adr() 2007-04-10 08:20:45 +00:00
f617567e03 Fixed bug with drive_scsi_dev_family= introduced by revision 796 (fcntl lock) 2007-04-10 08:17:07 +00:00
10a7a9d5e8 Next cdrskin-0.3.5 cycle 2007-04-10 07:58:19 +00:00
76ed9570c9 Reacted on compiler warning about last_rdev, fixed fresh typo bug 2007-04-09 11:10:41 +00:00
4bc8e4caea Cleaned up scsi sibling management, sketched grafting of DDLP 2007-04-09 10:54:17 +00:00
1a054b54c9 Updated media list in introduction comment 2007-04-06 06:49:51 +00:00
76a9fa4fa2 New cdrskin options --drive_not_f_setlk and --drive_not_o_excl 2007-04-04 18:43:23 +00:00
4c85686aad Added fcntl() locking to O_EXCL locking 2007-04-03 14:58:17 +00:00
a686340407 Make --old_pseudo_scsi_adr -scanbus work with any drive_scsi_dev_family= 2007-04-03 14:56:36 +00:00
16c7cf1889 Added fcntl() locking to O_EXCL locking 2007-04-03 14:04:04 +00:00
15b33422d0 Avoided unconditional finalizing of DVD+R 2007-03-30 21:47:56 +00:00
649f67697a Allowed finalizing of DVD+R 2007-03-30 20:11:36 +00:00
125e28160d Next cdrskin-0.3.5 cycle 2007-03-29 08:18:34 +00:00
eb860ee4b7 Silenced error message if tsize= is smaller than source is willing to deliver 2007-03-28 20:25:22 +00:00
a8c69206fe Made fifo based -isosize read 64k first and the rest only at normal stage 2007-03-28 18:21:46 +00:00
26745b4064 Enabled -isosize with S_IFREG or S_IFBLK files and without fifo 2007-03-28 16:02:26 +00:00
962f68b1d6 Silenced error condition about -sao with stdin and -isosize 2007-03-28 11:15:04 +00:00
cc5560fc86 Enabled -isosize for first track by help of fifo and without seeking 2007-03-28 10:07:09 +00:00
5d65697697 Preparations for option -isosize via fifo (only a debug message yet) 2007-03-27 21:33:22 +00:00
749d12591e Warning of very small tsize= settings. (Proposal by Eduard Bloch) 2007-03-24 09:34:56 +00:00
98f0dab87e Fixed bug with burn_disc_available_space(...,NULL) 2007-03-24 09:31:11 +00:00
17c87b78a6 Mentioned new sr behavior 2007-03-18 11:03:08 +00:00
ecbe1c0f39 Next cdrskin-0.3.5 cycle 2007-03-16 00:10:46 +00:00
9507587652 Updated drive_scsi_dev_family= 2007-03-15 20:34:08 +00:00
dba40c756b Trying to recognize kernel >= 2.6 and use /dev/sr by default 2007-03-15 19:59:54 +00:00
fd9e5dc935 Kept mmc_get_configuration() from believing the announcement of 1 GB reply 2007-03-15 19:55:17 +00:00
2816d8b569 Moved manual device family decision to a sufficiently early stage 2007-03-15 19:54:01 +00:00
64233b0ccc After loading tray wait for unit to become ready or to report some clear error 2007-03-15 19:50:57 +00:00
9e1b3719d6 React properly on drive stating that it cannot write any media 2007-03-15 19:46:26 +00:00
6086b59301 New option drive_scsi_dev_family=sr|scd|sg 2007-03-14 13:37:32 +00:00
c345426299 Next cdrskin-0.3.5 cycle 2007-03-14 13:15:00 +00:00
05216162ef Corrected truncated sentence and file sizes 2007-03-14 13:12:28 +00:00
13e2b23ace Updated cdrskin tarball generator 2007-03-12 16:01:51 +00:00
820f0924f9 Made number transition to 0.3.5 2007-03-12 15:58:19 +00:00
5b6aab575e Polished documentation 2007-03-10 11:49:49 +00:00
bd529442ed New option assert_write_lba= 2007-03-09 13:43:57 +00:00
33938c20eb Polished documentation 2007-03-08 21:55:50 +00:00
71c490d0ae Some adjustments for DVD+R recording 2007-03-07 15:13:25 +00:00
4458bb130a Enabled DVD+R as tested media (-multi is still always on) 2007-03-06 20:51:32 +00:00
99172bdeb4 Enabled DVD+R, DVD+R DL via --allow_untested_media_types, always -multi for now 2007-03-06 19:50:32 +00:00
790c75be9c Released cdrskin-0.3.2.pl01 2007-03-05 20:07:43 +00:00
6a5e1b6bd5 Fifo got stuck if sum of processed track sizes was exactly aligned to fifo size 2007-03-04 18:45:52 +00:00
49e0a6cb1a Fixed bug introduced with rev 736ff which prevented audio CD burning 2007-03-03 15:16:19 +00:00
b6c7fd7478 Re-enabled -force with write modes which seem unavailable 2007-03-03 14:11:52 +00:00
e955d50198 Determine physical interface SCSI,ATA,SATA,USB,... (for future use) 2007-03-03 14:09:46 +00:00
794d1ee712 Updated DVD-R[W] write mode description 2007-03-03 09:00:28 +00:00
3b5c80e867 Preparations for supporting DVD+R[/DL] 2007-03-01 12:07:29 +00:00
0c4cfdd359 Took into respect deliberate lack of DVD-R/DL multi session capability 2007-02-25 11:26:20 +00:00
f263443858 Forgotten source file for revision 743 2007-02-23 19:33:56 +00:00
362a8faa61 Enabled DVD-R/DL Sequential via --allow_untested_media_types 2007-02-23 19:10:30 +00:00
2e361e50ed Enabled DVD-R/DL Sequential via burn_allow_untested_profiles() 2007-02-23 19:08:58 +00:00
0ddeb01502 Made burn_disc_available_space() take into respect burn_write_opts_set_start_byte() 2007-02-22 11:30:12 +00:00
64ae333863 Macro for length of rejection reasons string (old size is still safe) 2007-02-22 09:49:18 +00:00
9f2c4b303d Disabled debugging messages about format descriptors 2007-02-22 07:31:32 +00:00
8182be7824 Re-enabled overwriteable pseudo-pseudo-SAO with unpredicted track size 2007-02-22 07:26:41 +00:00
fa6849374a Added -O2 to binary production 2007-02-21 20:57:04 +00:00
115f03cf63 Moved tao_to_sao_tsize into libburn, let cdrskin use auto_write_type and precheck 2007-02-21 20:53:28 +00:00
b6475c3d84 Re-arranged checking and defaulting of write parameters 2007-02-19 22:51:39 +00:00
afd54a1f87 Repaired slightly broken pacifier track size display with -audio 2007-02-19 18:41:38 +00:00
4f3dd8614d Adjusted maximum realistic number of tracks to MMC specs 2007-02-18 09:49:26 +00:00
7989d32834 Next cdrskin-0.3.3 cycle 2007-02-18 09:48:00 +00:00
0151358635 Clarified usage comment with burn_drive_info_free() (see ticket 98) 2007-02-18 09:44:44 +00:00
8c0e0a7a47 Removed unprecise unnecessary comment 2007-02-17 09:09:34 +00:00
c570e4868d Allowed forceful blanking of blank media in burn_disc_erase() 2007-02-17 08:56:41 +00:00
6ccd359c93 Another bug fix for revision 724 2007-02-17 08:52:07 +00:00
ca69e3f2ca Corrected CD TAO bug introduced with DVD bug fix 724 and CD SAO change 655 2007-02-16 11:21:01 +00:00
d272450a70 Repaired debugging message spoiled by uninitialized variable 2007-02-15 20:35:57 +00:00
a21c2a5138 Clarifications about current state of fillup 2007-02-15 20:23:49 +00:00
73273b1643 Corrected bug about open_ended filluped tracks 2007-02-15 20:19:07 +00:00
4df7aa0f3b Installed a guardian for predicted track end 2007-02-15 20:18:07 +00:00
dbe2ee41ae Took fill_up_media into respect with automatic write mode decisions 2007-02-15 20:16:22 +00:00
72a2ef9f96 New options --fill_up_media and --tell_media_space 2007-02-14 20:38:04 +00:00
e639cd5bbb Optional padding up to full media size when closing (incomplete yet) 2007-02-14 20:32:56 +00:00
3ec93316e0 Forgotten part of revision 718 2007-02-14 12:23:51 +00:00
ff6a9fc92b Handle eventual ridiculously high d->last_track_no 2007-02-14 12:20:32 +00:00
636f5278ad Set the advised write mode before inquiring media space 2007-02-14 12:05:26 +00:00
e10bfe2d37 Removed outdated ifdef 2007-02-14 12:03:47 +00:00
4da50dfad5 Applied new API function burn_disc_available_space() 2007-02-13 14:39:34 +00:00
dc281902a5 Removed or updated outdated restriction statements 2007-02-13 14:38:14 +00:00
4903bb9971 Mew API function burn_disc_available_space() 2007-02-13 14:37:25 +00:00
ba702bc9a8 Set a suitable page 05h after spc_probe_write_modes() 2007-02-13 11:55:09 +00:00
c7804d390f Made profile 0010h DVD-ROM suitable,full,not erasable. So it delivers a TOC. 2007-02-12 14:23:14 +00:00
9584adcc87 Updated list of keywords 2007-02-12 12:42:23 +00:00
7154d8cb91 Being exacting about on-the-fly and DVD-RW 2007-02-12 12:41:18 +00:00
36b4f2ded5 Documented changes and 0.3.2 release timestamp 2007-02-10 17:24:50 +00:00
1aed3f692c Added a comment about DVD-R 2007-02-10 17:23:49 +00:00
fdcb1a4014 Updated cdrskin tarball generator 2007-02-10 17:15:12 +00:00
384c47c710 Made number transition and activated development documentation 2007-02-10 17:13:41 +00:00
e8d210e15f Small corrections in documentation 2007-02-09 16:14:47 +00:00
6df2745652 Added special thanks towards Andy Polyakov 2007-02-09 16:01:45 +00:00
09b5bd2a1f Silenced compiler warning 2007-02-08 22:53:22 +00:00
67ce096aeb Mentioned DVD-R 2007-02-08 21:29:33 +00:00
cad7531058 New option --prodvd_cli_compatible 2007-02-08 21:09:10 +00:00
8dccb584b4 Finally made tests with DVD-R. They burn indeed like DVD-RW. 2007-02-08 14:10:05 +00:00
50eba7ee31 Updated documentation aspects 2007-02-07 17:49:52 +00:00
494693cc63 Made use of burn_write_opts_auto_write_type() 2007-02-07 16:37:25 +00:00
05623cffc4 New API function burn_write_opts_auto_write_type() 2007-02-07 16:30:42 +00:00
fed2af8c69 Next cdrskin-0.3.1 cycle 2007-02-06 21:22:41 +00:00
78f1cf835d Described DVD-R[W] DAO mode 2007-02-06 19:21:20 +00:00
d2283a5b4e Clarified CD and DVD peculiarities 2007-02-06 19:19:54 +00:00
8dd8ee4b9c Enabled fast blank for DVD-R[W] 2007-02-06 18:57:38 +00:00
6dfbbdf57f tao_to_sao_tsize= for DVD-R[W] DAO 2007-02-06 17:45:17 +00:00
d57166f64b Beautification of debugging messages 2007-02-06 17:08:15 +00:00
2799fe1b44 Implemented DVD-R[W] DAO as BURN_WRITE_SAO 2007-02-06 13:06:39 +00:00
330e0e2d5f Preparations for DVD-R[W] DAO 2007-02-05 13:28:57 +00:00
135d9d5016 New in API : struct burn_multi_caps and burn_disc_get_multi_caps() 2007-02-04 07:30:14 +00:00
db9f4a1d04 Mentioned DVD-RW multi-session 2007-02-03 18:46:42 +00:00
6b8ab52854 Improved classification and TOC of finalized DVD-R[W] media 2007-02-02 17:32:09 +00:00
4e93de2cd2 Make mmc_read_multi_session_c1 use TOC if available 2007-02-02 15:11:35 +00:00
a769f8aa87 Updated about DVD-R[W] blanking, multi-session info and TOC 2007-02-02 13:39:30 +00:00
e0a38be97b Some sed expressions for beautification 2007-02-02 13:37:34 +00:00
100de7b160 Mentioned DVD-RW multi-session in overview of features 2007-02-01 20:14:01 +00:00
9f7e5dd6dd Mentioned DVD-RW multi-session in overview of features 2007-02-01 20:06:03 +00:00
a9ac7ae480 Prepared next cdrskin-0.3.1 cycle 2007-02-01 19:53:07 +00:00
2e75680ed7 Prepared next cdrskin-0.3.1 cycle 2007-02-01 19:45:47 +00:00
c02dbe4eca Allowed blanking of DVD-RW which offer no Incremental Streaming 2007-02-01 19:15:06 +00:00
f3a08f6812 Reacted on justified compiler warning about unitialized sessions variable 2007-02-01 16:33:27 +00:00
e876f90e6c Obtain TOC from non-CD via 52h READ TRACK INFORMATION 2007-02-01 16:15:09 +00:00
dde52c1971 Provisorily obtain multi-session -C parameters (violates MMC specs but works) 2007-01-31 17:34:49 +00:00
f194aa8d5d Blank sequential DVD-RW, deformat overwriteable DVD-RW 2007-01-31 12:59:51 +00:00
b18b889750 Enabled Burnfree buffer underrun protection by default 2007-01-30 22:01:10 +00:00
0aafc18ac7 Added snapshot of emerging sequential DVD-R[W] cookbook 2007-01-30 20:16:55 +00:00
fa792f6a67 First successful multi-session write to a sequential DVD-RW 2007-01-30 19:16:35 +00:00
53a1e99675 Preparations for DVD-R[W] Sequential Recording 2007-01-30 17:54:39 +00:00
bda139f390 Experiments about list of features and profiles 2007-01-29 17:57:31 +00:00
ff7028d1fc Added a statement about blanking of DVD-RW 2007-01-29 17:52:36 +00:00
fa350edaae Initialized member set_size of burn_source within burn_null_source_new() 2007-01-26 17:33:29 +00:00
55e6c0ba82 Unified burn_file_source and burn_fd_source 2007-01-26 17:32:31 +00:00
f5a350f2cc Now offering cdrskin-0.3.0.pl01 for download 2007-01-26 11:09:07 +00:00
c079e09860 Enforce minimum track length with SAO 2007-01-25 18:52:50 +00:00
99f8e0eec5 Bug fix: DVD tracks of defined size >=2GB suffered 32-bit integer wraparound 2007-01-25 15:00:37 +00:00
3aec7fdeda Restored FreeBSD backend. 2007-01-24 12:44:22 +00:00
814d8cc83d Removed libisofs specific bits. 2007-01-24 12:41:25 +00:00
bc694d7457 Corrections of typos and text debris 2007-01-23 21:34:13 +00:00
66d70075ec Added SAO CD Cookbook 2007-01-23 10:35:51 +00:00
8f4dd8580c Banned mixed mode SAO (because broken in libburn and unclear in MMC) 2007-01-22 11:42:17 +00:00
7dd845a83b Clarification about TAO and mode page 05h per track 2007-01-21 19:13:27 +00:00
7b024f4a72 Comments learned from studying MMC-3 and MMC-5 for SAO CD cookbook 2007-01-21 19:10:37 +00:00
f1215f3295 Removed unnecessary after-grab loops 2007-01-21 19:09:07 +00:00
8e17806405 Changes with CD part. Especially explanation of TOC. 2007-01-20 14:26:32 +00:00
fb98c0390e Began to describe TAO multi-session CD writing 2007-01-19 20:54:11 +00:00
f418c49e63 Removed forgotten debug message printed to stderr 2007-01-19 11:05:18 +00:00
a34e872511 Kept DVD+RW from stopping BG formatting if it was not started at all 2007-01-18 21:18:03 +00:00
69a07aeec6 Made clarification about formatting state recognition 2007-01-18 21:16:13 +00:00
7addf0d5b5 More info about Current/Maximum Capacity Descriptor 2007-01-18 14:33:53 +00:00
a001f96b21 Wrote down what i learned from implementing support for overwriteable DVD 2007-01-18 13:55:28 +00:00
4a26017f2a Removed paragraph about obsoleted tao_to_sao_tsize= 2007-01-17 13:00:05 +00:00
0f48910aff Next cdrskin-0.3.1 cycle 2007-01-16 15:44:39 +00:00
c68efb346c Corrected typo 2007-01-16 15:18:34 +00:00
36f287d569 Corrected old libburn.pykix.org URL 2007-01-16 15:15:08 +00:00
4d7e28c09f Made version number transition to 0.3.1 2007-01-16 15:11:41 +00:00
c1342195f6 Updated cdrskin tarball generator 2007-01-16 15:07:09 +00:00
1fd003c1ec Next cdrskin-0.2.7 cycle 2007-01-15 15:30:41 +00:00
36d475eaf9 Updated about overwriteable DVD and pointer to dvd+rw-tools 2007-01-15 12:58:49 +00:00
55 changed files with 10510 additions and 1874 deletions

View File

@ -101,9 +101,9 @@ test_structest_CPPFLAGS = -Ilibburn
test_structest_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
test_structest_SOURCES = test/structest.c
## cdrskin construction site - ts A60816
## cdrskin construction site - ts A60816 - A70720
cdrskin_cdrskin_CPPFLAGS = -Ilibburn
cdrskin_cdrskin_CFLAGS = -DCdrskin_libburn_0_2_7
cdrskin_cdrskin_CFLAGS = -DCdrskin_libburn_0_3_8
cdrskin_cdrskin_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
cdrskin_cdrskin_SOURCES = cdrskin/cdrskin.c cdrskin/cdrfifo.c cdrskin/cdrfifo.h cdrskin/cdrskin_timestamp.h
##

49
README
View File

@ -54,7 +54,8 @@ See README file there.
Overview of libburnia.pykix.org
libburnia.pykix.org is an open-source software project for reading, mastering
and writing optical discs. For now this means only CD-R and CD-RW.
and writing optical discs.
For now this means only CD media and all single layer DVD media except DVD+R.
The project comprises of several more or less interdependent parts which
together strive to be a usable foundation for application development.
@ -66,10 +67,10 @@ we would need : login on a development machine resp. a live OS on CD or DVD,
advise from a system person about the equivalent of Linux sg or FreeBSD CAM,
volunteers for testing of realistic use cases.
We do have a workable code base for burning data CDs, though. The burn API is
quite comprehensively documented and can be used to build a presentable
application.
We do have a functional binary which emulates parts of cdrecord in order to
We have a workable code base for burning CD and most single layer DVD.
The burn API is quite comprehensively documented and can be used to build a
presentable application.
We have a functional binary which emulates parts of cdrecord in order to
prove that usability, and in order to allow you to explore libburnia's scope
by help of existing cdrecord frontends.
@ -78,20 +79,25 @@ The project components (list subject to growth, hopefully):
- libburn is the library by which preformatted data get onto optical media.
It uses either /dev/sgN (e.g. on kernel 2.4 with ide-scsi) or
/dev/hdX (e.g. on kernel 2.6).
libburn is the foundation of our cdrecord emulation.
libburn is the foundation of our cdrecord emulation. Its code is
independent of cdrecord. Its DVD capabilities are learned from
studying the code of dvd+rw-tools and MMC-5 specs. No code but only
the pure SCSI knowledge has been taken from dvd+rw-tools, though.
- libisofs is the library to pack up hard disk files and directories into a
ISO 9660 disk image. This may then be brought to CD via libburn.
ISO 9660 disk image. This may then be brought to media via libburn.
libisofs is to be the foundation of our upcoming mkisofs emulation.
- cdrskin is a limited cdrecord compatibility wrapper for libburn.
Cdrecord is a powerful GPL'ed burn program included in Joerg
Schilling's cdrtools. cdrskin strives to be a second source for
the services traditionally provided by cdrecord.
the services traditionally provided by cdrecord. Additionally it
provides libburn's DVD capabilities, where only -sao is compatible
with cdrecord.
cdrskin does not contain any bytes copied from cdrecord's sources.
Many bytes have been copied from the message output of cdrecord
runs, though.
See cdrskin/README for more.
See cdrskin/README and man cdrskin/cdrskin.1 for more.
- test is a collection of application gestures and examples given by the
authors of the library features. The main API example for libburn
@ -121,7 +127,7 @@ Project history as far as known to me:
It has meanwhile moved to use vanilla libburn.pykix.org , though.
Version 0.1.4 constitutes the first release of this kind.
- In Juli 2006 our team mate Mario Danic announced a revival of libburn
- In July 2006 our team mate Mario Danic announced a revival of libburn
which by about nearly everybody else was perceived as unfriendly fork.
Derek Foreman four days later posted a message which expressed his
discontent.
@ -178,13 +184,32 @@ Project history as far as known to me:
libburn, is now called libburnia. For the origin of this name, see
http://en.wikipedia.org/wiki/Liburnians .
- 16th January 2007 release of libburn-0.3.0 and cdrskin-0.3.0 . Now the scope
is widened to a first class of DVD media: overwriteable single layer types
DVD-RAM, DVD+RW, DVD-RW. This is not a cdrecord emulation but rather inspired
by dvd+rw-tools' "poor man" writing facility for this class of media.
Taking a bow towards Andy Polyakov.
- 11th February 2007 version 0.3.2 covers sequential DVD-RW and DVD-R with
multi-session and with DAO.
- 12th March 2007 version 0.3.4 supports DVD+R and thus covers all single layer
DVD media. Code for double layer DVD+/-R is implemented but awaits a tester
yet.
- 23th April 2007 version 0.3.6 follows the unanimous opinion of Linux kernel
people that one should not use /dev/sg on kernel 2.6.
- 31st July 2007 version 0.3.8 marks the first anniversary of libburn revival.
We look back on improved stability, a substantially extended list of media
and write modes, and better protection against typical user mishaps.
------------------------------------------------------------------------------
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
the Free Software Foundation. To be exact: version 2 of that License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of

View File

@ -26,12 +26,12 @@ following possible.
cdrskin. By Thomas Schmitt <scdbackup@gmx.net>
Integrated sub project of libburnia.pykix.org but also published via:
http://scdbackup.sourceforge.net/cdrskin_eng.html
http://scdbackup.sourceforge.net/cdrskin-0.2.7.tar.gz
http://scdbackup.sourceforge.net/cdrskin-0.3.8.tar.gz
Copyright (C) 2006-2007 Thomas Schmitt
------------------------------------------------------------------------------
On top of libburn there is implemented cdrskin 0.2.7, a limited cdrecord
On top of libburn there is implemented cdrskin 0.3.8, a limited cdrecord
compatibility wrapper which allows to use some libburn features from
the command line.
Interested users of cdrecord are invited to participate in the development
@ -59,16 +59,16 @@ systems, including 64 bit systems. (Further reports are welcome.)
Compilation, First Glimpse, Installation
Obtain cdrskin-0.2.7.tar.gz, take it to a directory of your choice and do:
Obtain cdrskin-0.3.8.tar.gz, take it to a directory of your choice and do:
tar xzf cdrskin-0.2.7.tar.gz
cd cdrskin-0.2.7
tar xzf cdrskin-0.3.8.tar.gz
cd cdrskin-0.3.8
Or obtain a libburnia.pykix.org SVN snapshot,
go into the toplevel directory of the snapshot (e.g. cd libburn_pykix ),
and execute the autotools script ./bootstrap . Use autools version >= 1.7 .
Within that toplevel directory of either cdrskin-0.2.7 or libburn then execute:
Within that toplevel directory of either cdrskin-0.3.8 or libburn then execute:
./configure
make
@ -126,16 +126,16 @@ The superuser should be able to see any usable drive and then set the
permissions as needed. If this hangs then there is a drive with
unexpected problems (locked, busy, broken, whatever). You might have to
guess the address of your (non-broken) burner by other means, then.
On Linux 2.4 this would be some /dev/sgN and on 2.6. some /dev/hdX.
On Linux 2.4 this would be some /dev/sgN and on 2.6. some /dev/srM or /dev/hdX.
The output of cdrskin --devices might look like
0 dev='/dev/sg0' rwrwr- : '_NEC' 'DVD_RW ND-4570A'
1 dev='/dev/sg1' rwrw-- : 'HL-DT-ST' 'DVDRAM GSA-4082B'
0 dev='/dev/sr0' rwrwr- : '_NEC' 'DVD_RW ND-4570A'
1 dev='/dev/sr1' rwrw-- : 'HL-DT-ST' 'DVDRAM GSA-4082B'
So full and insecure enabling of both for everybody would look like
chmod a+rw /dev/sg0 /dev/sg1
chmod a+rw /dev/sr0 /dev/sr1
I strongly discourage to run cdrskin with setuid root or via sudo !
It is not checked for the necessary degree of hacker safety.
@ -143,13 +143,16 @@ It is not checked for the necessary degree of hacker safety.
Usage examples
For options and recordable media classes see
man 1 cdrskin
Get an overview of cdrecord style addresses of available devices
cdrskin -scanbus
cdrskin dev=ATA -scanbus
cdrskin --devices
Adresses reported with dev=ATA need prefix "ATA:". Address examples:
dev=0,1,0 dev=ATA:1,0,0 dev=/dev/sg1 dev=/dev/hdc
dev=0,1,0 dev=ATA:1,0,0 dev=/dev/sg1 dev=/dev/hdc dev=/dev/sr0
See also "Drive Addressing" below.
Obtain some info about the drive
@ -158,21 +161,34 @@ Obtain some info about the drive
Obtain some info about the drive and the inserted media
cdrskin dev=0,1,0 -atip -v
Thoroughly blank a CD-RW
cdrskin -v dev=0,1,0 blank=all -eject
Blank CD-RW sufficiently for making it ready for overwrite
Make used CD-RW or used unformatted DVD-RW writeable again
cdrskin -v dev=0,1,0 blank=fast -eject
Burn image file my_image.iso to CD or DVD+-RW
Format DVD-RW to avoid need for blanking before re-use
cdrskin -v dev=0,1,0 blank=format_overwrite
De-format DVD-RW to make it capable of multi-session again
cdrskin -v dev=/dev/sr0 blank=deformat_sequential
Burn image file my_image.iso to media
cdrskin -v dev=0,1,0 speed=12 fs=8m driveropts=burnfree padsize=300k \
-eject my_image.iso
Burn a compressed afio archive to CD or DVD+-RW on-the-fly
Write multi-session to the same CD , DVD-R[W] or DVD+R
cdrskin dev=/dev/hdc padsize=300k -multi 1.iso
cdrskin dev=/dev/hdc padsize=300k -multi -tao 2.iso
cdrskin dev=/dev/hdc padsize=300k -multi -tao 3.iso
cdrskin dev=/dev/hdc padsize=300k -tao 4.iso
Get multi-session info for option -C of program mkisofs:
c_values=$(cdrskin dev=/dev/hdc -msinfo 2>/dev/null)
mkisofs ... -C "$c_values" ...
Burn a compressed afio archive to media on-the-fly
find . | afio -oZ - | cdrskin -v dev=0,1,0 fs=32m speed=8 -tao \
driveropts=burnfree padsize=300k -
Burn 6 audio tracks from files with different formats to CD.
Burn 6 audio tracks from files with different formats to CD (not to any DVD).
Anything except .wav or .au files has to be converted into raw format first.
See below "Audio CD" for specifications.
ogg123 -d raw -f track01.cd /path/to/track1.ogg
@ -194,7 +210,7 @@ cdrskin -scanbus (and hopefully as listed with cdrecord -scanbus) :
or a device file address as listed by --devices with an accessible drive :
export SCDBACKUP_SCSI_ADR="/dev/sg1"
export SCDBACKUP_SCSI_ADR="/dev/sr1"
Set usage of cdrskin with appropriate options rather than cdrecord :
@ -207,12 +223,11 @@ Run a backup :
Restrictions
The major restrictions are lifted now: audio, TAO, multi-session do work.
Many cdrecord options are still unsupported, though.
Many cdrecord options are still unsupported.
If you have use cases for them, please report your wishes and expectations.
DVD support is still immature and restricted to DVD+-RW for now.
DVD support is restricted to single layer DVD for now. Double layer media
are implemented but untested.
@ -227,11 +242,12 @@ Do not bother Joerg Schilling with any cdrskin problems.
cdrskin does not contain any bytes copied from cdrecord's sources. Many bytes
have been copied from the message output of cdrecord runs, though. I am
thankful to Joerg Schilling for every single one of them.
Actually i, Thomas Schmitt, am a devoted user of cdrecord via my project
scdbackup which still runs a bit better with cdrecord than with cdrskin. TAO.
I have the hope that Joerg feels more flattered than annoyed by cdrskin.
Many thanks to Andy Polyakov for his dvd+rw-tools
http://fy.chalmers.se/~appro/linux/DVD+RW/tools
which provide me with examples and pointers into MMC specs for DVD writing.
Drive Addressing
@ -256,8 +272,8 @@ the meaning of the components. A cdrecord-style address for cdrskin
can be interpreted in two different modes.
Standard mode tries to be compatible to original cdrecord. This should be true
with (emulated) SCSI where the /dev/sgN with is looked up with matching
scsibus,target,lun as given by the operating system.
with (emulated) SCSI where the device file /dev/s[rg]N with is looked up with
matching scsibus,target,lun as given by the operating system.
With dev=ATA: or dev=ATAPI: the translation to /dev/hdX is purely literal
but matches the cdrecord addresses on all systems tested so far:
X = 'a' + 2 * scsibus + target
@ -277,8 +293,8 @@ Component "scsibus" indicates the translation method. Defined busses are:
1 associated to device file /dev/sgN , target chooses N
2 associated to device file /dev/hdX , target 0='a', 1='b' ..., 25='z'
So "1,1,0" is /dev/sg1, "2,3,0" is /dev/hdd, "0,2,0" is libburn drive #2 at
some unspecified device file.
So "1,1,0" is /dev/sg1 (resp. its /dev/sr*), "2,3,0" is /dev/hdd,
"0,2,0" is libburn drive #2 at some unspecified device file.
This scheme shall help to keep cdrecord-style addresses stable and exchangeable
between users without excluding drives with unexpected device addresses.
The numbering on bus 0 is prone to arbitrary changes caused by changes in
@ -298,12 +314,12 @@ Old frontends which do not know dev=ATA or dev=ATAPI and which do ask their
To direct any remaining stubborn callers to the appropriate drives, cdrskin
allows to define device address aliases. Like
cdrskin dev_translation=+1,0,0+/dev/sg1 \
dev_translation=+ATA:1,0,0+/dev/sg1 \
cdrskin dev_translation=+1,0,0+/dev/sr1 \
dev_translation=+ATA:1,0,0+/dev/sr1 \
dev_translation=-"cd+dvd"-0,1,0 \
...
Any of the addresses dev=1,0,0, dev=ATA:1,0,0, dev=cd+dvd will be mapped to
/dev/sg1 resp. to 0,1,0.
/dev/sr1 resp. to 0,1,0.
The first character after "dev_translation=" defines the character which
separates the two parts of the translation pair. (Above: "+" and "-".)
@ -315,7 +331,7 @@ and to make them default in menu
A suitable setting for "cdrecord" in menu
Settings:Configure K3b...:Programs:User Parameters
would then probably be
-v dev_translation=+1,0,0+/dev/sg1
-v dev_translation=+1,0,0+/dev/sr1
You will learn from button "Show Debugging Output" after a failed burn run
what cdrecord command was used with what address "dev=...". This address "..."
will be the right one to replace "1,0,0" in above example.
@ -386,7 +402,7 @@ most recent session. For example put an ISO filesystem at address 1 GB:
cdrskin dev=/dev/sr0 -v fs=32m -eject speed=4 write_start_address=524288s -
The superuser may then do:
mount -t iso9660 -o ro,sbsector=524288 /dev/sr0 /mnt
Note: On my linux-2.4.21-215 mount works only with sbsector <= 337920 (660 MB).
Note: On my linux-2.4.21-215 mount works only with sbsector <= 337920 (660 MiB)
To extend a filesystem already existing at address 0
mkisofs -C 0,524288 -M /dev/sr0 ... | cdrskin dev=/dev/sr0 ...
Record the number 524288 for usage as first number with -C at the next
@ -399,36 +415,67 @@ into the format of the burned data. Be advised to use growisofs for the
task of maintaining extendable ISO-Filesystems on DVD+RW.
DVD-RW
DVD-RW and DVD-R
DVD-RW are usable if formatted to state "Restricted Overwrite" or if in state
"Sequential Recording". DVD-R are always in sequential state.
DVD-RW are usable if formatted to state "Restricted Overwrite". They then
behave much like DVD+RW. See above.
DVD-RW in state "Sequential" have first to be formatted by
cdrskin dev=... -v blank=format_overwrite
"Sequential" is the state of unused media and of media previously blanked
or written by cdrecord. dvd+rw-format -blank can also achieve this state.
(Command dvd+rw-format -force can achieve "Restricted Overwrite".)
The according cdrskin option is blank=deformat_sequential .
If "Incremental Streaming" is available, then sequential media are capable
of multi-session like CD-R[W]. (But not capable of -audio recording.)
This means they need option -multi to stay appendable, need to be blanked
to be writeable from start, return useable info with -toc and -msinfo,
eventually perform appending automatically.
Without "Incremental Streaming" offered by the drive, only write mode DAO is
available with sequential DVD-R[W]. It only works with blank media, allows only
one single track, no -multi, and demands a fixely predicted track size.
(growisofs uses it with DVD-R[W] if option -dvd-compat is given.)
Overwriteable DVD-RW behave much like DVD+RW. "Restricted" refers only to the
granularity of random access and block size which have always to be aligned to
full 32 kB. Sequential DVD-RW are converted into overwriteable DVD-RW by
cdrskin dev=... -v blank=format_overwrite
(Command dvd+rw-format -force can achieve "Restricted Overwrite", too.)
Formatting or first use of freshly formatted DVD-RW can produce unusual noises
from the drive and last several minutes. Depending on mutual compatibility of
drive and media, formatting can yield unusable media. It seems that those die
too on blanking by cdrecord or dvd+rw-format. Perils of DVD-RW, i fear.
too on blanking by cdrecord, dvd+rw-format or cdrskin. Perils of DVD-RW.
There are three formatting variants with cdrskin currently:
There are three DVD-RW formatting variants with cdrskin currently:
blank=format_overwrite uses "DVD-RW Quick" formatting (MMC-type 15h)
and writes a first session of 128 MB. This leads to media which are expandable
and writes a first session of 128 MiB. This leads to media which are expandable
and random addressable by cdrskin.
blank=format_overwrite_quickest uses "DVD-RW Quick" formatting (type 15h) too,
but leaves the media in "intermediate" state. In the first session of writing
one may only write sequentially to such a DVD. After that, it gets random
addressable by cdrskin.
addressable by cdrskin. DVD-ROM drives might show ill behavior with them.
blank=format_overwrite_full uses preferrably "Full Format" (type 00h).
This formatting lasts as long as writing a full DVD. It includes writing of
lead-out which is said to be good for DVD ROM compatibility.
De-formatting options are available to make overwriteable DVD-RW sequential:
blank=deformat_sequential performs thorough blanking of all states of DVD-RW.
blank=all and blank=fast perform the same thorough blanking, but refuse to do
this with overwriteable DVD-RW, thus preserving their formatting. The specs
allow minimal blanking but the resulting media on my drives offer no
Incremental Streaming afterwards. So blank=fast will do full blanking.
blank=deformat_sequential_quickest is faster but might yield DAO-only media.
DVD+R
From the view of cdrskin they behave much like DVD-R. Each track gets wrapped
into an own session, though.
------------------------------------------------------------------------------
Special compilation variations

View File

@ -20,27 +20,28 @@ set -x
# The script is to be run in the directory above the toplevel
# directory of libburn resp. cdrskin development.
#
# libburn version used: http://libburn.pykix.org
# The top level directory in the SVN snapshot is named
intermediate="./libburn_pykix"
# libburn source used: http://libburnia.pykix.org
# Downloaded by:
# $ svn co http://libburn-svn.pykix.org/trunk libburn_pykix
# $ svn co http://libburnia-svn.pykix.org/libburn/tags/... $intermediate
# packed up in a tarball just to save it from inadverted changes by
# $ tar czf libburn_svn.tgz libburn_pykix
original="./libburn_svn.tgz"
# $ tar czf libburn_svn.tgz $intermediate
original="./libburn_svn_release.tgz"
# Historic moments:
# original="./libburn_svn_A60815.tgz"
# original="./libburn_cdrskin_A60819.tgz"
# The top level directory in that snapshot is named
intermediate="./libburn_pykix"
# My changes are in libburn-0.2.3.ts.develop , mainly in ./cdrskin
# My changes are in $changes , mainly in $changes/cdrskin
changes="./libburn-release"
changes="./libburn-0.2.3.ts.develop"
skin_release="0.2.6"
patch_level=".pl01"
skin_release="0.3.8"
patch_level=".pl00"
skin_rev="$skin_release""$patch_level"
# The result directory and the name of the result tarballs
target="./cdrskin-${skin_release}"
cdrskin_tarball="./cdrskin-${skin_rev}.tar.gz"
@ -54,6 +55,9 @@ compile_cmd="./cdrskin/compile_cdrskin.sh"
compile_static_opts="-static"
compile_result="cdrskin/cdrskin"
man_to_html_cmd="./cdrskin/convert_man_to_html.sh"
man_page_html="cdrskin/man_1_cdrskin.html"
bintarget_dynamic="cdrskin_${skin_rev}-x86-suse9_0"
bintarget_static="$bintarget_dynamic"-static
@ -110,7 +114,8 @@ then
fi
cp -a "$cdrskin_dir" "$cdrskin_target"
# Remove copied binaries
# Remove copied vim.swp and binaries
rm "$cdrskin_target"/.*.swp
rm "$cdrskin_target"/*.o
rm "$cdrskin_target"/cdrfifo
rm "$cdrskin_target"/cdrskin
@ -122,6 +127,8 @@ do
rm "$cdrskin_target"/cdrskin_"$i"
fi
done
# Remove eventual SVN stuff from cdrskin directory
for i in .deps .dirstamp .libs
do
if test -e "$cdrskin_target"/"$i"
@ -130,6 +137,23 @@ do
fi
done
# Remove GIFs of cdrskin_eng.html
rm "$cdrskin_target"/doener_*.gif "$cdrskin_target"/doener_*.png
# Remove automatically generated HTML man page
rm "$cdrskin_target"/man_1_cdrskin.html
# Remove all add_ts_changes_to_libburn besides this one
for i in "$cdrskin_target"/add_ts_changes_to_libburn*
do
if test $(basename "$0") = $(basename "$i")
then
dummy=dummy
else
rm $i
fi
done
# Remove unwanted SVN stuff (TODO: avoid downloading it)
for i in "$target"/.svn "$target"/*/.svn
do
@ -144,12 +168,6 @@ do
fi
done
## No more : Add own libburn-README in toplevel
# cp -a "$changes"/README "$target"
## No more : Add modified Makefile.am
# cp -a "$changes"/Makefile.am "$target"
# Make SVN state tarball for the libburn team
tar czf "$cdrskin_tarball_svn" "$target"
@ -175,22 +193,36 @@ do
fi
done
# Repair non-portable shell code output of ./bootstrap
(
cd "$compile_dir" || exit 1
sed -e 's/^for ac_header in$/test -z 1 \&\& for ac_header in dummy/' \
< ./configure > ./configure-repaired
if test "$?" = 0
then
echo "$0: Empty 'for ac_header in' found in configure." >&2
fi
mv ./configure-repaired ./configure
chmod a+rx,go-w,u+w ./configure
)
# Pack it up to the new libburn+cdrskin-tarball
tar czf "$cdrskin_tarball" "$target"
# Produce a static and a dynamic binary
# Produce a static and a dynamic binary, and a HTML man page
(
cd "$compile_dir" || exit 1
./configure
make
$compile_cmd -do_strip
"$compile_cmd" -O2 -do_strip
cp "$compile_result" "../$bintarget_dynamic"
if test -n "$compile_static_opts"
then
$compile_cmd $compile_static_opts -do_strip
"$compile_cmd" $compile_static_opts -O2 -do_strip
cp "$compile_result" "../$bintarget_static"
fi
"$man_to_html_cmd"
mv "$man_page_html" ..
)
# Remove the build area
@ -203,4 +235,5 @@ rm -rf "$target"
ls -l "$cdrskin_tarball"
ls -l "$bintarget_dynamic"
ls -l "$bintarget_static"
ls -l $(basename "$man_page_html")

View File

@ -20,26 +20,30 @@ set -x
# The script is to be run in the directory above the toplevel
# directory of libburn resp. cdrskin development.
#
# libburn version used: http://libburn.pykix.org
# The top level directory in the SVN snapshot is named
intermediate="./libburn_pykix"
# libburn source used: http://libburnia.pykix.org
# Downloaded by:
# $ svn co http://libburn-svn.pykix.org/libburn/trunk libburn_pykix
# $ svn co http://libburnia-svn.pykix.org/libburn/tags/... $intermediate
# packed up in a tarball just to save it from inadverted changes by
# $ tar czf libburn_svn.tgz libburn_pykix
# $ tar czf libburn_svn.tgz $intermediate
original="./libburn_svn.tgz"
# Historic moments:
# original="./libburn_svn_A60815.tgz"
# original="./libburn_cdrskin_A60819.tgz"
# The top level directory in that snapshot is named
intermediate="./libburn_pykix"
# My changes are in libburn-0.2.3.ts.develop , mainly in ./cdrskin
# My changes are in $changes , mainly in $changes/cdrskin
changes="./libburn-develop"
changes="./libburn-0.2.3.ts.develop"
skin_rev="0.2.7"
skin_release="0.3.9"
patch_level=""
skin_rev="$skin_release""$patch_level"
# The result directory and the name of the result tarballs
target="./cdrskin-${skin_rev}"
target="./cdrskin-${skin_release}"
cdrskin_tarball="./cdrskin-${skin_rev}.tar.gz"
cdrskin_tarball_svn="./cdrskin-${skin_rev}.svn.tar.gz"
@ -110,7 +114,8 @@ then
fi
cp -a "$cdrskin_dir" "$cdrskin_target"
# Remove copied binaries
# Remove copied vim.swp and binaries
rm "$cdrskin_target"/.*.swp
rm "$cdrskin_target"/*.o
rm "$cdrskin_target"/cdrfifo
rm "$cdrskin_target"/cdrskin
@ -123,10 +128,7 @@ do
fi
done
# Remove automatically generated HTML man page
rm "$cdrskin_target"/man_1_cdrskin.html
# Remove eventual SVN stuff from cdrskin driectory
# Remove eventual SVN stuff from cdrskin directory
for i in .deps .dirstamp .libs
do
if test -e "$cdrskin_target"/"$i"
@ -136,7 +138,21 @@ do
done
# Remove GIFs of cdrskin_eng.html
rm "$cdrskin_target"/doener_*.gif
rm "$cdrskin_target"/doener_*.gif "$cdrskin_target"/doener_*.png
# Remove automatically generated HTML man page
rm "$cdrskin_target"/man_1_cdrskin.html
# Remove all add_ts_changes_to_libburn besides this one
for i in "$cdrskin_target"/add_ts_changes_to_libburn*
do
if test $(basename "$0") = $(basename "$i")
then
dummy=dummy
else
rm $i
fi
done
# Remove unwanted SVN stuff (TODO: avoid downloading it)
for i in "$target"/.svn "$target"/*/.svn
@ -152,12 +168,6 @@ do
fi
done
## No more : Add own libburn-README in toplevel
# cp -a "$changes"/README "$target"
## No more : Add modified Makefile.am
# cp -a "$changes"/Makefile.am "$target"
# Make SVN state tarball for the libburn team
tar czf "$cdrskin_tarball_svn" "$target"
@ -183,6 +193,19 @@ do
fi
done
# Repair non-portable shell code output of ./bootstrap
(
cd "$compile_dir" || exit 1
sed -e 's/^for ac_header in$/test -z 1 \&\& for ac_header in dummy/' \
< ./configure > ./configure-repaired
if test "$?" = 0
then
echo "$0: Empty 'for ac_header in' found in configure." >&2
fi
mv ./configure-repaired ./configure
chmod a+rx,go-w,u+w ./configure
)
# Pack it up to the new libburn+cdrskin-tarball
tar czf "$cdrskin_tarball" "$target"
@ -192,11 +215,11 @@ tar czf "$cdrskin_tarball" "$target"
cd "$compile_dir" || exit 1
./configure
make
"$compile_cmd" -do_strip
"$compile_cmd" -libburn_svn -O2 -do_strip
cp "$compile_result" "../$bintarget_dynamic"
if test -n "$compile_static_opts"
then
"$compile_cmd" $compile_static_opts -do_strip
"$compile_cmd" $compile_static_opts -libburn_svn -O2 -do_strip
cp "$compile_result" "../$bintarget_static"
fi
"$man_to_html_cmd"

View File

@ -38,7 +38,9 @@
#define Cdrfifo_ffd_maX 100
/* 1= enable , 0= disable status messages to stderr */
/* 1= enable , 0= disable status messages to stderr
2= report each
*/
static int Cdrfifo_debuG= 0;
@ -75,6 +77,8 @@ struct CdrfifO {
double empty_counter;
double full_counter;
/* eventual ISO-9660 image size obtained from first 64k of input */
double iso_fs_size;
/* (sequential) fd chaining */
/* fds: 0=source, 1=dest */
@ -82,6 +86,8 @@ struct CdrfifO {
/* index of first byte in buffer which does not belong to predecessor fd */
int follow_up_eop[Cdrfifo_ffd_maX];
/* if follow_up_eop[i]==buffer_size : read_idx was 0 when this was set */
int follow_up_was_full_buffer[Cdrfifo_ffd_maX];
/* index of first byte in buffer which belongs to [this] fd pair */
int follow_up_sod[Cdrfifo_ffd_maX];
@ -99,6 +105,9 @@ struct CdrfifO {
/* (simultaneous) peer chaining */
struct CdrfifO *next;
struct CdrfifO *prev;
/* rank in peer chain */
int chain_idx;
};
@ -152,14 +161,17 @@ int Cdrfifo_new(struct CdrfifO **ff, int source_fd, int dest_fd,
o->get_counter= 0.0;
o->empty_counter= 0.0;
o->full_counter= 0.0;
o->iso_fs_size= -1.0;
for(i= 0; i<Cdrfifo_ffd_maX; i++) {
o->follow_up_fds[i][0]= o->follow_up_fds[i][1]= -1;
o->follow_up_eop[i]= o->follow_up_sod[i]= -1;
o->follow_up_was_full_buffer[i]= 0;
o->follow_up_in_limits[i]= -1.0;
}
o->follow_up_fd_counter= 0;
o->follow_up_fd_idx= -1;
o->next= o->prev= NULL;
o->chain_idx= 0;
o->buffer= TSOB_FELD(char,buffer_size);
if(o->buffer==NULL)
goto failed;
@ -299,10 +311,16 @@ int Cdrfifo_attach_follow_up_fds(struct CdrfifO *o, int source_fd, int dest_fd,
*/
int Cdrfifo_attach_peer(struct CdrfifO *o, struct CdrfifO *next, int flag)
{
int idx;
struct CdrfifO *s;
for(s= o;s->prev!=NULL;s= s->prev); /* determine start of o-chain */
for(;o->next!=NULL;o= o->next); /* determine end of o-chain */
for(;next->prev!=NULL;next= next->prev); /* determine start of next-chain */
next->prev= o;
o->next= next;
for(idx= 0;s!=NULL;s= s->next)
s->chain_idx= idx++;
return(1);
}
@ -375,6 +393,13 @@ int Cdrfifo_get_min_fill(struct CdrfifO *o, int *total_min_fill,
}
int Cdrfifo_get_iso_fs_size(struct CdrfifO *o, double *size_in_bytes, int flag)
{
*size_in_bytes= o->iso_fs_size;
return(o->iso_fs_size>=2048);
}
/** Get counters which are mentioned by cdrecord at the end of burning.
It still has to be examined wether they mean what i believe they do.
*/
@ -383,7 +408,7 @@ int Cdrfifo_get_cdr_counters(struct CdrfifO *o,
double *empty_counter, double *full_counter,
int flag)
{
*put_counter= o->put_counter;;
*put_counter= o->put_counter;
*get_counter= o->get_counter;
*empty_counter= o->empty_counter;
*full_counter= o->full_counter;
@ -408,10 +433,26 @@ int Cdrfifo_eop_adjust(struct CdrfifO *o,int *buffer_fill, int *eop_idx,
for(i=0; i<=o->follow_up_fd_idx; i++) {
if(o->follow_up_eop[i]>=0 && o->follow_up_eop[i]>=o->read_idx) {
eop_is_near= 1;
valid_fill= o->follow_up_eop[i]-o->read_idx;
if(o->follow_up_eop[i]<o->buffer_size || o->read_idx>0) {
valid_fill= o->follow_up_eop[i]-o->read_idx;
o->follow_up_was_full_buffer[i]= 0;
} else {
/*
If an input fd change hit exactly the buffer end then follow_up_eop
points to buffer_size and not to 0. So it is time to switch output
pipes unless this is immediately after follow_up_eop was set and
read_idx was 0 (... if this is possible at all while write_idx is 0).
follow_up_was_full_buffer was set in this case and gets invalid as
soon as a non-0 read_idx is detected (see above).
*/
if(o->follow_up_was_full_buffer[i])
valid_fill= o->buffer_size;
else
valid_fill= 0; /* the current pipe is completely served */
}
if(valid_fill==0)
*eop_idx= i;
else if(valid_fill<=o->chunk_size)
else if(valid_fill<o->chunk_size)
eop_is_near= 2; /* for debugging. to carry a break point */
break;
}
@ -436,7 +477,7 @@ static int Cdrfifo_setup_try(struct CdrfifO *o, struct timeval start_tv,
*/
{
int buffer_space,buffer_fill,eop_reached= -1,eop_is_near= 0,was_closed;
int fd_buffer_fill;
int fd_buffer_fill, eop_reached_counter= 0;
struct timeval current_tv;
struct timezone tz;
double diff_time,diff_counter,limit,min_wait_time;
@ -465,21 +506,26 @@ setup_try:;
if(eop_reached>=0) { /* switch to next output fd */
o->dest_fd= o->follow_up_fds[eop_reached][1];
if(Cdrfifo_debuG)
fprintf(stderr,"\ncdrfifo %d: new fifo destination fd : %d\n",
o->chain_idx,o->dest_fd);
o->read_idx= o->follow_up_sod[eop_reached];
o->follow_up_eop[eop_reached]= -1;
eop_is_near= 0;
eop_reached= -1;
eop_reached_counter= 0;
goto setup_try;
} else {
/* work is really done */
if((!was_closed) && ((flag&1)||Cdrfifo_debuG))
fprintf(stderr,
"\ncdrfifo_debug: w=%d r=%d | b=%d s=%d | i=%.f o=%.f (done)\n",
o->write_idx,o->read_idx,buffer_fill,buffer_space,
"\ncdrfifo %d: w=%d r=%d | b=%d s=%d | i=%.f o=%.f (done)\n",
o->chain_idx,o->write_idx,o->read_idx,buffer_fill,buffer_space,
o->in_counter,o->out_counter);
return(2);
}
}
} else if(eop_reached>=0)
eop_reached_counter++;
if(o->interval_counter>0) {
if(o->total_min_fill>buffer_fill && o->source_fd>=0)
o->total_min_fill= buffer_fill;
@ -581,7 +627,8 @@ return: <0 = error , 0 = idle , 1 = did some work
if(ret==-1) {
/* >>> handle broken pipe */;
fprintf(stderr,"\ncdrfifo: on write: errno=%d , \"%s\"\n",errno,
fprintf(stderr,"\ncdrfifo %d: on write: errno=%d , \"%s\"\n",
o->chain_idx,errno,
errno==0?"-no error code available-":strerror(errno));
if(!(flag&4))
@ -613,22 +660,31 @@ after_write:;
if(ret==-1) {
/* >>> handle input error */;
fprintf(stderr,"\ncdrfifo: on read: errno=%d , \"%s\"\n",errno,
fprintf(stderr,"\ncdrfifo %d: on read: errno=%d , \"%s\"\n",
o->chain_idx,errno,
errno==0?"-no error code available-":strerror(errno));
o->source_fd= -1;
} else if(ret==0) { /* eof */
/* activate eventual follow-up source fd */
if(Cdrfifo_debuG || (flag&1))
fprintf(stderr,"\ncdrfifo: on read(%d,buffer,%d): eof\n",
o->source_fd,can_read);
fprintf(stderr,"\ncdrfifo %d: on read(%d,buffer,%d): eof\n",
o->chain_idx,o->source_fd,can_read);
if(o->follow_up_fd_idx+1 < o->follow_up_fd_counter) {
idx= ++(o->follow_up_fd_idx);
o->source_fd= o->follow_up_fds[idx][0];
/* End-Of-Previous */
if(o->write_idx==0)
if(o->write_idx==0) {
o->follow_up_eop[idx]= o->buffer_size;
else
/* A70304 : can this happen ? */
o->follow_up_was_full_buffer[idx]= (o->read_idx==0);
if(Cdrfifo_debuG || (flag&1))
fprintf(stderr,"\ncdrfifo %d: write_idx 0 on eop: read_idx= %d\n",
o->chain_idx,o->read_idx);
} else
o->follow_up_eop[idx]= o->write_idx;
/* Start-Of-Data . Try to start at next full chunk */
sod= o->write_idx;
@ -644,7 +700,8 @@ after_write:;
o->fd_in_counter= 0;
o->fd_in_limit= o->follow_up_in_limits[idx];
if(Cdrfifo_debuG || (flag&1))
fprintf(stderr,"\ncdrfio: new fifo source fd : %d\n",o->source_fd);
fprintf(stderr,"\ncdrfifo %d: new fifo source fd : %d\n",
o->chain_idx,o->source_fd);
} else {
o->source_fd= -1;
}
@ -777,13 +834,13 @@ ex:;
} else
elapsed= wait_usec;
if(elapsed>=wait_usec) {
if((flag&1)||Cdrfifo_debuG) {
if((flag&1)||Cdrfifo_debuG>=2) {
fprintf(stderr,"\n");
for(ff= o; ff!=NULL; ff= ff->next) {
buffer_space= Cdrfifo_tell_buffer_space(ff,0);
fprintf(stderr,
"cdrfifo_debug: w=%d r=%d | b=%d s=%d | i=%.f o=%.f\n",
ff->write_idx,ff->read_idx,
"cdrfifo %d: w=%d r=%d | b=%d s=%d | i=%.f o=%.f\n",
ff->chain_idx,ff->write_idx,ff->read_idx,
ff->buffer_size-buffer_space,buffer_space,
ff->in_counter,ff->out_counter);
}
@ -823,6 +880,24 @@ int Cdrfifo_fill(struct CdrfifO *o, int size, int flag)
if(ret==2)
break;
}
#ifndef Cdrfifo_standalonE
{ int Scan_for_iso_size(unsigned char data[2048], double *size_in_bytes,
int flag);
int i;
double size;
/* try to obtain an ISO-9660 file system size */
for(i= 0; i<32*2048 && i+2048<=fill; i+=2048) {
ret= Scan_for_iso_size((unsigned char *) (o->buffer+i), &size, 0);
if(ret<=0)
continue;
o->iso_fs_size= size;
break;
}
}
#endif
o->total_min_fill= fill;
o->interval_min_fill= fill;
return(1);
@ -875,6 +950,76 @@ double Scanf_io_size(char *text, int flag)
}
/* This is a hardcoded test mock-up for two simultaneous fifos of which the
one runs with block size 2048 and feeds the other which runs with 2352.
Both fifos have the same number of follow_up pipes (tracks) which shall
be connected 1-to-1.
*/
int Test_mixed_bs(char **paths, int path_count,
int fs_size, double speed_limit, double interval, int flag)
/*
bit0= debugging verbousity
*/
{
int fd_in[100],fd_out[100],ret,pipe_fds[100][2],real_out[100];
int i,iv,stall_counter= 0,cycle_counter= 0.0;
char buf[10240], target_path[80];
double in_counter, out_counter, prev_in= -1.0, prev_out= -1.0;
struct CdrfifO *ff_in= NULL, *ff_out= NULL;
if(path_count<1)
return(2);
Cdrfifo_new(&ff_in,fd_in[0],fd_out[0],2048,fs_size,0);
for(i= 0; i<path_count; i++) {
fd_in[2*i]= open(paths[i],O_RDONLY);
if(fd_in[2*i]==-1)
return(0);
if(pipe(pipe_fds[2*i])==-1)
return(-1);
fd_out[2*i]= pipe_fds[2*i][1];
if(i==0)
ret= Cdrfifo_new(&ff_in,fd_in[2*i],fd_out[2*i],2048,fs_size,0);
else
ret= Cdrfifo_attach_follow_up_fds(ff_in,fd_in[2*i],fd_out[2*i],0);
if(ret<=0)
return(ret);
fd_in[2*i+1]= pipe_fds[2*i][0];
sprintf(target_path,"/dvdbuffer/fifo_mixed_bs_test_%d",i);
fd_out[2*i+1]= open(target_path,O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
if(i==0)
ret= Cdrfifo_new(&ff_out,fd_in[2*i+1],fd_out[2*i+1],2352,fs_size,0);
else
ret= Cdrfifo_attach_follow_up_fds(ff_out,fd_in[2*i+1],fd_out[2*i+1],0);
if(ret<=0)
return(ret);
fprintf(stderr,"test_mixed_bs: %d : %2d fifo %2d pipe %2d fifo %2d : %s\n",
i, fd_in[2*i],fd_out[2*i],fd_in[2*i+1],fd_out[2*i+1], target_path);
}
Cdrfifo_attach_peer(ff_in,ff_out,0);
/* Let the fifos work */
iv= interval*1e6;
while(1) {
ret= Cdrfifo_try_to_work(ff_in,iv,NULL,NULL,flag&1);
if(ret<0 || ret==2) { /* <0 = error , 2 = work is done */
fprintf(stderr,"\ncdrfifo %d: fifo ended work with ret=%d\n",
ff_in->chain_idx,ret);
if(ret<0)
return(-7);
break;
}
cycle_counter++;
Cdrfifo_get_counters(ff_in, &in_counter, &out_counter, 0);
if(prev_in == in_counter && prev_out == out_counter)
stall_counter++;
prev_in= in_counter;
prev_out= out_counter;
}
return(1);
}
/* This is a hardcoded test mock-up for two simultaneous fifos of which the
first one simulates the cdrskin fifo feeding libburn and the second one
simulates libburn and the burner at given speed. Both have two fd pairs
@ -933,7 +1078,8 @@ int Test_multi(int fs_size, double speed_limit, double interval, int flag)
while(1) {
ret= Cdrfifo_try_to_work(ff1,iv,NULL,NULL,flag&1);
if(ret<0 || ret==2) { /* <0 = error , 2 = work is done */
fprintf(stderr,"\ncdrfifo: fifo ended work with ret=%d\n",ret);
fprintf(stderr,"\ncdrfifo %d: fifo ended work with ret=%d\n",
ff1->chain_idx,ret);
if(ret<0)
return(-7);
break;
@ -992,6 +1138,13 @@ int main(int argc, char **argv)
} else if(strncmp(argv[i],"vb=",3)==0) {
sscanf(argv[i]+3,"%d",&verbous);
} else if(strcmp(argv[i],"-mixed_bs_test")==0) {
ret= Test_mixed_bs(argv+i+1,argc-i-1,
(int) fs_value,speed_limit,interval,(verbous>=2));
fprintf(stderr,"Test_mixed_bs(): ret= %d\n",ret);
exit(ret<0);
} else if(strcmp(argv[i],"-multi_test")==0) {
if(speed_limit==0.0)
@ -1035,7 +1188,7 @@ int main(int argc, char **argv)
if(speed_limit!=0.0)
Cdrfifo_set_speed_limit(ff,speed_limit,0);
if(fill_buffer) {
ret= Cdrfifo_fill(ff,0);
ret= Cdrfifo_fill(ff,0,0);
if(ret<=0) {
fprintf(stderr,
"cdrfifo: FATAL : initial filling of fifo buffer failed\n");

View File

@ -117,6 +117,11 @@ int Cdrfifo_get_cdr_counters(struct CdrfifO *o,
double *empty_counter, double *full_counter,
int flag);
/** Inquire the eventually detected size of an eventual ISO-9660 file system
@return 0=no ISO resp. size detected, 1=size_in_bytes is valid
*/
int Cdrfifo_get_iso_fs_size(struct CdrfifO *o, double *size_in_bytes,int flag);
/** Check for pending data at the fifo's source file descriptor and wether the
fifo is ready to take them. Simultaneously check the buffer for existing

View File

@ -2,7 +2,7 @@
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
.TH CDRSKIN 1 "January 12, 2007"
.TH CDRSKIN 1 "July 19, 2007"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
@ -16,7 +16,7 @@
.\" .sp <n> insert n+1 empty lines
.\" for manpage-specific macros, see man(7)
.SH NAME
cdrskin \- burns preformatted data to CD-R, CD-RW, DVD+/-RW, DVD-RAM
cdrskin \- burns preformatted data to CD-R[W], DVD-R[W], DVD+R[W], DVD-RAM
via libburn.
.SH SYNOPSIS
.B cdrskin
@ -29,12 +29,12 @@ via libburn.
.\" respectively.
.PP
\fBcdrskin\fP is a program that provides some of cdrecord's options
in a compatible way for CD media. With DVD it has its own ways for now.
in a compatible way for CD media. With DVD it has its own ways.
You do not need to be superuser for its daily usage.
.PP
.B Overview of features:
.br
Blanking of CD-RW.
Blanking of CD-RW and DVD-RW.
.br
Burning of data or audio tracks to CD,
.br
@ -42,14 +42,32 @@ either in versatile Track at Once mode (TAO)
.br
or in Session at Once mode for seamless tracks.
.br
Multi session on CD (follow-up sessions in TAO only).
Multi session on CD (follow-up sessions in TAO only)
.br
or on DVD-R[W] (in Incremental mode) or on DVD+R.
.br
Single session on DVD-RW or DVD-R (Disk-at-once)
.br
or on overwriteable DVD+RW, DVD-RW, DVD-RAM.
.br
Bus scan, burnfree, speed options, retrieving media info, padding, fifo.
.br
Burning of a single data track to DVD+RW, DVD-RW or DVD-RAM.
.br
See section EXAMPLES at the end of this text.
.PP
.B General information paragraphs:
.br
Track recording model
.br
Write mode selection
.br
Recordable CD Media
.br
Sequentially Recordable DVD Media
.br
Overwriteable DVD Media
.br
Drive preparation and addressing
.PP
.B Track recording model:
.br
The input-output entities which get processed are called tracks.
@ -64,7 +82,7 @@ More than one track can be burned by a single run of cdrskin.
In the terms of the MMC standard all tracks written by the same run constitute
a \fBsession\fP.
.br
CDs can be kept appendable so that further tracks can
Some media types can be kept appendable so that further tracks can
be written to them in subsequent runs of cdrskin (see option -multi).
Info about the addresses of burned tracks is kept in a table of
content (TOC) on media and can be retrieved via cdrskin option -toc.
@ -72,7 +90,7 @@ These informations are also used by the operating systems' CD-ROM read drivers.
.PP
In general there are two types of tracks: data and audio. They differ in
sector size, throughput and readability via the systems' CD-ROM drivers
resp. by music CD players.
resp. by music CD players. With DVD there is only type data.
.br
If not explicitely option -audio is given, then any track is burned as type
data, unless the track source is a file with suffix ".wav" or ".au" and has a
@ -92,11 +110,33 @@ have been developed for magnetic tapes. Only formats which mark a detectable
end-of-archive in their data are suitable, though. Well tested are
the archivers afio and star. Not suitable seems GNU tar.
.PP
.B Write mode selection:
.br
If none of the options -dao, -tao or -sao is given then the program will
try to choose a write mode which matches the defined recording job,
the capabilities of the drive and the state of the present media.
.br
So the mentioning of write modes in the following paragraphs and in the
examples is not so much a demand that the user shall choose one explicitely,
but rather an illustration of what to expect with particular media types.
.PP
.B Recordable CD Media:
.br
CD-R can be initially written only once and eventually extended until they
get closed (or are spoiled because they are overly full). After that they are
read-only.
read-only. Closing is done automatically unless option
.B -multi
is given which keeps the media appendable.
.br
There are two write modes,
.B -tao
and
.B -sao .
.br
-tao allows to use track source of unpredictable length (like stdin) and allows
to write further sessions to appendable media. -sao produces audio sessions
with seamless tracks but needs predicted track sizes and cannot append sessions
to media.
.br
CD-RW media can be blanked to make them re-usable for another
round of overwriting. Usually
@ -106,24 +146,71 @@ Blanking damages the previous content but does not
make it completely unreadable. It is no effective privacy precaution.
Multiple cycles of blanking and overwriting with random numbers might be.
.PP
.B Recordable DVD Media:
.B Sequentially Recordable DVD Media:
.br
Currently only types DVD+RW, DVD-RW and DVD-RAM can be burned via cdrskin.
Currently DVD-RW, DVD-R and DVD+R can be used for the Sequential recording
model.
.br
DVD-RW must be in state "Sequential Recording".
The media must be either blank or appendable.
Newly purchased DVD-RW and DVD-R media are in this state.
Used DVD-RW get into blank sequential state by option
.B blank=deformat_sequential .
.br
With DVD-R[W] two write modes may be available:
.br
Mode DAO has many restrictions. It does not work with
appendable media, allows no -multi and only a single track. The size of the
track needs to be known in advance. So either its source has to be a disk file
of recognizable size or the size has to be announced explicitely by options
.B tsize=
or
.B tao_to_sao_tsize= .
.br
DAO is the only mode for media which do not offer feature 21h Incremental
Streaming. DAO may also be selected explicitely by option
.B -sao .
Program growisofs uses DAO on sequential DVD-R[W] media for maximum
DVD-ROM/-Video compatibility.
.br
The other mode, Incremental Streaming, is the default write mode if
it is available and if the restrictions of DAO would prevent the job.
Incremental Streaming may be selected explicitely by option
.B -tao
as it resembles much CD TAO by allowing track sources of
unpredicted length and to keep media appendable by option
.B -multi .
The only restriction towards CD-R[W] is the lack of support for -audio tracks.
Multiple tracks per session are permissible.
.br
The write modes for DVD+R resemble those with DVD-R except that with DVD+R
each track gets wrapped in an own session. There is no -dummy writing with
DVD+R.
.br
Quite deliberately write mode -sao insists in the tradition of a predicted
track size and blank media, whereas -tao writes the tracks open ended and
allows appendable media.
.PP
.B Overwriteable DVD Media:
.br
Currently types DVD+RW, DVD-RW and DVD-RAM can be overwritten via cdrskin.
.br
DVD+RW and DVD-RAM media get treated as blank media regardless wether they
hold data or not. They need no special initial formatting.
Options -audio and -multi are not allowed. Only one track is allowed.
-toc does not return information about the media content.
Speed is counted in DVD units (i.e. 1x = 1,385,000 bytes/second). Currently
there is no difference between -sao and -tao. If ever, then -tao will be the
mode which preserves the current behavior.
Currently there is no difference between -sao and -tao. If ever, then -tao
will be the mode which preserves the current behavior.
.br
DVD-RW need to be formatted to state "Restricted Overwrite". Then they behave
much like DVD+RW. This formatting can be done by option
.B blank=format_overwrite
It is necessary for unused media, for media written or blanked by cdrecord,
for media which have been written unformatted by growisofs or blanked by
dvd+rw-format -blank. If in doubt, just give it a try.
DVD-RW are sold in state "Sequential Recording". To become suitable for the
Overwriteable DVD recording model they need to get formatted to state
"Restricted Overwrite". Then they behave much like DVD+RW. This formatting
can be done by option
.B blank=format_overwrite .
.br
Several programs like dvd+rw-format, cdrecord, wodim, or cdrskin
can bring a DVD-RW out of overwriteable state so
that it has to be formatted again. If in doubt, just give it a try.
.PP
.B Drive preparation and addressing:
.br
@ -133,10 +220,12 @@ by a run of \fBcdrskin --devices\fP.
.br
On Linux, they are device files which traditionally do not offer
w-permissions for normal users. Because libburn needs rw-permission,
it might be only the superuser who is able to get this list without further
it might be only the
.B superuser
who is able to get this list without further
precautions.
.br
It is consensus that \fBchmod a+rw /dev/sg0\fP or \fBchmod a+rw /dev/hdc\fP
It is consensus that \fBchmod a+rw /dev/sr0\fP or \fBchmod a+rw /dev/hdc\fP
is less security sensitive than chmod u+s /usr/bin/cdrskin. The risk for the
drive is somewhat higher but the overall system is much less at stake.
.br
@ -154,7 +243,7 @@ See option -scanbus for getting a list of cdrecord style addresses.
.br
Further are accepted on Linux: links to libburn-suitable device files,
device files which have the same major and minor device number,
and device files which have the same SCSI address parameters (e.g. /dev/sr0).
and device files which have the same SCSI address parameters (e.g. /dev/sg0).
.br
.SH OPTIONS
.TP
@ -180,12 +269,14 @@ Announces that the subsequent tracks are to be burned as audio.
The source is supposed to be uncompressed headerless PCM, 44100 Hz, 16 bit,
stereo. For little-endian byte order (which is usual on PCs) use option
-swab. Unless marked explicitely by option -data, input files with suffix
.wav are examined wether they have a header in MS-WAVE format confirming
".wav" are examined wether they have a header in MS-WAVE format confirming
those parameters and eventually raw audio data get extracted and burned as
audio track. Same is done for suffix .au and SUN Audio.
audio track. Same is done for suffix ".au" and SUN Audio.
.br
Option -audio may be used only with CD media and not with DVD.
.TP
.BI blank= type
Blank a CD-RW or format a DVD+/-RW.
Blank a CD-RW, a DVD-RW, or format a DVD+/-RW.
This is combinable with burning in the same run of cdrskin.
The type given with blank= selects the particular behavior:
.RS
@ -194,29 +285,48 @@ help
Print this list of blanking types.
.TP
all
Blank an entire CD.
Blank an entire CD-RW or an unformatted DVD-RW.
(See also --prodvd_cli_compatible)
.TP
fast
Minimally blank an entire CD.
Minimally blank an entire CD-RW or blank an unformatted DVD-RW.
(See also --prodvd_cli_compatible)
.TP
format_overwrite
Format a DVD-RW to "Restricted Overwrite". The user should bring some patience.
(Note: format_overwrite* are not original cdrecord options.)
.br
(Note: blank=format_overwrite* are not original cdrecord options.)
.TP
format_overwrite_quickest
Like format_overwrite without creating a 128 MB trailblazer session.
Like format_overwrite without creating a 128 MiB trailblazer session.
Leads to "intermediate" state which only allows sequential write
beginning from address 0.
The "intermediate" state ends after the first session of writing data.
.TP
format_overwrite_full
For DVD-RW this is like format_overwrite but claims full media size
rather than just 128 MB.
rather than just 128 MiB.
Most traditional formatting is attempted. No data get written.
Much patience is required.
.br
This option treats already formatted media even if not option -force is given.
.br
For DVD+RW this is the only supported explicit formatting type. It provides
complete "de-icing" so no reader slips on unwritten data areas.
.TP
deformat_sequential
Like blank=all but with the additional ability to blank overwriteable DVD-RW.
This will destroy their formatting and make them sequentially recordable.
Another peculiarity is the ability to blank media which appear already blank.
This is similar to option -force but does not try to blank media other than
recognizable CD-RW and DVD-RW.
.br
(Note: blank=deformat_sequential* are not original cdrecord options.)
.TP
deformat_sequential_quickest
Like blank=deformat_sequential but blanking DVD-RW only minimally.
This is faster than full blanking but may yield media incapable of
Incremental Streaming (-tao).
.RE
.TP
.BI \-checkdrive
@ -224,7 +334,8 @@ Retrieve some info about the addressed drive.
Exits with non-zero value if the drive cannot be found and opened.
.TP
.BI \-dao
Alias for option -sao. Write disk in Session at Once mode.
Alias for option -sao. Write CD in Session at Once mode
or DVD-R[W] in Disc-at-once mode.
.TP
.BI \-data
Subsequent tracks are data tracks. This option is default and only needed
@ -247,17 +358,20 @@ Be aware that deprecated option --old_pseudo_scsi_adr may change the meaning
of Bus,Target,Lun addresses.
.TP
.BI driveropts= opt
Set "driveropts=burnfree" to enable the drive's eventual protection mechanism
against temporary lack of source data (i.e. buffer underrun).
It is not an error to do this with a drive that has no such capabilities.
Set "driveropts=noburnfree" to disable the drive's eventual protection
mechanism against temporary lack of source data (i.e. buffer underrun).
A drive that announces no such capabilities will not get them enabled anyway,
even if attempted explicitely via "driveropts=burnfree".
.TP
.BI \-dummy
Try to perform the drive operations without actually affecting the inserted
media. There is no guarantee that this will work with a particular drive
in a particular write mode. Blanking is prevented reliably, though.
media. There is no warranty that this will work with a particular combination
of drive, media, and write mode. Blanking is prevented reliably, though.
To avoid inadverted real burning, -dummy refuses burn runs on anything but
CD-R[W] and DVD-R[W].
.TP
.BI \-eject
Eject the disk after work is done.
Eject the disc after work is done.
.TP
.BI \-force
Assume that the user knows better in situations when cdrskin or libburn are
@ -265,9 +379,13 @@ insecure about drive or media state. This includes the attempt to blank
media which are classified as unknown or unsuitable, and the attempt to use
write modes which libburn believes they are not supported by the drive.
.br
Another application is with blank=format_* to enforce re-formatting of media
which appear to be sufficiently formatted already.
Another application is to enforce blanking or re-formatting of media
which appear to be in the desired blank or format state already.
.br
This option enables a burn run with option -dummy even if libburn believes
that drive and media will not simulate the write mode but will write for real.
.br
.B Caution:
Use this only when in urgent need.
.TP
.BI fs= size
@ -289,6 +407,29 @@ option fifo_start_at=size.
.BI gracetime= seconds
Set the grace time before starting to write. (Default is 0)
.TP
.BI -isosize
The next track following this option will try to obtain its source size from
the header information out of the first few blocks of the source data.
If these blocks indicate an ISO-9660 filesystem then its declared size
will be used under the assumption that it is a single session filesystem.
.br
If not, then the burn run will be aborted.
.br
The range of -isosize is exactly one track. Further tracks may be preceeded
by further -isosize options, though. At least 15 blocks of padding will be
added to each -isosize track. But be advised to rather use padsize=300k.
.br
This option can be performed on track sources which are regular files or block
devices. For the first track of the session it can be performed on any type
of source if there is a fifo of at least 64 kiB. See option fs= .
.TP
.BI minbuf= percentage
Equivalent to:
.br
modesty_on_drive=1:min_percent=<percentage>:max_percent=95
.br
Percentage is permissible between 25 and 95.
.TP
.BI msifile= path
Run option -msinfo and copy the result line into the file given by path.
Unlike -msinfo this option does not redirect all normal output away from
@ -299,19 +440,23 @@ Note: msifile=path is actually an option of wodim and not of cdrecord.
.BI \-msinfo
Retrieve multi-session info for preparing a follow-up session by option -C
of programs mkisofs or genisoimage. Print result to standard output.
This option redirects to stderr all
message output besides its own result string, which consists of two numbers.
This option redirects to stderr all message output except the one of option
--tell_media_space and its own result string, which consists of two numbers.
The result string shall be used as argument of option -C with said programs.
It gives the start address of the most recent session and the predicted
start address of the next session to be appended. The string is empty if
the most recent session was not written with option -multi.
.TP
.BI \-multi
This option keeps the CD appendable after the current session has been written.
Without it the disk gets closed and may not be written any more - unless it
is a CD-RW and gets blanked which causes loss of its content.
This option keeps the CD or unformatted DVD-R[W] appendable after the current
session has been written.
Without it the disc gets closed and may not be written any more - unless it
is a -RW and gets blanked which causes loss of its content.
.br
The following sessions can only be written in -tao mode.
The following sessions can only be written in -tao mode. -multi is prohibited
with overwriteable DVD media and with DVD-R[W] DAO write mode.
Option --prodvd_cli_compatible eventually makes -multi tolerable but cannot
make it work.
.br
In order to have all filesystem content accessible, the eventual ISO-9660
filesystem of a follow-up
@ -328,7 +473,7 @@ to be no use for audio tracks with incomplete last sector, this option applies
only to data tracks. There it is default.
.TP
.BI \-pad
Add 30 kB of trailing zeros to each data track. (This is not sufficient to
Add 30 kiB of trailing zeros to each data track. (This is not sufficient to
avoid problems with various CD-ROM read drivers.)
.TP
.BI padsize= size
@ -337,18 +482,30 @@ gets reset to padsize=0 after that next track is written. It may be set
again before the next track argument. About size specifiers, see option fs=.
.TP
.BI \-raw96r
Write disk in RAW/RAW96R mode. This mode allows to put more payload bytes
Write CD in RAW/RAW96R mode. This mode allows to put more payload bytes
into a CD sector but obviously at the cost of error correction. It can only
be used for tracks of fixely predicted size. Some drives allow this mode but
then behave strange or even go bad for the next few attempts to burn a CD.
One should use it only if inavoidable.
.TP
.BI \-sao
Write disk in Session At Once mode. This mode is able to put several audio
tracks on CD without producing audible gaps between them. It can only
be used for tracks of fixely predicted size. This implies that track arguments
which depict stdin or named pipes need to be preceeded by option tsize= or
by option tao_to_sao_tsize=.
Write CD in Session At Once mode, a sequential DVD-R[W] in Disc-at-once
(DAO) mode, or a DVD+R.
.br
With CD this mode is able to put several audio tracks on media without
producing audible gaps between them.
.br
With DVD-R[W] this mode can only write a single track.
No -multi is allowed with DVD-R[W] -sao.
.br
-sao is permissible with overwriteable DVD and with DVD+R but actually only
imposes restrictions without providing known advantages.
.br
-sao can only be used for tracks of fixely predicted size. This implies that
track arguments which depict stdin or named pipes need to be preceeded by
option tsize= or by option tao_to_sao_tsize=.
.br
-sao cannot be used on appendable media.
.TP
.BI \-scanbus
Scan the system for drives. On Linux the drives at /dev/s* and at /dev/hd*
@ -365,8 +522,12 @@ Bus,Target,Lun Number) 'Vendor' 'Mode' 'Revision'
.TP
.BI speed= number
Set speed of drive. With data CD, 1x speed corresponds to a throughput of
150 kB/s. It is not an error to set a speed higher than is suitable for drive
150,000 bytes/second. With DVD, 1x = 1,385,000 bytes/second.
It is not an error to set a speed higher than is suitable for drive
and media. One should stay within a realistic speed range, though.
Special speed settings are:
.br
0 = minimal speed , -1 = maximal speed (default).
.TP
.BI \-swab
Announce that the raw audio data source of subsequent tracks is byte swapped
@ -377,13 +538,17 @@ Less guesswork is needed if track sources are in format MS-WAVE in a file with
suffix ".wav".
.TP
.BI \-tao
Write disk in Track At Once (TAO) mode. This mode can be used with track
sources of unpredictable size, like standard input or named pipes. It is
also the only mode that can be used for writing to appendable CD which
already hold data.
Write CD in Track At Once (TAO) mode, sequential DVD-R[W] in Incremental
Streaming mode, or DVD+R without traditional -sao restrictions.
This mode also applies pro-forma to overwriteable DVD media.
.br
Mode -tao can be used with track sources of unpredictable size, like standard
input or named pipes. It is also the only mode that can be used for writing
to appendable media which already hold data. With unformatted DVD-R[W] it is
the only mode which allows -multi.
.TP
.BI \-toc
Print the table of content (TOC) which describes the tracks recorded on CD.
Print the table of content (TOC) which describes the tracks recorded on disc.
The output contains all info from option -atip plus lines which begin with
"track:", the track number, the word "lba:" and a number which gives the
start address of the track. Addresses are counted in CD sectors which with
@ -416,7 +581,7 @@ About size specifiers, see option fs=.
If the track source does not deliver the predicted amount of bytes, the
remainder of the track is padded with zeros. This is not considered an error.
If on the other hand the track source delivers more than the announced bytes
then the track on CD gets truncated to the predicted size and cdrskin exits
then the track on media gets truncated to the predicted size and cdrskin exits
with non-zero value.
.TP
.BI \-v
@ -430,6 +595,12 @@ somebody who had a look into the program sourcecode.
Alphabetical list of options which are genuine to cdrskin and intended for
normal use:
.TP
.BI \--adjust_speed_to_drive
Curb explicitely given speed= values to the maximum which is announced by the
drive for the loaded media. By default, such an adjustment is only made with
pseudo-speeds 0 and -1 whereas speed settings > 0 are sent unchanged to the
drive which will then choose an appropriate speed on its own.
.TP
.BI \--allow_setuid
Disable the loud warning about insecure discrepance between login user and
effective user which indicates application of chmod u+s to the program binary.
@ -441,6 +612,20 @@ contain a "=" character.
By default such arguments are seen as misspelled options. It is nevertheless
not possible to use one of the options listed with --list_ignored_options.
.TP
.BI assert_write_lba= block_number | byte_address
Abort if the write address given with this option is not the same as predicted
immediately before the write session starts. This option can ensure that a
start address which was presumed by a formatter like mkisofs -C is really used
by the drive for writing.
assert_write_lba=0 effectively demands blank media and excludes appendables.
.br
Block numbering is peculiar: If the last character of the option string is
a letter [a-zA-Z] then the usual unit scaling by "s", "k", "m", etc. applies
and the result is divided by 2048. Else the number value of the string is
taken as plain block number with block size 2048 byte.
(E.g ...=1000 or ...=1000s means block 1000, ...=1m means block
512, ...=4096b means block number 2)
.TP
.BI \--demand_a_drive
Exit with a nonzero value if no drive can be found during a bus scan.
.TP
@ -465,10 +650,10 @@ fifo_start_at= combine a quick burn start and a large savings buffer to
compensate for temporary lack of source data. At the beginning of burning,
the software protection against buffer underun is as weak as the size of
fifo_start_at= . So it is best if the drive offers hardware protection which
has to be enabled by driveropts=burnfree.
is enabled automatically if not driveropts=noburnfree is given.
.TP
.BI \--list_ignored_options
List all ignored cdrecord options. The --options cannot be used as addresses
List all ignored cdrecord options. The "-" options cannot be used as addresses
of track sources. No track source address may begin with a text equal to an
option which ends by "=". The list is ended by an empty line.
.TP
@ -476,13 +661,56 @@ option which ends by "=". The list is ended by an empty line.
Only if used as first command line argument this option prevents reading and
interpretation of eventual startup files. See section FILES below.
.TP
.BI \--prodvd_cli_compatible
Activates behavior modifications with some DVD situations which bring cdrskin
nearer to the behavior of cdrecord-ProDVD:
.br
Option -multi with unsuitable media is not an error but simply has no effect.
.br
Options blank=fast and blank=all deformat overwriteable DVD-RW media.
.br
Option blank=fast does indeed minmal blanking with DVD-RW. This may yield media
which can only do DAO but not Incremental Streaming.
.TP
.BI \--single_track
Accept only the last argument of the command line as track source address.
.TP
.BI tao_to_sao_tsize= size
Set an exact fixed size for the next track to be in effect only if the track
source cannot deliver a size prediction and no tsize= was specified and an
exact track size prediction is demanded by the write mode.
.br
This was the fallback from bad old times when cdrskin was unable to burn
in mode -tao . It came back with minimally blanked DVD-RW which allow no
Incremental Streaming (-tao) resp. with explicitly selected write mode -sao
for best DVD-ROM compatibility.
.br
If the track source delivers less bytes than announced then the missing ones
will be filled with zeros.
.TP
.BI --tell_media_space
Prepare a recording session, do not perform it but rather inquire the
maximum number of 2048 byte data blocks which may be written in
the current state of media with the prepared setup. So this option disables
recording of data. It does allow blanking, though, and will measure space
afterwards.
.br
It is not mandatory to give track sources but their nature may influence
the available capacity. So for most realistic results one may set up
the full burn session and add --tell_media_space. But if one has to expect
a cdrskin version prior to 0.3.3 no track source should be given in order
not to start an involuntary burn session.
In this case set at least -sao or -tao explicitely.
.br
The result gets printed to standard output. It is 0 or empty if no writing
is possible with the given options.
This option redirects to stderr all message output except its own result
string and eventual output of -msinfo.
.TP
.BI write_start_address= byte_offset
Set the address on media where to start writing the track. With DVD+RW or
DVD-RAM byte_offset must be aligned to 2 KB blocks, but better is 32 kB.
With DVD-RW 32 kB alignment is mandatory.
DVD-RAM byte_offset must be aligned to 2 kiB blocks, but better is 32 kiB.
With DVD-RW 32 kiB alignment is mandatory.
.br
Other media are not suitable for this option yet.
.PP
@ -495,6 +723,17 @@ but rather to shut it down and to wait until it has ended the final operations.
This option is only needed for revoking eventual --ignore_signals or
--no_abort_handler.
.TP
.BI \--allow_untested_media
Enable the use of media profiles which have been implemented but not yet
tested. Currently this applies to :
.br
Profile 0015h , DVD-R/DL Sequential (will not allow -multi).
.br
Profile 002Bh , DVD+R/DL.
.br
If you really test such media, then please report the outcome on
libburn-hackers@pykix.org
.TP
.BI dev_translation= <sep><from><sep><to>
Set drive address alias. This was necessary before cdrskin-0.2.4 to manually
translate cdrecord addresses into cdrskin addresses.
@ -504,7 +743,7 @@ translate cdrecord addresses into cdrskin addresses.
dev=. <to> is the address to be used instead whenever <from> is given.
More than one translation instruction can be given in one cdrskin run.
.br
E.g.: dev_translation=+ATA:1,0,0+/dev/sg1 dev_translation=+ATA:1,1,0+/dev/sg2
E.g.: dev_translation=+ATA:1,0,0+/dev/sr1 dev_translation=+ATA:1,1,0+/dev/sr2
.TP
.BI \--drive_abort_on_busy
Linux specific: Abort process if a busy drive is encountered.
@ -513,14 +752,33 @@ Linux specific: Abort process if a busy drive is encountered.
Linux specific: Try to wait for a busy drive to become free.
This is not guaranteed to work with all drivers. Some need nonblocking i/o.
.TP
.BI \--drive_f_setlk
Linux specific: Try to get exclusive lock on drive device file via fcntl(2).
.TP
.BI \--drive_not_exclusive
Linux specific: Combine --drive_not_f_setlk and --drive_not_o_excl.
.TP
.BI \--drive_not_f_setlk
Linux specific: Do not try to get exclusive lock on drive device file via
fcntl(2).
.TP
.BI \--drive_not_o_excl
Linux specific: Do not ask the operating system to prevent opening busy drives.
Wether this leads to senseful behavior depends on operating system and kernel.
.TP
.BI drive_scsi_dev_family= sr | scd | sg
Linux specific: Select a SCSI device file family to be used for drive command
transactions. Normally this is /dev/sgN on kernel versions < 2.6 and /dev/srN
on kernels >= 2.6 . This option allows to explicitely override that default
in order to meet other programs at a common device file for each drive.
On kernel 2.4 families sr and scd will find no drives.
.br
Device file family /dev/hdX on kernel >= 2.6 is not affected by this setting.
.TP
.BI \--drive_scsi_exclusive
Linux specific:
Try to exclusively reserve device files /dev/srN, /dev/scdM, /dev/stK of drive.
this would be helpful to protect against collisions with program growisofs.
Try to exclusively reserve device files /dev/srN, /dev/scdM, /dev/sgK of drives.
This would be helpful to protect against collisions with program growisofs.
Regrettably on Linux kernel 2.4 with ide-scsi emulation this seems not to
work. Wether it becomes helpful with new Linux systems has to be evaluated.
.TP
@ -530,6 +788,18 @@ Disable fifo despite any fs=.
.BI \--fifo_per_track
Use a separate fifo for each track.
.TP
.BI \--fill_up_media
Expand the last track of the session to occupy all remaining free space on
the media.
.br
This option overrides option -multi. It will not fill up media if option -sao
is given with CD media.
.br
.B Caution:
This option might increase read compatibility with DVD-ROM drives but
with some DVD recorders and media types it might also fail to produce readable
media at all. "Your mileage may vary".
.TP
.BI grab_drive_and_wait= seconds
Open the addressed drive, wait the given number of seconds, release the drive,
and do normal work as indicated by the other options used. This option helps
@ -542,13 +812,37 @@ Try to ignore any signals rather than to abort the program. This is not a
very good idea. You might end up waiting a very long time for cdrskin
to finish.
.TP
.BI modesty_on_drive= <mode>[:min_percent=<num>][:max_percent=<num>]
Mode 1 keeps the program from trying to write to the burner drive while its
buffer is in danger to be filled by more than max_percent. If this filling is
exceeded then the program will wait until the filling is at most min_percent.
.br
This can ease the load on operating system and drive controller and thus help
with achieving better input bandwidth if disk and burner are not on independent
controllers (like hda and hdb). Unsufficient input bandwidth is indicated by
output "(fifo xy%)" of option -v if xy is lower than 90 for some time.
modesty_on_drive= might hamper output bandwidth and cause buffer underruns.
.br
To have max_percent larger than the burner's best actual
buffer fill has the same effect as min_percent==max_percent. Some burners
do not use their full buffer with all media types. Watch output "[buf xy%]"
of option -v to get an impression of the actual buffer usage. Some burners
are not suitable because they report buffer fill with granularity too large
in size or time.
.br
Mode 0 disables this feature. Mode -1 keeps it unchanged. Default is:
.br
modesty_on_drive=0:min_percent=65:max_percent=95
.br
Percentages are permissible in the range of 25 to 100.
.TP
.BI \--no_abort_handler
On signals exit even if the drive is in busy state. This is not a very good
idea. You might end up with a stuck drive that refuses to hand out the media.
.TP
.BI \--no_blank_appendable
Refuse to blank appendable CD-RW. This is a feature that was once builtin with
libburn. No information available for what use case it was needed.
Refuse to blank appendable CD-RW or DVD-RW. This is a feature that was once
builtin with libburn. No information available for what use case it was needed.
.TP
.BI \--no_convert_fs_adr
Do only literal translations of dev=. This prevents cdrskin from test-opening
@ -558,23 +852,17 @@ Partly Linux specific:
Such opening is needed for Bus,Target,Lun addresses unless option
--old_pseudo_scsi_adr is given. It is also needed to resolve device file
addresses which are not listed with cdrskin --devices but nevertheless point
to a usable drive. (Like /dev/sr0 using the same SCSI address as /dev/sg0.)
to a usable drive. (Like /dev/sg0 using the same SCSI address as /dev/sr0.)
.TP
.BI \--old_pseudo_scsi_adr
Linux specific:
Use and report literal Bus,Target,Lun addresses rather than real SCSI and
pseudo ATA addresses. This method is outdated and was never compatible with
original cdrecord.
.TP
.BI tao_to_sao_tsize= size
Set an exact fixed size for the next track to be in effect only if the track
source cannot deliver a size prediction and no tsize= was specified.
This is the fallback from bad old times when cdrskin was unable to burn
in mode -tao.
.br
.SH EXAMPLES
.SS
.B Get an overview of drives:
.B Get an overview of drives and their addresses:
.br
cdrskin -scanbus
.br
@ -586,57 +874,65 @@ cdrskin --devices
.br
cdrskin dev=0,1,0 -checkdrive
.br
cdrskin dev=ATA:1,0,0 -atip
cdrskin dev=ATA:1,0,0 -v -atip
.br
cdrskin dev=/dev/hdc -toc
.SS
.B Make used CD-RW writable again:
.B Make used CD-RW or used unformatted DVD-RW writable again:
.br
cdrskin -v dev=/dev/sg1 blank=all -eject
cdrskin -v dev=/dev/sg1 blank=fast -eject
.br
cdrskin -v dev=/dev/dvd blank=fast -eject
cdrskin -v dev=/dev/dvd blank=all -eject
.SS
.B Format DVD-RW before first use with cdrskin:
.B Format DVD-RW to avoid need for blanking before re-use:
.br
cdrskin -v dev=/dev/sr0 blank=format_overwrite
.SS
.B Write ISO-9660 filesystem image:
.B De-format DVD-RW to make it capable of multi-session again:
.br
cdrskin -v dev=/dev/sr0 blank=deformat_sequential
.SS
.B Write ISO-9660 filesystem image as only one to blank or formatted media:
.br
cdrskin -v dev=/dev/hdc speed=12 fs=8m \\
.br
driveropts=burnfree -sao -eject \\
.br
padsize=300k my_image.iso
-sao -eject padsize=300k my_image.iso
.SS
.B Write compressed afio archive on-the-fly:
.B Write compressed afio archive on-the-fly (not possible with minimally blanked DVD-RW):
.br
find . | afio -oZ - | \\
.br
cdrskin -v dev=0,1,0 fs=32m speed=8 driveropts=burnfree \\
cdrskin -v dev=0,1,0 fs=32m speed=8 \\
.br
padsize=300k -tao -
-tao padsize=300k -
.SS
.B Write several sessions to the same CD:
.B Write multi-session to the same CD, DVD-R[W] or DVD+R:
.br
cdrskin dev=/dev/hdc padsize=300k -multi 1.iso
cdrskin dev=/dev/hdc -v padsize=300k -multi -tao 1.iso
.br
cdrskin dev=/dev/hdc padsize=300k -multi -tao 2.afio
cdrskin dev=/dev/hdc -v padsize=300k -multi -tao 2.iso
.br
cdrskin dev=/dev/hdc padsize=300k -multi -tao 3.afio
cdrskin dev=/dev/hdc -v padsize=300k -multi -tao 3.iso
.br
cdrskin dev=/dev/hdc padsize=300k -tao 4.afio
cdrskin dev=/dev/hdc -v padsize=300k -tao 4.iso
.SS
.B Get CD multi-session info for option -C of program mkisofs:
.B Get multi-session info for option -C of program mkisofs:
.br
c_values=$(cdrskin dev=/dev/sr0 -msinfo 2>/dev/null)
c_values=$(cdrskin dev=/dev/hdc -msinfo 2>/dev/null)
.br
mkisofs ... -C "$c_values" ...
.SS
.B Inquire free space on media for a -tao -multi run:
.br
x=$(cdrskin dev=/dev/sr0 -tao -multi \\
.br
--tell_media_space 2>/dev/null)
.br
echo "Available: $x blocks of 2048 data bytes"
.SS
.B Write audio tracks to CD:
.br
cdrskin -v dev=ATA:1,0,0 speed=48 \\
.br
driveropts=burnfree -sao \\
cdrskin -v dev=ATA:1,0,0 speed=48 -sao \\
.br
track1.wav track2.au -audio -swab track3.raw
.br
@ -677,7 +973,7 @@ fs=16m
.br
.SH SEE ALSO
.TP
Formatting track sources for cdrskin:
Formatting data track sources for cdrskin:
.br
.BR mkisofs (8),
.BR genisoimage (8),
@ -691,7 +987,7 @@ Other CD/DVD burn programs:
.BR wodim (1)
.br
.TP
For DVD burning:
For DVD burning (also tutor of libburn's DVD capabilities):
.br
.BR growisofs (1)
.br

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
<HEAD>
<META NAME="description" CONTENT="cdrskin, a limited cdrecord compatibility wrapper for libburn">
<META NAME="keywords" CONTENT="cdrskin, libburn, libburnia, burn, CD, linux, CDR, CD-R, CDRW, CD-RW, cdrecord, compatible, scdbackup, burning">
<META NAME="keywords" CONTENT="cdrskin, libburn, libburnia, burn, CD, DVD, linux, recording, burning, CD-R, CD-RW, DVD-R, DVD-RW, DVD+RW, DVD+R, cdrecord, compatible, scdbackup">
<META NAME="robots" CONTENT="follow">
<TITLE>cdrskin homepage english</TITLE>
</HEAD>
@ -12,7 +12,7 @@
<CENTER>
<A HREF="http://en.wikipedia.org/wiki/D%C3%B6ner_kebab">
<IMG SRC="doener_150x200_tr_octx.gif" BORDER=0
<IMG SRC="doener_150x200_tr_octx.png" BORDER=0
ALT="cdrskin logo: Doener mit Scharf">
</A>
<P><H2> Homepage of </H2>
@ -24,9 +24,8 @@
<P>
<H2>Purpose:</H2>
<UL>
<LI>Burns preformatted data to CD-R or CD-RW</LI>
</UL>
Burns preformatted data to CD and single layer DVD media:<BR>
CD-R, DVD-R, DVD+R, CD-RW, DVD-RW, DVD-RAM, DVD+RW
</P>
<P>
@ -34,9 +33,10 @@
<P>
<H2>Hardware requirements:</H2>
A CD recorder suitable for
<A HREF="http://libburnia.pykix.org">libburnia.pykix.org</A>
(SCSI or IDE/ATAPI writers compliant to mmc-3 standard).
A CD/DVD recorder suitable for
<A HREF="http://libburnia.pykix.org">libburnia.pykix.org</A> <BR>
(SCSI , ATA , USB , or SATA writers compliant to standard MMC-3 for CD
and to MMC-5 for DVD).
<BR>
</P>
@ -44,7 +44,7 @@ A CD recorder suitable for
<H2>Software requirements :</H2>
<DL>
<DT>Linux kernel 2.4 or higher</DT>
<DD>With kernel 2.4 the drive has to be under ide-scsi emulation.</DD>
<DD>With kernel 2.4 an ATA drive has to be under ide-scsi emulation.</DD>
<DD>With kernel 2.6 the drive should not be under ide-scsi.</DD>
<DT>libpthread</DT>
<DD>is supposed to be a standard system component.</DD>
@ -56,9 +56,9 @@ A CD recorder suitable for
GPL software included:<BR>
</H2>
<DL>
<DT>libburn-0.2.6</DT>
<DT>libburn-0.3.8</DT>
<DD>(by Derek Foreman, Ben Jansens, and team of libburnia.pykix.org)</DD>
<DD>transfers data to CD</DD>
<DD>transfers data to CD and DVD</DD>
</DL>
</P>
@ -81,71 +81,93 @@ Ports to other usable systems are appreciated. Reports are welcome.
<P>
<H2>Commands:</H2>
<DL>
<DT>The goal is to provide some of cdrecord's options in a compatible way.
This has been achieved quite sufficiently for the needs of backup tool
<A HREF="http://scdbackup.sourceforge.net/main_eng.html">scdbackup</A>
and for data CD projects of <A HREF="http://www.k3b.org">K3b</A>
(see <A HREF="#examples">examples</A>).
Suitability for audio CD frontends has been improved much and is now being
evaluated.<BR>
Further enhancements depend on people who can describe and discuss their
wishes as well as on the development of libburn.</DT>
<DT>The most common options of cdrecord for data and audio on CD media
are provided in a compatible way.<BR>
On single layer DVD media cdrskin is able to perform any recording job
which is possible with cdrecord.
Other than with cdrecord, options -multi and -tao are supported with
certain DVD types.
</DT>
<BR><BR>
<DT>Get an overview of drives:</DT>
<DD>$ cdrskin -scanbus</DD>
<DD>$ cdrskin dev=ATA -scanbus</DD>
<DD>$ cdrskin --devices</DD>
<DT>Get an overview of drives and their addresses</DT>
<DD>#<KBD>&nbsp;cdrskin -scanbus</KBD></DD>
<DD>#<KBD>&nbsp;cdrskin dev=ATA -scanbus</KBD></DD>
<DD>#<KBD>&nbsp;cdrskin --devices</KBD></DD>
<DT>Being superuser avoids permission problems with /dev/srN resp. /dev/hdX .
</DT>
<DT>Ordinary users should then get granted rw access to the /dev files
as listed by option --devices.</DT>
<DT>&nbsp;</DT>
<DT>Get info about a particular drive or loaded media:</DT>
<DD>$ cdrskin dev=0,1,0 -checkdrive</DD>
<DD>$ cdrskin dev=ATA:1,0,0 -atip</DD>
<DD>$ cdrskin dev=/dev/hdc -toc</DD>
<DT>Make used CD-RW writable again:</DT>
<DD>$ cdrskin -v dev=/dev/sg1 blank=all -eject</DD>
<DD>$ cdrskin -v dev=/dev/dvd blank=fast -eject</DD>
<DT>Write ISO-9660 filesystem image:</DT>
<DD>$ cdrskin -v dev=/dev/hdc speed=12 fs=8m driveropts=burnfree -sao -eject padsize=300k my_image.iso</DD>
<DT>Write compressed afio archive on-the-fly :</DT>
<DD>$ find . | afio -oZ - | cdrskin -v dev=0,1,0 fs=32m speed=8 driveropts=burnfree padsize=300k -tao -</DD>
<DT>Write audio tracks:</DT>
<DD>$ cdrskin -v dev=ATA:1,0,0 speed=48 driveropts=burnfree -sao track1.wav track2.au -audio -swab track3.raw
<DD>
<BR>
<DD>$<KBD>&nbsp;cdrskin dev=0,1,0 -checkdrive</KBD></DD>
<DD>$<KBD>&nbsp;cdrskin dev=ATA:1,0,0 -v -atip</KBD></DD>
<DD>$<KBD>&nbsp;cdrskin dev=/dev/hdc -toc</KBD></DD>
<DT>Make used CD-RW or used unformatted DVD-RW writable again:</DT>
<DD>$<KBD>&nbsp;cdrskin -v dev=/dev/sg1 blank=fast -eject</KBD></DD>
<DD>$<KBD>&nbsp;cdrskin -v dev=/dev/dvd blank=all -eject</KBD></DD>
<DT>Format DVD-RW to avoid need for blanking before re-use:</DT>
<DD>$<KBD>&nbsp;cdrskin -v dev=/dev/sr0 blank=format_overwrite</KBD></DD>
<DT>De-format DVD-RW to make it capable of multi-session again:</DT>
<DD>$<KBD>&nbsp;cdrskin -v dev=/dev/sr0 blank=deformat_sequential</KBD></DD>
<DT>Write ISO-9660 filesystem image as only one to blank or formatted media:
</DT>
<DD>$<KBD>&nbsp;cdrskin -v dev=/dev/hdc speed=12 fs=8m \</KBD></DD>
<DD><KBD>&nbsp;&nbsp;-sao -eject padsize=300k my_image.iso</KBD></DD>
<DT>Write compressed afio archive on-the-fly:</DT>
<DD>$<KBD>&nbsp;find . | afio -oZ - | \</KBD></DD>
<DD><KBD>&nbsp;&nbsp;cdrskin -v dev=0,1,0 fs=32m speed=8 \</KBD></DD>
<DD><KBD>&nbsp;&nbsp;-tao padsize=300k -</KBD></DD>
<DT>Write several sessions to the same CD, DVD-R[W] or DVD+R:</DT>
<DD>$<KBD>&nbsp;cdrskin dev=/dev/hdc -v padsize=300k -multi -tao 1.iso</KBD>
</DD>
<DD>$<KBD>&nbsp;cdrskin dev=/dev/hdc -v padsize=300k -multi -tao 2.iso</KBD>
</DD>
<DD>$<KBD>&nbsp;cdrskin dev=/dev/hdc -v padsize=300k -multi -tao 3.iso</KBD>
</DD>
<DD>$<KBD>&nbsp;cdrskin dev=/dev/hdc -v padsize=300k -tao 4.iso</KBD></DD>
<DT>Get multi-session info for option -C of program mkisofs:</DT>
<DD>$<KBD>&nbsp;c_values=$(cdrskin dev=/dev/sr0 -msinfo 2>/dev/null)</KBD></DD>
<DD>$<KBD>&nbsp;mkisofs ... -C "$c_values" ...</KBD></DD>
<DT>Inquire free space on media for a -tao -multi run:</DT>
<DD>$<KBD>&nbsp;x=$(cdrskin dev=/dev/sr0 -tao -multi \</KBD></DD>
<DD><KBD>&nbsp;&nbsp;--tell_media_space 2>/dev/null)</KBD></DD>
<DD>$<KBD>&nbsp;echo "Available: $x blocks of 2048 data bytes"</KBD></DD>
<DT>Write audio tracks to CD:</DT>
<DD>$<KBD>&nbsp;cdrskin -v dev=ATA:1,0,0 speed=48 -sao \</KBD></DD>
<DD><KBD>&nbsp;&nbsp;track1.wav track2.au -audio -swab track3.raw</KBD></DD>
<DT>Get overview of the cdrecord compatible options:</DT>
<DD><A HREF="cdrskin_help">$ cdrskin -help</A></DD>
<DD>$<KBD>&nbsp;<A HREF="cdrskin_help">cdrskin -help</A></KBD></DD>
<DT>Get overview of the non-cdrecord options:</DT>
<DD><A HREF="cdrskin__help">$ cdrskin --help</A></DD>
<DD>$<KBD>&nbsp;<A HREF="cdrskin__help">cdrskin --help</A></KBD></DD>
<DT>Read the detailed manual page:</DT>
<DD><A HREF="man_1_cdrskin.html">$ man cdrskin</A></DD>
<DD>$<KBD>&nbsp;<A HREF="man_1_cdrskin.html">man cdrskin</A></KBD></DD>
</DL>
<DL>
<DT>Read about the standard for which cdrskin is striving:</DT>
<DD><A HREF="http://cdrecord.berlios.de/old/private/man/cdrecord-2.0.html">
$ man cdrecord</A></DD>
<DD>$<KBD>&nbsp;
<A HREF="http://cdrecord.berlios.de/old/private/man/cdrecord-2.0.html">
man cdrecord</A></KBD></DD>
<DD><B>Do not bother Joerg Schilling with any cdrskin problems.</B>
(Be cursed if you install cdrskin as "cdrecord" without clearly forwarding
this "don't bother Joerg" demand.)
</DD>
</DL>
</P>
<P>
<H2>Known deficiencies:</H2>
<UL>
<DT></DT>
<LI>
Appending sessions to unclosed media is restricted to write mode TAO.
</LI>
<LI>
cdrskin -scanbus or --devices hangs for quite a while if there is
a CD drive which does not work properly (e.g. because it has individual
problems with DMA).
So if the superuser gets no result with cdrskin --devices then one should
disable DMA with the problematic CD drives
(like: <KBD>hdparm -d0 /dev/hdd</KBD> )
and try again.<BR>
In severe cases it might be necessary to guess the device name /dev/sgN resp.
/dev/hdX of the non-ill burner if it cannot be found otherwise among its
ill peers. Alternatively one can guess the address of the ill device, remove
rw-permissions and retry the bus scan as non-superuser.
</UL>
Testers wanted who are willing to risk some double layer DVD media.
</P>
<HR>
@ -153,10 +175,9 @@ rw-permissions and retry the bus scan as non-superuser.
<P>
<DL>
<DT>Download as source code (see README):</DT>
<DD><A HREF="cdrskin-0.2.6.pl02.tar.gz">cdrskin-0.2.6.pl02.tar.gz</A>
(510 KB).
<DD><A HREF="cdrskin-0.3.8.pl00.tar.gz">cdrskin-0.3.8.pl00.tar.gz</A>
(615 KB).
</DD>
<DD>(Most recent patch: backported man page from cdrskin-0.2.7)</DD>
<DD>
The "stable" cdrskin tarballs are source code identical with "stable"
libburn releases or with "stabilized" libburn SVN snapshots. They get
@ -165,21 +186,21 @@ cdrskin is part of libburn - full libburn is provided with cdrskin releases.
</DD>
<DD>&nbsp;</DD>
<DT>Download as single x86 binaries (untar and move to /usr/bin/cdrskin):</DT>
<DD><A HREF="cdrskin_0.2.6.pl01-x86-suse9_0.tar.gz">
cdrskin_0.2.6.pl01-x86-suse9_0.tar.gz</A>, (60 KB),
<DD><A HREF="cdrskin_0.3.8.pl00-x86-suse9_0.tar.gz">
cdrskin_0.3.8.pl00-x86-suse9_0.tar.gz</A>, (90 KB),
<DL>
<DD>runs on SuSE 9.0 (2.4.21) , RIP-14.4 (2.6.14) ,
Gentoo (2.6.15 x86_64 Athlon).</DD>
</DL>
<DD><A HREF="cdrskin_0.2.6.pl01-x86-suse9_0-static.tar.gz">
cdrskin_0.2.6.pl01-x86-suse9_0-static.tar.gz</A>, (260 KB), -static compiled,
<DD><A HREF="cdrskin_0.3.8.pl00-x86-suse9_0-static.tar.gz">
cdrskin_0.3.8.pl00-x86-suse9_0-static.tar.gz</A>, (290 KB), -static compiled,
<DL>
<DD>runs on SuSE 7.2 (2.4.4), and on the systems above.</DD>
</DL>
</DD>
</DL>
<DL><DT>Documentation:</DT>
<DD><A HREF="README_cdrskin">README</A> a short introduction</DD>
<DD><A HREF="README_cdrskin">README</A> an introduction</DD>
<DD><A HREF="cdrskin__help">cdrskin --help</A> non-cdrecord options</DD>
<DD><A HREF="cdrskin_help">cdrskin -help</A> cdrecord compatible options</DD>
<DD><A HREF="man_1_cdrskin.html">man cdrskin</A> the manual page</DD>
@ -199,47 +220,40 @@ cdrskin_0.2.6.pl01-x86-suse9_0-static.tar.gz</A>, (260 KB), -static compiled,
<HR>
<P>
Enhancements towards previous stable version cdrskin-0.2.4:
Enhancements towards previous stable version cdrskin-0.3.4:
<UL>
<LI>Option <KBD><B>-tao</B></KBD> is fully enabled.<BR>
SAO is still the preferred default but TAO is default if a track of
unpredicted size is present (stdin, named pipe, ...) or if a follow-up
session is written to an appendable CD.
(This is an intentional deviation from cdrecord defaults which themselves
have changed with the newest cdrecord versions.)
</LI>
<LI>Status report during blank, preparation and finalization improved.</LI>
<LI>Bug fixed: Trailing trash appended to .wav files caused error message
and, if exceeding fifo size, could even stall a burn.
(Workaround: disable fifo by <KBD><B>fs=0</B></KBD>)</LI>
<LI>Bug fixed: False speed with first pacifier cycle. Potential program
abort by floating point exception (NaN).</LI>
<LI>multi-session CDs: <KBD><B>-multi</B></KBD>, <KBD><B>-msinfo</B></KBD>,
writing to appendable CDs (for now restricted to write mode TAO).</LI>
<LI>Now able to cope with the peculiarities of Linux 2.4 USB</LI>
<LI>Refusal to perform -dummy runs on media which cannot simulate burning</LI>
<LI>Precautions against using the burner drive as track source</LI>
<LI>New option modesty_on_drive= may help with hda -> hdb burns</LI>
<LI>New option minbuf= , cdrecord compatible frontend of modesty_on_drive=</LI>
<LI>New option --adjust_speed_to_drive</LI>
</UL>
<!--
Bug fixes towards cdrskin-0.3.8.pl00:
<UL>
<LI>none yet</LI>
</UL>
-->
</P>
<HR>
<P>
<DL>
<DT><H3>Development snapshot, version 0.2.7 :</H3></DT>
<DD>Enhancements towards stable version 0.2.6:
<DT><H3>Development snapshot, version 0.3.9 :</H3></DT>
<DD>Enhancements towards stable version 0.3.8.pl00:
<UL>
<LI>Improved recognition of unsuitable media types</LI>
<LI>Ban of chmod u+s is replaced by a loud warning</LI>
<LI>Detailed man page (already backported to cdrskin-0.2.6.pl02)</LI>
<LI>Burning to DVD+RW and DVD-RAM as non-multi, non-appending,
single-track session</LI>
<LI>Formatting and then burning to DVD-RW like to DVD+RW</LI>
<LI>Emulation of new wodim option msifile=path</LI>
<LI>none yet</LI>
</UL>
</DD>
<DD>&nbsp;</DD>
<DD><A HREF="README_cdrskin_devel">README 0.2.7</A>
<DD><A HREF="cdrskin__help_devel">cdrskin_0.2.7 --help</A></DD>
<DD><A HREF="cdrskin_help_devel">cdrskin_0.2.7 -help</A></DD>
<DD><A HREF="man_1_cdrskin_devel.html">man cdrskin (as of 0.2.7)</A></DD>
<DD><A HREF="README_cdrskin_devel">README 0.3.9</A>
<DD><A HREF="cdrskin__help_devel">cdrskin_0.3.9 --help</A></DD>
<DD><A HREF="cdrskin_help_devel">cdrskin_0.3.9 -help</A></DD>
<DD><A HREF="man_1_cdrskin_devel.html">man cdrskin (as of 0.3.9)</A></DD>
<DD>&nbsp;</DD>
<DT>Maintainers of cdrskin unstable packages please use SVN of
<A HREF="http://libburnia.pykix.org"> libburnia.pykix.org</A></DT>
@ -259,15 +273,15 @@ admins with full system souvereignty.</DT>
<A HREF="README_cdrskin_devel">upcoming README</A> ):
</DD>
<DD>
<A HREF="cdrskin-0.2.7.tar.gz">cdrskin-0.2.7.tar.gz</A>
(550 KB).
<A HREF="cdrskin-0.3.9.tar.gz">cdrskin-0.3.9.tar.gz</A>
(615 KB).
</DD>
<DD>Binary (untar and move to /usr/bin/cdrskin):</DD>
<DD><A HREF="cdrskin_0.2.7-x86-suse9_0.tar.gz">
cdrskin_0.2.7-x86-suse9_0.tar.gz</A>, (75 KB).
<DD><A HREF="cdrskin_0.3.9-x86-suse9_0.tar.gz">
cdrskin_0.3.9-x86-suse9_0.tar.gz</A>, (90 KB).
</DD>
<DD><A HREF="cdrskin_0.2.7-x86-suse9_0-static.tar.gz">
cdrskin_0.2.7-x86-suse9_0-static.tar.gz</A>, (275 KB)
<DD><A HREF="cdrskin_0.3.9-x86-suse9_0-static.tar.gz">
cdrskin_0.3.9-x86-suse9_0-static.tar.gz</A>, (290 KB)
</DD>
</DL>
</P>
@ -283,6 +297,10 @@ Historic versions based on Derek's and Ben's
<A HREF="http://icculus.org/burn">icculus.org/burn</A> :<BR>
<A HREF="cdrskin-0.1.2.0.2.ts.tar.gz">cdrskin-0.1.2.0.2.ts.tar.gz</A><BR>
<A HREF="cdrskin-0.1.3.0.2.ts.tar.gz">cdrskin-0.1.3.0.2.ts.tar.gz</A>
<BR>
Very special thanks to Andy Polyakov whose
<A HREF="http://fy.chalmers.se/~appro/linux/DVD+RW/tools">dvd+rw-tools</A>
provide libburn with invaluable examples on how to deal with DVD media.
</P>
<HR>
@ -291,13 +309,13 @@ Historic versions based on Derek's and Ben's
<P>
<DL>
<DT>Example for a setup of device permissions. To be done by the superuser:</DT>
<DT>(CD devices which offer no r-permission are invisible to normal users.)</DT>
<DT>(CD devices which offer no w-permission are not useable.)</DT>
<DT>(CD devices which offer no rw-permission are invisible to normal users.)
</DT>
<DD># <KBD><B>cdrskin --devices</B></KBD></DD>
<DD><KBD>...</KBD></DD>
<DD><KBD>0&nbsp; dev='/dev/sg0'&nbsp; rwrwr- :&nbsp; 'TEAC' 'CD-ROM CD-532S'</KBD></DD>
<DD><KBD>0&nbsp; dev='/dev/sr0'&nbsp; rwrwr- :&nbsp; 'TEAC' 'CD-ROM CD-532S'</KBD></DD>
<DD><KBD>1&nbsp; dev='/dev/hdc'&nbsp; rwrw-- :&nbsp; 'LITE-ON' 'LTR-48125S'</KBD></DD>
<DD># <KBD><B>chmod a+rw /dev/sg0 /dev/hdc</B></KBD></DD>
<DD># <KBD><B>chmod a+rw /dev/sr0 /dev/hdc</B></KBD></DD>
</DL>
</P>
@ -325,7 +343,7 @@ is a GUI frontend which uses cdrecord for CD burning.)
<DD><KBD>...</KBD></DD>
<DD><KBD>&nbsp;&nbsp;&nbsp; 1,0,0 &nbsp;&nbsp; 1)&nbsp; 'LITE-ON' 'LTR-48125S' '?' Removable CD-ROM</KBD></DD>
<DD>$ <KBD><B>export SCDBACKUP_SCSI_ADR="ATA:1,0,0"</B></KBD></DD>
<DD>$ <KBD><B>export SCDBACKUP_CDRECORD="cdrskin -v -v tao_to_sao_tsize=650m"</B></KBD></DD>
<DD>$ <KBD><B>export SCDBACKUP_CDRECORD="cdrskin -v -v"</B></KBD></DD>
<DD>$ <KBD><B>scdbackup_home</B></KBD></DD>
</DL>
<DL>
@ -334,7 +352,7 @@ is a GUI frontend which uses cdrecord for CD burning.)
<DD>$ <KBD><B>export SCDBACKUP_USE_CDRSKIN=1</B></KBD></DD>
<DD>$ <KBD><B>./CONFIGURE_CD</B></KBD></DD>
<DD><KBD>...</KBD></DD>
<DD><KBD>cdrskin 0.2.6 : limited cdrecord compatibility wrapper for libburn</KBD></DD>
<DD><KBD>cdrskin 0.3.8 : limited cdrecord compatibility wrapper for libburn</KBD></DD>
</DL>
If your system is stricken with some ill CD device then this can stall
and you will have to press <KBD>Ctrl+C</KBD> to abort.
@ -393,8 +411,8 @@ Contact me. Let's see what we can achieve.
<BR>
<BR>
libburn and cdrskin are now mature enough to substitute cdrecord in its
major use cases of CD burning. It is possible to foist cdrskin on various
software packages if it gets falsely named "cdrecord".
major use cases of CD and DVD burning. It is possible to foist cdrskin on
various software packages if it gets falsely named "cdrecord".
I do not encourage this approach, but of course such a replacement
opportunity is the goal of a cdrecord compatibility wrapper.
<BR>
@ -411,7 +429,7 @@ I owe him much. For cdrecord, for mkisofs, for star. Chapeau.
<BR><BR>
-->
<A HREF="http://en.wikipedia.org/wiki/D%C3%B6ner_kebab">
<IMG SRC="doener_150x200_tr.gif" BORDER=0
<IMG SRC="doener_150x200_tr.png" BORDER=0
ALT="cdrskin logo: Doener mit Scharf"></A>
<BR><BR>
<FONT SIZE=+0>Enjoying free Open Source hosting by <A HREF="http://www.webframe.org">www.webframe.org</A><BR>

View File

@ -1 +1 @@
#define Cdrskin_timestamP "2007.01.14.133951"
#define Cdrskin_timestamP "2007.07.20.120001"

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
debug_opts=
def_opts=
largefile_opts="-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1"
libvers="-DCdrskin_libburn_0_2_7"
libvers="-DCdrskin_libburn_0_3_8"
cleanup_src_or_obj="libburn/cleanup.o"
libdax_msgs_o="libburn/libdax_msgs.o"
libdax_audioxtr_o="libburn/libdax_audioxtr.o"
@ -33,15 +33,15 @@ do
libdax_audioxtr_o=
libdax_msgs_o="libburn/message.o"
cleanup_src_or_obj="-DCleanup_has_no_libburn_os_H cdrskin/cleanup.c"
elif test "$i" = "-libburn_0_2_6"
elif test "$i" = "-libburn_0_3_8"
then
libvers="-DCdrskin_libburn_0_2_6"
libvers="-DCdrskin_libburn_0_3_8"
libdax_audioxtr_o="libburn/libdax_audioxtr.o"
libdax_msgs_o="libburn/libdax_msgs.o"
cleanup_src_or_obj="libburn/cleanup.o"
elif test "$i" = "-libburn_svn"
then
libvers="-DCdrskin_libburn_0_2_7"
libvers="-DCdrskin_libburn_0_3_9"
libdax_audioxtr_o="libburn/libdax_audioxtr.o"
libdax_msgs_o="libburn/libdax_msgs.o"
cleanup_src_or_obj="libburn/cleanup.o"
@ -79,7 +79,7 @@ do
echo " -compile_cdrfifo compile program cdrskin/cdrfifo."
echo " -compile_dewav compile program test/dewav without libburn."
echo " -cvs_A60220 set macro to match libburn-CVS of 20 Feb 2006."
echo " -libburn_0_2_6 set macro to match libburn-0.2.6."
echo " -libburn_0_3_8 set macro to match libburn-0.3.8."
echo " -libburn_svn set macro to match current libburn-SVN."
echo " -no_largefile do not use 64 bit off_t (must match libburn)."
echo " -do_not_compile_cdrskin omit compilation of cdrskin/cdrskin."

View File

@ -43,11 +43,15 @@ then
-e 's/<h1 align=center>CDRSKIN<\/h1>/<h1 align=center>man 1 cdrskin<\/h1>/' \
-e 's/<body>/<body BGCOLOR="#F5DEB3" TEXT=#000000 LINK=#0000A0 VLINK=#800000>/' \
-e 's/<b>Overview of features:<\/b>/\&nbsp;<BR><b>Overview of features:<\/b>/' \
-e 's/<b>General information paragraphs:<\/b>/\&nbsp;<BR><b>General information paragraphs:<\/b>/' \
-e 's/<b>Track recording model:<\/b>/\&nbsp;<BR><b>Track recording model:<\/b>/' \
-e 's/In general there are two types of tracks: data and audio./\&nbsp;<BR>In general there are two types of tracks: data and audio./' \
-e 's/While audio tracks just contain a given/\&nbsp;<BR>While audio tracks just contain a given/' \
-e 's/<b>Write mode selection:<\/b>/\&nbsp;<BR><b>Write mode selection:<\/b>/' \
-e 's/<b>Recordable CD Media:<\/b>/\&nbsp;<BR><b>Recordable CD Media:<\/b>/' \
-e 's/<b>Recordable DVD Media:<\/b>/\&nbsp;<BR><b>Recordable DVD Media:<\/b>/' \
-e 's/<b>Overwriteable DVD Media:<\/b>/\&nbsp;<BR><b>Overwriteable DVD Media:<\/b>/' \
-e 's/<b>Sequentially Recordable DVD Media:<\/b>/\&nbsp;<BR><b>Sequentially Recordable DVD Media:<\/b>/' \
-e 's/The write modes for DVD+R/\&nbsp;<BR>The write modes for DVD+R/' \
-e 's/<b>Drive preparation and addressing:<\/b>/\&nbsp;<BR><b>Drive preparation and addressing:<\/b>/' \
-e 's/If you only got one CD capable drive/\&nbsp;<BR>If you only got one CD capable drive/' \
-e 's/^Alphabetical list of options/\&nbsp;<BR>Alphabetical list of options/' \
@ -59,7 +63,7 @@ then
chmod u+rw,go+r,go-w "$htmlpage"
echo "Emerged file:"
ls -l "$htmlpage"
ls -lL "$htmlpage"
else

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@ -1,14 +1,18 @@
--------------------------------------------------------------------------
cdrskin Wiki - plain text copy
--------------------------------------------------------------------------
[[Image(source:/libburn/trunk/cdrskin/doener_150x200_tr.gif)]] [http://en.wikipedia.org/wiki/D%C3%B6ner_kebab Doener]
[[Image(source:/libburn/trunk/cdrskin/doener_150x200_tr.png)]] [http://en.wikipedia.org/wiki/D%C3%B6ner_kebab Doener]
'''cdrskin is the cdrecord compatibility middleware of libburn.'''
Its paragon, cdrecord, is a powerful GPL'ed burn program included in Joerg
Schilling's cdrtools. cdrskin strives to be a second source for the services
traditionally provided by cdrecord. Currently it does CD-R and CD-RW.
Its future ability to burn DVD media depends on the development of libburn.
traditionally provided by cdrecord. Currently it does CD-R and CD-RW this way.
Overwriteable media DVD-RAM, DVD+RW and DVD-RW are handled differently than
with cdrecord-ProDVD in order to offer TAO-like single track recording.
Sequential DVD-R[W] and DVD+R are handled like CD-R[W] with TAO and
multi-session. Additionally cdrskin offers cdrecord-ProDVD-like mode DAO
with DVD-R[W].
cdrskin does not contain any bytes copied from cdrecord's sources.
Many bytes have been copied from the message output of cdrecord
@ -19,14 +23,9 @@ About libburn API for burning CD: http://libburnia-api.pykix.org
--------------------------------------------------------------------------
Appending sessions to an unclosed CD is restricted to write mode TAO.
(Users who have a burner which succeeds with a follow-up session via
cdrecord -sao : please contact us.)
The development version of cdrskin is able to burn a single track to DVD+RW
or DVD-RW media.
For other DVD types and for appending sessions to ISO filesystems see the
advise to use dvd+rw-tools at the end of this text.
For dual layer DVD types and for appending sessions to ISO filesystems on
DVD other than DVD-RW, DVD-R, DVD+R see the advise to use dvd+rw-tools at
the end of this text.
--------------------------------------------------------------------------
@ -68,7 +67,7 @@ and displays their detected properties.
The drives are listed one per line, with fields:
libburn-drive-number, sysadmin-device-file, permissions, vendor, type
{{{
0 dev='/dev/sg0' rwrw-- : 'HL-DT-ST' 'DVDRAM GSA-4082B'
0 dev='/dev/sr0' rwrw-- : 'HL-DT-ST' 'DVDRAM GSA-4082B'
}}}
This feature is valuable since cdrskin -scanbus will not give you
the device file name and its current permissions.
@ -83,20 +82,64 @@ has to offer both, r- and w-permission.
--------------------------------------------------------------------------
Non-cdrecord blank mode blank=format_overwrite is needed to bring a DVD-RW
The DVD capabilities of cdrskin differ from those of cdrecord-ProDVD. cdrskin
offers TAO-like multi-session with DVD-R[W], DVD+R and TAO-like single session
with overwriteable DVD media. It also offers DAO on DVD-R[W] which is probably
the same as the traditional cdrecord-ProDVD write mode.
Non-cdrecord blank mode blank=format_overwrite brings a DVD-RW
disc from its initial profile "Sequential Recording" into profile state
"Restricted Overwrite". The latter is usable with cdrskin.
"Restricted Overwrite".
{{{
cdrskin dev=/dev/sr0 -v blank=format_overwrite
}}}
DVD-RW "Restricted Overwrite" and DVD+RW appear to cdrskin as blank media
DVD-RAM, DVD+RW and overwriteable DVD-RW appear to cdrskin as blank media
which are capable of taking only a single track. This track may be positioned
on a 32KiB aligned address, though.
{{{
cdrskin ... write_start_address=2412m ...
}}}
Non-cdrecord blank mode blank=deformat_sequential brings an overwriteable
DVD-RW back into state "Sequential Recording" with the capability of doing
multi-session, if the drive is capable of "Incremental Streaming"
(MMC feature 21h).
Used sequential DVD-RW media may be blanked by blank=fast or blank=all which
normally both do full blanking.
blank=deformat_sequential does minimal blanking of DVD-RW which usually yields
media incapable of "Incremental Streaming".
Option --prodvd_cli_compatible activates blank=fast and blank=all for
overwriteable DVD-RW which normally ignore those two options. It also makes
option -multi tolerable with media and write modes which are not suitable for
multi-session. (The default behavior of cdrskin deems me to be preferrable.)
--------------------------------------------------------------------------
assert_write_lba=<lba> allows to ensure that the start block address which
was used with the formatter program (e.g. mkisofs -C) matches the start block
address which will be used by the upcoming burn.
E.g. cdrskin aborts with an error message if
{{{
assert_write_lba=0
}}}
is given but an appendable media is to be burned which would start at
block 68432.
An ISO-9660 file system image must be prepared according to a particular
block address on media. If the prepared address and the real address on media
do not match then the filesystem will not be mountable or may even cause system
trouble.
A sequential archive format like afio or star will not necessarily need such
a coordination of addresses. It might nevertheless be confusing to a reader
if the archive does not start at block 0.
--------------------------------------------------------------------------
fifo_start_at=<num> is a throughput enhancer for unsteady data streams
@ -154,21 +197,6 @@ $HOME/.cdrskinrc
--------------------------------------------------------------------------
tao_to_sao_tsize=<num> allows the - actually unsupported - cdrecord option
-tao and defines a default track size to be used if - as custom with -tao -
no option tsize=# is given.
Since -tao is supported in cdrskin-0.2.6 the TAO-to-SAO workaround has become
quite obsolete. Nevertheless, tao_to_sao_tsize= allows to preset a default
size for SAO mode which is in effect only if no track size is available.
As in general with cdrskin tsize=# the data source does not have to provide
the full annouced amount of data. Missing data will be padded up by 0-bytes.
Surplus data is supposed to cause an error, though. The burn will then
be a failure in any way.
--------------------------------------------------------------------------
dev_translation=<sep><from><sep><to> may be needed to foist cdrskin to
frontend programs of cdrecord which do *not* ask cdrecord -scanbus but
which make own assumptions and guesses about cdrecord's device addresses.
@ -200,9 +228,10 @@ for an illustrated example with K3b 0.10 .
DVD advise:
For burning of DVD media the cdrskin project currently advises to use
Andy Polyakov's dvd+rw-tools which despite their historic name burn
for me on above burner: DVD+RW, DVD+R, DVD-RW, DVD-R .
For burning of DVD media other than DVD-RAM, DVD+RW, DVD+R, DVD-RW, DVD-R,
the cdrskin project currently advises to use Andy Polyakov's dvd+rw-tools
which despite their historic name are capable of all the media above
and also do dual layer and even BD discs.
http://fy.chalmers.se/~appro/linux/DVD+RW/tools
@ -210,21 +239,19 @@ They are not compatible or related to cdrecord resp. cdrecord-ProDVD
(now obsoleted by original source cdrtools cdrecord with identical
capabilities besides the license key).
libburn and thus the cdrskin project are currently aquiring own capabilities
to burn to DVD media. For now restricted to DVD+RW and DVD-RW and to single
A special feature of dvd+rw-tools is growing of ISO-9660 filesystems on
overwriteable media. This is not the same as multi-session writing of cdrskin
with CD media, but retrieves additional information from the existing ISO
image and finally manipulates the start sectors of this existing image.
So for growable ISO filesystems on DVD-RAM or DVD+RW growisofs is the only
choice, currently.
cdrskin can offer DVD multi-session only with sequential DVD-R[W] and with
DVD+R.
Associated options blank=, -multi, -msinfo and -toc are available in this case.
Thus sequential DVD-RW behave much like large CD-RW with possibly more than 99
tracks.
To my knowledge, Linux kernels 2.6 do write to DVD+RW via block devices as
they would write to a traditional tape device. Try old tape archiver
commands with addresses like /dev/sr0 or /dev/hdc rather than /dev/mt0 .
I have heard rumors that DVD-RW in mode "restricted overwrite" would be
block device ready, too. My burner is not a real friend of DVD-RW and
in an experiment the burn worked fine - but the result was not identical
to the stream sent to the device. I had similar failure with DVD-RAM, too.
Beware of the impact of a slow block device on overall system i/o buffering.
It is wise to curb its input to a speed which it is able to deliver to media.
Else your i/o dedicated RAM might buffer a big amount of stream data.
--------------------------------------------------------------------------

View File

@ -1,4 +1,4 @@
AC_INIT([libburn], [0.2.7], [http://libburnia.pykix.org])
AC_INIT([libburn], [0.3.8], [http://libburnia.pykix.org])
AC_PREREQ([2.50])
dnl AC_CONFIG_HEADER([config.h])
@ -7,12 +7,6 @@ AC_CANONICAL_TARGET
AM_INIT_AUTOMAKE([subdir-objects])
dnl A61101 This breaks Linux build (makes 32 bit off_t)
dnl http://sourceware.org/autobook/autobook/autobook_96.html says
dnl one must include some config.h and this was a pitfall.
dnl So why dig the pit at all ?
dnl AM_CONFIG_HEADER(config.h)
dnl Making releases:
dnl BURN_MICRO_VERSION += 1;
dnl BURN_INTERFACE_AGE += 1;
@ -24,8 +18,8 @@ dnl
dnl if MAJOR or MINOR version changes, be sure to change AC_INIT above to match
dnl
BURN_MAJOR_VERSION=0
BURN_MINOR_VERSION=2
BURN_MICRO_VERSION=7
BURN_MINOR_VERSION=3
BURN_MICRO_VERSION=8
BURN_INTERFACE_AGE=0
BURN_BINARY_AGE=0
BURN_VERSION=$BURN_MAJOR_VERSION.$BURN_MINOR_VERSION.$BURN_MICRO_VERSION
@ -39,7 +33,7 @@ AC_SUBST(BURN_VERSION)
dnl Libtool versioning
LT_RELEASE=$BURN_MAJOR_VERSION.$BURN_MINOR_VERSION
LT_CURRENT=`expr $BURN_MICRO_VERSION - $BURN_INTERFACE_AGE`
LT_CURRENT=4
LT_REVISION=$BURN_INTERFACE_AGE
LT_AGE=`expr $BURN_BINARY_AGE - $BURN_INTERFACE_AGE`
LT_CURRENT_MINUS_AGE=`expr $LT_CURRENT - $LT_AGE`
@ -76,12 +70,6 @@ AC_PROG_INSTALL
AC_CHECK_HEADERS()
AC_CHECK_MEMBER([struct tm.tm_gmtoff],
[AC_DEFINE(HAVE_TM_GMTOFF, 1,
[Define this if tm structure includes a tm_gmtoff entry.])],
,
[#include <time.h>])
THREAD_LIBS=-lpthread
AC_SUBST(THREAD_LIBS)

View File

@ -6,9 +6,11 @@
@section intro Introduction
Libburnia is an open-source project for reading, mastering and writing
optical discs. For now this means only CD-R and CD-RW.
Support for DVD+RW and DVD-RW is emerging.
optical discs.
For now this means CD-R, CD-RW, DVD-RAM, DVD+RW, DVD+R, DVD-RW, DVD-R.
Not supported yet are dual layer media, HD-DVD, BD (blue ray). Testers for
dual layer DVD+/-R are wanted, though.
The project comprises of several more or less interdependent parts which
together strive to be a usable foundation for application development.
@ -20,9 +22,9 @@ we would need : login on a development machine resp. a live OS on CD or DVD,
advise from a system person about the equivalent of Linux sg or FreeBSD CAM,
volunteers for testing of realistic use cases.
We have a workable code base for burning data and audio CDs. The burn API is
quite comprehensively documented and can be used to build a presentable
application.
We have a workable code base for burning data and audio CDs and many DVD types.
The burn API is quite comprehensively documented and can be used to build a
presentable application.
We have a functional binary which emulates the core use cases of cdrecord in
order to prove that usability, and in order to allow you to explore libburn's
scope by help of existing cdrecord frontends.
@ -31,8 +33,11 @@ scope by help of existing cdrecord frontends.
- libburn is the library by which preformatted data get onto optical media.
It uses either /dev/sgN (e.g. on kernel 2.4 with ide-scsi) or
/dev/hdX (e.g. on kernel 2.6).
libburn is the foundation of our cdrecord emulation.
/dev/srM or /dev/hdX (e.g. on kernel 2.6).
libburn is the foundation of our cdrecord emulation. Its code is
independent of cdrecord. Its DVD capabilities are learned from
studying the code of dvd+rw-tools and MMC-5 specs. No code but only
the pure SCSI knowledge has been taken from dvd+rw-tools, though.
- libisofs is the library to pack up hard disk files and directories into a
ISO 9660 disk image. This may then be brought to CD via libburn.
@ -41,15 +46,18 @@ scope by help of existing cdrecord frontends.
- cdrskin is a limited cdrecord compatibility wrapper for libburn.
cdrecord is a powerful GPL'ed burn program included in Joerg
Schilling's cdrtools. cdrskin strives to be a second source for
the services traditionally provided by cdrecord.
the services traditionally provided by cdrecord. Additionally it
provides libburn's DVD capabilities, where only -sao is compatible
with cdrecord.
cdrskin does not contain any bytes copied from cdrecord's sources.
Many bytes have been copied from the message output of cdrecord
runs, though.
See cdrskin/README for more.
- "test" is a collection of application gestures and examples given by the
authors of the library features. The main API example of libburn
is named test/libburner.c .
authors of the library features. The burn API example of libburn
is named test/libburner.c . The API for media information inquiry is
demonstrated in test/telltoc.c .
Explore these examples if you look for inspiration.
We plan to be a responsive upstream. Bear with us.
@ -82,9 +90,8 @@ languages and development tools.
libburner is a minimal demo application for the library libburn
(see: libburn/libburn.h) as provided on http://libburn.pykix.org .
It can list the available devices, can blank a CD-RW and
can burn to CD-R or CD-RW.
New: burning to DVD+/-RW (single data track, single session only).
It can list the available devices, can blank a CD-RW or DVD-RW and
can burn to recordable CD and recordable single layer DVD.
It's main purpose, nevertheless, is to show you how to use libburn and also
to serve the libburnia team as reference application. libburner does indeed
@ -95,8 +102,9 @@ stay upward compatible for a good while.
<pre>
Usage: test/libburner
[--drive <address>|<driveno>|"-"] [--audio]
[--blank_fast|--blank_full] [--try_to_simulate]
[--multi] [one or more imagefiles|"-"]
[--blank_fast|--blank_full|--format_overwrite]
[--try_to_simulate]
[--multi] [<one or more imagefiles>|"-"]
Examples
A bus scan (needs rw-permissions to see a drive):
test/libburner --drive -
@ -106,22 +114,27 @@ Burn a file to drive chosen by persistent address, close:
test/libburner --drive /dev/hdc my_image_file
Blank a used CD-RW (is combinable with burning in one run):
test/libburner --drive /dev/hdc --blank_fast
Burn two audio tracks
Blank a used DVD-RW (is combinable with burning in one run):
test/libburner --drive /dev/hdc --blank_full
Format a DVD-RW to avoid need for blanking before re-use:
test/libburner --drive /dev/hdc --format_overwrite
Burn two audio tracks (to CD only):
lame --decode -t /path/to/track1.mp3 track1.cd
test/dewav /path/to/track2.wav -o track2.cd
test/libburner --drive /dev/hdc --audio track1.cd track2.cd
Burn a compressed afio archive on-the-fly:
( cd my_directory ; find . -print | afio -oZ - ) | \
test/libburner --drive /dev/hdc -
To be read from *not mounted* CD via: afio -tvZ /dev/hdc
Program tar would need a clean EOF which our padded CD cannot deliver.
To be read from *not mounted* media via: afio -tvZ /dev/hdc
</pre>
libburner has two companions, telltoc and dewav, which help to perform some
peripheral tasks of burning.
telltoc prints a table of content (sessions, tracks and leadouts), it tells
about type and state of CD media, and also is able to provide the necessary
multi-session information for program mkisofs option -C.
about type and state of media, and also is able to provide the necessary
multi-session information for program mkisofs option -C. Especially helpful
are its predictions with "Write multi" and "Write modes" where availability
of "TAO" indicates that tracks of unpredicted length can be written.
See: test/telltoc --help.
dewav extracts raw byte-swapped audio data from files of format .wav (MS WAVE)

1100
doc/cookbook.txt Normal file

File diff suppressed because it is too large Load Diff

388
doc/ddlp.txt Normal file
View File

@ -0,0 +1,388 @@
-------------------------------------------------------------------------------
Users of modern desktop Linux installations report misburns with CD/DVD
recording due to concurrency problems.
This text describes two locking protocols which have been developed by our
best possible effort. But finally they rather serve as repelling example of
what would be needed in user space to achieve an insufficient partial solution.
Ted Ts'o was so friendly to help as critic with his own use cases. It turned
out that we cannot imagine a way in user space how to cover reliably the needs
of callers of libblkid and the needs of our burn programs.
-------------------------------------------------------------------------------
Content:
The "Delicate Device Locking Protocol" shall demonstrate our sincere
consideration of the problem.
"What are the Stumble Stones ?" lists reasons why the effort finally failed.
-----------------------------------------------------------------------------
Delicate Device Locking Protocol
(a joint sub project of cdrkit and libburnia)
(contact: scdbackup@gmx.net )
Our projects provide programs which allow recording of data on CD or DVD.
We encounter an increasing number of bug reports about spoiled burn runs and
wasted media which obviously have one common cause: interference by other
programs which access the drive's device files.
There is some riddling about which gestures exactly are dangerous for
ongoing recordings or can cause weirdly misformatted drive replies to MMC
commands.
We do know, nevertheless, that these effects do not occur if no other program
accesses a device file of the drive while our programs use it.
DDLP shall help to avoid collisions between programs in the process of
recording to a CD or DVD drive and other programs which access that drive.
The protocol intends to provide advisory locking. So any good-willing program
has to take some extra precautions to participate.
If a program does not feel vulnerable to disturbance, then the precautions
impose much less effort than if the program feels the need for protection.
Two locking strategies are specified:
DDLP-A operates on device files only. It is very Linux specific.
DDLP-B adds proxy lock files, inspired by FHS /var/lock standard.
DDLP-A
This protocol relies on the hardly documented feature open(O_EXCL | O_RDWR)
with Linux device files and on POSIX compliant fcntl(F_SETLK).
Other than the original meaning of O_EXCL with creating regular files, the
effect on device files is mutual exclusion of access. I.e. if one
filedescriptor is open on that combination of major-minor device number, then
no other open(O_EXCL) will succeed. But open() without O_EXCL would succeed.
So this is advisory and exclusive locking.
With kernel 2.6 it seems to work on all device drivers which might get used
to access a CD/DVD drive.
The vulnerable programs shall not start their operation before they occupied a
wide collection of drive representations.
Non-vulnerable programs shall take care to detect the occupation of _one_ such
representation.
So for Friendly Programs
A program which does not feel vulnerable to disturbance is urged to access
CD/DVD drives by opening a file descriptor which will uphold the lock
as long as it does not get closed. There are two alternative ways to achieve
this.
Very reliable is
open( some_path , O_EXCL | ...)
But O_EXCL imposes restrictions and interferences:
- O_EXCL | O_RDONLY does not succeed with /dev/sg* !
- O_EXCL cannot provide shared locks for programs which only want to lock
against burn programs but not against their own peers.
- O_EXCL keeps from obtaining information by harmless activities.
- O_EXCL already has a meaning with devices which are mounted as filesystems.
This priority meaning is more liberal than the one needed for CD/DV recording
protection.
So it may be necessary to use a cautious open() without O_EXCL and to aquire
a POSIX lock via fcntl(). "Cautious" means to add O_NDELAY to the flags of
open(), because this is declared to avoid side effects within open().
With this gesture it is important to use the paths expected by our burn
programs: /dev/sr[0..255] /dev/scd[0..255] /dev/sg[0..255] /dev/hd[a..z]
because fcntl(F_SETLK) does not lock the device but only a device-inode.
std_path = one of the standard device files:
/dev/sr[0..255] /dev/scd[0..255] /dev/sg[0..255] /dev/hd[a..z]
or a symbolic link pointing to one of them.
open( std_path , ... | O_NDELAY)
fcntl(F_SETLK) and close() on failure
... eventually disable O_NDELAY by fcntl(F_SETFL) ...
There is a pitfall mentioned in man 2 fcntl :
"locks are automatically released [...] if it closes any file descriptor
referring to a file on which locks are held. This is bad [...]"
So you may have to re-lock after some temporary fd got closed.
Vulnerable Programs
For programs which do feel vulnerable, O_EXCL would suffice for the /dev/hd*
device file family and their driver. But USB and SATA recorders appear with
at least two different major-minor combinations simultaneously.
One as /dev/sr* alias /dev/scd*, the other as /dev/sg*.
The same is true for ide-scsi or recorders attached to SCSI controllers.
So, in order to lock any access to the recorder, one has to open(O_EXCL)
not only the device file that is intended for accessing the recorder but also
a device file of any other major-minor representation of the recorder.
This is done via the SCSI address parameter vector (Host,Channel,Id,Lun)
and a search on standard device file paths /dev/sr* /dev/scd* /dev/sg*.
In this text the alternative device representations are called "siblings".
For finding them, it is necessary to apply open() to many device files which
might be occupied by delicate operations. On the other hand it is very
important to occupy all reasonable representations of the drive.
So the reading of the (Host,Channel,Id,Lun) parameters demands an
open(O_RDONLY | O_NDELAY) _without_ fcntl() in order to find the outmost
number of representations among the standard device files. Only ioctls
SCSI_IOCTL_GET_IDLUN and SCSI_IOCTL_GET_BUS_NUMBER are applied.
Hopefully this gesture is unable to cause harmful side effects on kernel 2.6.
At least one file of each class sr, scd and sg should be found to regard
the occupation as satisfying. Thus corresponding sr-scd-sg triplets should have
matching ownerships and access permissions.
One will have to help the sysadmins to find those triplets.
A spicy detail is that sr and scd may be distinct device files for the same
major-minor combination. In this case fcntl() locks on both are needed
but O_EXCL can only be applied to one of them.
An open and free implementation ddlpa.[ch] is provided as
http://libburnia.pykix.org/browser/libburn/trunk/libburn/ddlpa.h?format=txt
http://libburnia.pykix.org/browser/libburn/trunk/libburn/ddlpa.c?format=txt
The current version of this text is
http://libburnia.pykix.org/browser/libburn/trunk/doc/ddlp.txt?format=txt
Put ddlpa.h and ddlpa.c into the same directory and compile as test program by
cc -g -Wall -DDDLPA_C_STANDALONE -o ddlpa ddlpa.c
Use it to occupy a drive's representations for a given number of seconds
./ddlpa /dev/sr0 300
It should do no harm to any of your running activities.
If it does: Please, please alert us.
Your own programs should not be able to circumvent the occupation if they
obey above rules for Friendly Programs.
Of course ./ddlpa should be unable to circumvent itself.
A successfull occupation looks like
DDLPA_DEBUG: ddlpa_std_by_rdev("/dev/scd0") = "/dev/sr0"
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/sr0"
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/scd0"
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/sg0"
DDLPA_DEBUG: ddlpa_occupy() : '/dev/scd0'
DDLPA_DEBUG: ddlpa_occupy() O_EXCL : '/dev/sg0'
DDLPA_DEBUG: ddlpa_occupy() O_EXCL : '/dev/sr0'
---------------------------------------------- Lock gained
ddlpa: opened /dev/sr0
ddlpa: opened siblings: /dev/scd0 /dev/sg0
slept 1 seconds of 300
Now an attempt via device file alias /dev/NEC must fail:
DDLPA_DEBUG: ddlpa_std_by_rdev("/dev/NEC") = "/dev/sg0"
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/sr0"
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/scd0"
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/sg0"
Cannot exclusively open '/dev/sg0'
Reason given : Failed to open O_RDWR | O_NDELAY | O_EXCL : '/dev/sr0'
Error condition : 16 'Device or resource busy'
With hdc, of course, things are trivial
DDLPA_DEBUG: ddlpa_std_by_rdev("/dev/hdc") = "/dev/hdc"
DDLPA_DEBUG: ddlpa_occupy() O_EXCL : '/dev/hdc'
---------------------------------------------- Lock gained
ddlpa: opened /dev/hdc
slept 1 seconds of 1
Ted Ts'o provided program open-cd-excl which allows to explore open(2) on
device files with combinations of read-write, O_EXCL, and fcntl().
(This does not mean that Ted endorsed our project yet. He helps exploring.)
Friendly in the sense of DDLP-A would be any run which uses at least one of
the options -e (i.e. O_EXCL) or -f (i.e. F_SETLK, applied to a file
descriptor which was obtained from a standard device file path).
The code is available under GPL at
http://libburnia.pykix.org/browser/libburn/trunk/test/open-cd-excl.c?format=txt
To be compiled by
cc -g -Wall -o open-cd-excl open-cd-excl.c
Options:
-e : open O_EXCL
-f : aquire lock by fcntl(F_SETLK) after sucessful open
-i : do not wait in case of success but exit 0 immediately
-r : open O_RDONLY , with -f use F_RDLCK
-w : open O_RDWR , with -f use F_WRLCK
plus the path of the devce file to open.
Friendly Programs would use gestures like:
./open-cd-excl -e -r /dev/sr0
./open-cd-excl -e -w /dev/sg1
./open-cd-excl -e -w /dev/black-drive
./open-cd-excl -f -r /dev/sg1
./open-cd-excl -e -f -w /dev/sr0
Ignorant programs would use and cause potential trouble by:
./open-cd-excl -r /dev/sr0
./open-cd-excl -w /dev/sg1
./open-cd-excl -f -w /dev/black-drive
where "/dev/black-drive" is _not_ a symbolic link to
any of /dev/sr* /dev/scd* /dev/sg* /dev/hd*, but has an own inode.
Prone to failure without further reason is:
./open-cd-excl -e -r /dev/sg1
----------------------------------------------------------------------------
DDLP-B
This protocol relies on proxy lock files in some filesystem directory. It can
be embedded into DDLP-A or it can be used be used standalone, outside DDLP-A.
DDLP-A shall be kept by DDLP-B from trying to access any device file which
might already be in use. There is a problematic gesture in DDLP-A when SCSI
address parameters are to be retrieved. For now this gesture seems to be
harmless. But one never knows.
Vice versa DDLP-B may get from DDLP-A the service to search for SCSI device
file siblings. So they are best as a couple.
But they are not perfect. Not even as couple. fcntl() locking is flawed.
There is a proxy file locking protocol described in FHS:
http://www.pathname.com/fhs/pub/fhs-2.3.html#VARLOCKLOCKFILES
But it has shortcommings (see below). Decisive obstacle for its usage are the
possibility for stale locks and the lack of shared locks.
DDLP-B rather defines a "path prefix" which is advised to be
/tmp/ddlpb-lock-
This prefix will get appended "device specific suffixes" and then form the path
of a "lockfile".
Not the existence of a lockfile but its occupation by an fcntl(F_SETLK) will
constitute a lock. Lockfiles may get prepared by the sysadmin in directories
where normal users are not allowed to create new files. Their rw-permissions
then act as additional access restriction to the device files.
The use of fcntl(F_SETLK) will prevent any stale locks after the process ended.
It will also allow to obtain shared locks as well as exclusive locks.
There are two classes of device specific suffixes:
- Device file path suffix. Absolute paths only. "/" gets replaced by "_-".
Eventual "_-" in path gets replaced by "_-_-". The leading group of "_-"
is always interpreted as a group of "/", though. E.g.:
/dev/sr0 <-> "_-dev_-sr0"
/mydevs/burner/nec <-> "_-mydevs_-burners_-nec"
/dev/rare_-name <-> "_-dev_-rare_-_-name"
///strange/dev/x <-> "_-_-_-strange_-dev_-x"
- st_rdev suffix. A hex representation of struct stat.st_rdev. Capital letters.
The number of characters is pare with at most one leading 0. I.e. bytewise
printf("%2.2X") beginning with the highest order byte that is not zero.
E.g. : "0B01", "2200", "01000000000004001"
If a lockfile does not exist and cannot be created then this shall not keep
a program from working on a device. But if a lockfile exists and if permissions
or locking state do not allow to obtain a lock of the appropirate type, then
this shall prevent any opening of device file in question resp. shall cause
immediate close(2) of an already opened device file.
The vulnerable programs shall not start their operation before they locked a
wide collection of drive representations.
Non-vulnerable programs shall take care to lock the suffix resulting from the
path they will be using and the suffix from the st_rdev from that path.
The latter is to be obtained by call stat(2).
Locks get upheld as long as their file descriptor is not closed or no other
incident as described in man 2 fcntl releases the lock.
So with shared locks there are no imandatory further activities after they
have been obtained.
In case of exclusive locks, the file has to have been opened for writing and
must be truncated to 0 bytes length immediately after obtaining the lock.
When releasing an exclusive lock it is a nice gesture to
already do this truncation.
Then a /var/lock/ compatible first line has to be written.
E.g. by: printf("%10u\n",(unsigned) getpid()) yielding " 1230\n".
Any further lines are optional. They shall have the form Name=Value and must
be printable cleartext. If such further lines exist, then the last one must
have the name "endmark".
Defined Names are:
hostid =hostname of the machine where the process number of line 1 is valid
start =start time of lock in seconds since 1970. E.g: 1177147634.592410
program =self chosen name of the program which obtained the lock
argv0 =argv[0] of that program
mainpath =device file path which will be used for operations by that program
path =device file path which lead to the lock
st_rdev =st_rdev suffix which is associated with path
scsi_hcil=eventual SCSI parameters Host,Channel,Id,Lun
scsi_bus =eventual SCSI parameter Bus
endmark =declares the info as complete.
Any undefined name or a line without "=" shall be handled as comment.
"=" in the value is allowed. Any line beginning with an "=" character is an
extension of the previous value.
If programs encounter an exclusive lock, they are invited to read the content
of the lockfile anyway. But they should be aware that the info might be in the
progress of emerging. There is a race condition possible in the short time
between obtaining the exclusive lock and erasing the file content.
If it is not crucial to obtain most accurate info then one may take the newline
of the first line as indicator of a valid process number and the "endmark"
name as indicator that the preceding lines are valid.
Very cautious readers should obtain the info twice with a decent waiting period
inbetween. Only if both results are identical they should be considered valid.
There is no implementation of DDLP-B yet.
----------------------------------------------------------------------------
What are the Stumble Stones ?
----------------------------------------------------------------------------
Any of the considered locking mechanisms has decisive shortcommings
which keeps it from being the solution to all known legitimate use cases.
The attempt has failed to compose a waterproof locking mechanism from means of
POSIX, FHS and from hardly documented Linux open(O_EXCL) on device files.
The resulting mechanisms would need about 1000 lines of code and still do
not close all gaps resp. cover the well motivated use cases.
This attempt you see above: DDLP-A and DDLP-B.
Summary of the reasons why the established locking mechanisms do not suffice:
None of the mechanisms can take care of the double device driver identity
sr versus sg. To deduce the one device file from the other involves the need
to open many other (possibly unrelated) device files with the risk to disturb
them.
This hard to solve problem is aggravated by the following facts.
Shortcommings of Linux specific open(O_EXCL) :
- O_EXCL | O_RDONLY does not succeed with /dev/sg*
- O_EXCL cannot provide shared locks for programs which only want to lock
against burn programs but not against their own peers.
- O_EXCL keeps from obtaining information by harmless activities.
- O_EXCL already has a meaning with devices which are mounted as filesystems.
This priority meaning is more liberal than the one needed for CD/DV recording
protection.
Shortcommings of POSIX fcntl(F_SETLK) :
- fcntl() demands an open file descriptor. open(2) might have side effects.
- fcntl() locks can be released inadvertedly by submodules which just open and
close the same file (inode ?) without refering to fcntl locks in any way.
See man 2 fcntl "This is bad:".
Stacking of software modules is a widely used design pattern. But fcntl()
cannot cope with that.
Shortcommings of FHS /var/lock/ :
- Stale locks are possible.
- It is necessary to create a file (using the _old_ meaning of O_EXCL flag ?)
but /var/lock/ might not be available early during system start and it often
has restrictive permission settings.
- There is no way to indicate a difference between exclusive and shared locks.
- The FHS prescription relies entirely on the basename of the device file path.

View File

@ -12,6 +12,7 @@
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/*
#include <a ssert.h>
@ -235,9 +236,18 @@ void burn_disc_erase(struct burn_drive *drive, int fast)
/* ts A70103 moved up from burn_disc_erase_sync() */
/* ts A60825 : allow on parole to blank appendable CDs */
if ( ! (drive->status == BURN_DISC_FULL ||
(drive->status == BURN_DISC_APPENDABLE &&
! libburn_back_hack_42) ) ) {
/* ts A70131 : allow blanking of overwriteable DVD-RW (profile 0x13) */
/* ts A70216 : allow blanking of CD-RW or DVD-RW in any regular state
and of any kind of full media */
if ((drive->current_profile != 0x0a &&
drive->current_profile != 0x13 &&
drive->current_profile != 0x14 &&
drive->status != BURN_DISC_FULL)
||
(drive->status != BURN_DISC_FULL &&
drive->status != BURN_DISC_APPENDABLE &&
drive->status != BURN_DISC_BLANK)
) {
libdax_msgs_submit(libdax_messenger, drive->global_index,
0x00020130,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
@ -323,6 +333,18 @@ static void *write_disc_worker_func(struct w_list *w)
void burn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc)
{
struct write_opts o;
char reasons[BURN_REASONS_LEN+80];
#ifndef Libburn_precheck_write_ruleS
int i, j, mode, mixed_mode = 0;
#endif
/* For the next lines any return indicates failure */
opts->drive->cancel = 1;
/* ts A70203 : people have been warned in API specs */
if (opts->write_type == BURN_WRITE_NONE)
return;
/* ts A61006 */
/* a ssert(!SCAN_GOING()); */
@ -343,9 +365,56 @@ void burn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc)
"Drive capabilities not inquired yet", 0, 0);
return;
}
/* ts A61009 : obsolete Assert in sector_headers() */
if (! burn_disc_write_is_ok(opts, disc)) /* issues own msgs */
/* ts A70219 : intended to replace all further tests here and many
tests in burn_*_write_sync()
*/
strcpy(reasons, "Write job parameters are unsuitable:\n");
if (burn_precheck_write(opts, disc, reasons + strlen(reasons), 1)
== BURN_WRITE_NONE) {
#ifndef Libburn_precheck_write_ruleS
libdax_msgs_submit(libdax_messenger,
opts->drive->global_index, 0x00020139,
LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH,
reasons, 0, 0);
#else
libdax_msgs_submit(libdax_messenger,
opts->drive->global_index, 0x00020139,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
reasons, 0, 0);
return;
#endif /* Libburn_precheck_write_ruleS */
}
#ifndef Libburn_precheck_write_ruleS
/* <<< covered burn_precheck_write() */
/* ts A61009 : obsolete Assert in sector_headers() */
if (! burn_disc_write_is_ok(opts, disc, 0)) /* issues own msgs */
return;
/* <<< covered burn_precheck_write() */
/* ts A70122 : libburn SAO code mishandles mode changes */
for (i = 0; i < disc->sessions; i++) {
if (disc->session[i]->tracks <= 0)
continue;
mode = disc->session[i]->track[0]->mode;
for (j = 1; j < disc->session[i]->tracks; j++)
if (mode != disc->session[i]->track[j]->mode)
mixed_mode = 1;
}
if (mixed_mode && opts->write_type == BURN_WRITE_SAO) {
libdax_msgs_submit(libdax_messenger,
opts->drive->global_index, 0x00020133,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
"Cannot mix data and audio in SAO mode", 0, 0);
return;
}
#endif /* ! Libburn_precheck_write_ruleS */
opts->drive->cancel = 0; /* End of the return = failure area */
o.drive = opts->drive;
o.opts = opts;

614
libburn/ddlpa.c Normal file
View File

@ -0,0 +1,614 @@
/* ddlpa
Implementation of Delicate Device Locking Protocol level A.
Copyright (C) 2007 Thomas Schmitt <scdbackup@gmx.net>
Provided under any of the following licenses: GPL, LGPL, BSD. Choose one.
Compile as test program:
cc -g -Wall \
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE \
-DDDLPA_C_STANDALONE -o ddlpa ddlpa.c
The system macros enable 64-bit off_t and open(2) flag O_LARGEFILE, which
are not absolutely necessary but explicitely take into respect that
our devices can offer more than 2 GB of addressable data.
Run test program:
./ddlpa /dev/sr0 15
./ddlpa 0,0,0 15
*/
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <scsi/scsi.h>
/* All callers of ddlpa must do this */
#include "ddlpa.h"
/* 1 = Enable progress message on stderr, 0 = normal silent operation */
static int ddlpa_debug_mode = 1;
/* #define _GNU_SOURCE or _LARGEFILE64_SOURCE to get real O_LARGEFILE */
#ifndef O_LARGEFILE
#define O_LARGEFILE 0
#endif
/* ----------------------- private -------------------- */
static int ddlpa_new(struct ddlpa_lock **lck, int o_flags, int ddlpa_flags)
{
int i;
struct ddlpa_lock *o;
o = *lck = (struct ddlpa_lock *) malloc(sizeof(struct ddlpa_lock));
if (o == NULL)
return ENOMEM;
for (i = 0; i < sizeof(struct ddlpa_lock); i++)
((char *) o)[i] = 0;
o->path = NULL;
o->fd = -1;
for (i = 0; i < DDLPA_MAX_SIBLINGS; i++)
o->sibling_fds[i] = -1;
o->errmsg = NULL;
o->o_flags = o_flags;
o->ddlpa_flags = ddlpa_flags;
return 0;
}
static int ddlpa_enumerate(struct ddlpa_lock *o, int *idx,
char path[DDLPA_MAX_STD_LEN + 1])
{
if (*idx < 0)
*idx = 0;
if (*idx < 26)
sprintf(path, "/dev/hd%c", 'a' + *idx);
else if (*idx < 256 + 26)
sprintf(path, "/dev/sr%d", *idx - 26);
else if (*idx < 2 * 256 + 26)
sprintf(path, "/dev/scd%d", *idx - 256 - 26);
else if (*idx < 3 * 256 + 26)
sprintf(path, "/dev/sg%d", *idx - 2 * 256 - 26);
else
return 1;
(*idx)++;
return 0;
}
static int ddlpa_std_by_rdev(struct ddlpa_lock *o)
{
int idx = 0;
char try_path[DDLPA_MAX_STD_LEN+1];
struct stat path_stbuf, try_stbuf;
if (!o->path_is_valid)
return EFAULT;
if (stat(o->path, &path_stbuf) == -1)
return errno;
while (ddlpa_enumerate(o, &idx, try_path) == 0) {
if (stat(try_path, &try_stbuf) == -1)
continue;
if (path_stbuf.st_rdev != try_stbuf.st_rdev)
continue;
strcpy(o->std_path, try_path);
if (ddlpa_debug_mode)
fprintf(stderr,
"DDLPA_DEBUG: ddlpa_std_by_rdev(\"%s\") = \"%s\"\n",
o->path, o->std_path);
return 0;
}
return ENOENT;
}
/* Caution : these tests are valid only with standard paths */
static int ddlpa_is_scsi(struct ddlpa_lock *o, char *path)
{
return (strncmp(path, "/dev/s", 6) == 0);
}
static int ddlpa_is_sg(struct ddlpa_lock *o, char *path)
{
return (strncmp(path, "/dev/sg", 7) == 0);
}
static int ddlpa_is_sr(struct ddlpa_lock *o, char *path)
{
return (strncmp(path, "/dev/sr", 7) == 0);
}
static int ddlpa_is_scd(struct ddlpa_lock *o, char *path)
{
return (strncmp(path, "/dev/scd", 8) == 0);
}
static int ddlpa_fcntl_lock(struct ddlpa_lock *o, int fd, int l_type)
{
struct flock lockthing;
int ret;
memset(&lockthing, 0, sizeof(lockthing));
lockthing.l_type = l_type;
lockthing.l_whence = SEEK_SET;
lockthing.l_start = 0;
lockthing.l_len = 0;
ret = fcntl(fd, F_SETLK, &lockthing);
if (ret == -1)
return EBUSY;
return 0;
}
static int ddlpa_occupy(struct ddlpa_lock *o, char *path, int *fd,
int no_o_excl)
{
int ret, o_flags, o_rw, l_type;
char *o_rwtext;
o_flags = o->o_flags | O_NDELAY;
if(!no_o_excl)
o_flags |= O_EXCL;
o_rw = (o_flags) & (O_RDONLY | O_WRONLY | O_RDWR);
o_rwtext = (o_rw == O_RDONLY ? "O_RDONLY" :
(o_rw == O_WRONLY ? "O_WRONLY" :
(o_rw == O_RDWR ? "O_RDWR " : "O_?rw-mode?")));
*fd = open(path, o_flags);
if (*fd == -1) {
o->errmsg = malloc(strlen(path)+160);
if (o->errmsg)
sprintf(o->errmsg,
"Failed to open %s | O_NDELAY %s: '%s'",
o_rwtext,
(o_flags & O_EXCL ? "| O_EXCL " : ""), path);
return (errno ? errno : EBUSY);
}
if (o_rw == O_RDWR || o_rw == O_WRONLY)
l_type = F_WRLCK;
else
l_type = F_RDLCK;
ret = ddlpa_fcntl_lock(o, *fd, l_type);
if (ret) {
o->errmsg = malloc(strlen(path)+160);
if (o->errmsg)
sprintf(o->errmsg,
"Failed to lock fcntl(F_WRLCK) : '%s'",path);
close(*fd);
*fd = -1;
return ret;
}
if (ddlpa_debug_mode)
fprintf(stderr, "DDLPA_DEBUG: ddlpa_occupy() %s %s: '%s'\n",
o_rwtext,
(no_o_excl ? " " : "O_EXCL "), path);
return 0;
}
static int ddlpa_obtain_scsi_adr(struct ddlpa_lock *o, char *path,
int *bus, int *host, int *channel, int *id, int *lun)
{
int fd, ret, open_mode = O_RDONLY | O_NDELAY;
struct my_scsi_idlun {
int x;
int host_unique_id;
};
struct my_scsi_idlun idlun;
fd = open(path, open_mode);
if (fd == -1)
return (errno ? errno : EBUSY);
if (ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, bus) == -1)
*bus = -1;
ret = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &idlun);
close(fd);
if (ret == -1)
return (errno ? errno : EIO);
*host = (idlun.x >> 24) & 255;
*channel = (idlun.x >> 16) & 255;
*id = (idlun.x) & 255;
*lun = (idlun.x >> 8 ) & 255;
return 0;
}
static int ddlpa_collect_siblings(struct ddlpa_lock *o)
{
int idx = 0, ret, have_sg = 0, have_sr = 0, have_scd = 0;
dev_t path_dev;
ino_t path_inode;
struct stat stbuf;
char *path, try_path[DDLPA_MAX_STD_LEN+1];
int t_bus, t_host, t_channel, t_id, t_lun;
if (o->ddlpa_flags & DDLPA_OPEN_GIVEN_PATH)
path = o->path;
else
path = o->std_path;
if (path[0] == 0 || o->num_siblings != 0)
return EFAULT;
if (!ddlpa_is_scsi(o, o->std_path))
return EFAULT;
if (stat(path, &stbuf) == -1)
return errno;
path_inode = stbuf.st_ino;
path_dev = stbuf.st_dev;
o->rdev = stbuf.st_rdev;
o->dev = stbuf.st_dev;
o->ino = stbuf.st_ino;
ret = ddlpa_obtain_scsi_adr(o, path,
&(o->bus), &(o->host), &(o->channel),
&(o->id), &(o->lun));
if (ret) {
o->errmsg = strdup(
"Cannot obtain SCSI parameters host,channel,id,lun");
return ret;
}
o->hcilb_is_valid = 1;
while (ddlpa_enumerate(o, &idx, try_path) == 0) {
if (!ddlpa_is_scsi(o, try_path))
continue;
if (stat(try_path, &stbuf) == -1)
continue;
ret = ddlpa_obtain_scsi_adr(o, try_path,
&t_bus, &t_host, &t_channel, &t_id, &t_lun);
if (ret) {
/* >>> interpret error, memorize busy, no permission */
continue;
}
if (t_host != o->host || t_channel != o->channel ||
t_id != o->id || t_lun != o->lun)
continue;
if (o->num_siblings >= DDLPA_MAX_SIBLINGS) {
o->errmsg =
strdup("Too many matching device files found");
return ERANGE;
}
if (ddlpa_is_sg(o, try_path))
have_sg = 1;
else if (ddlpa_is_sr(o, try_path))
have_sr = 1;
else if (ddlpa_is_scd(o, try_path))
have_scd = 1;
strcpy(o->sibling_paths[o->num_siblings], try_path);
o->sibling_rdevs[o->num_siblings] = stbuf.st_rdev;
o->sibling_devs[o->num_siblings] = stbuf.st_dev;
o->sibling_inodes[o->num_siblings] = stbuf.st_ino;
if (ddlpa_debug_mode)
fprintf(stderr,
"DDLPA_DEBUG: ddlpa_collect_siblings() found \"%s\"\n",
try_path);
(o->num_siblings)++;
}
if (have_sg && have_sr && have_scd)
return 0;
if (o->ddlpa_flags & DDLPA_ALLOW_MISSING_SGRCD)
return 0;
o->errmsg = strdup("Did not find enough siblings");
/* >>> add more info about busy and forbidden paths */
return EBUSY;
}
static int ddlpa_std_by_btl(struct ddlpa_lock *o)
{
int idx = 0, ret;
char try_path[DDLPA_MAX_STD_LEN+1];
int t_bus, t_host, t_channel, t_id, t_lun;
if (!o->inbtl_is_valid)
return EFAULT;
while (ddlpa_enumerate(o, &idx, try_path) == 0) {
if (!ddlpa_is_sr(o, try_path))
continue;
ret = ddlpa_obtain_scsi_adr(o, try_path,
&t_bus, &t_host, &t_channel, &t_id, &t_lun);
if (ret) {
/* >>> interpret error, memorize busy, no permission */
continue;
}
if (t_bus != o->in_bus || t_id != o->in_target ||
t_lun != o->in_lun)
continue;
strcpy(o->std_path, try_path);
if (ddlpa_debug_mode)
fprintf(stderr,
"DDLPA_DEBUG: ddlpa_std_by_btl(%d,%d,%d) = \"%s\"\n",
t_bus, t_id, t_lun, o->std_path);
return 0;
}
/* >>> add more info about busy and forbidden paths */
return ENOENT;
}
static int ddlpa_open_all(struct ddlpa_lock *o)
{
int i, j, ret, no_o_excl;
if (ddlpa_is_scsi(o, o->std_path)) {
ret = ddlpa_collect_siblings(o);
if (ret)
return ret;
for (i = 0; i < o->num_siblings; i++) {
/* Watch out for the main personality of the drive. */
/* No need to occupy identical path or softlink path */
if (o->sibling_devs[i] == o->dev &&
o->sibling_inodes[i] == o->ino)
continue;
/* There may be the same rdev but different inode. */
no_o_excl = (o->sibling_rdevs[i] == o->rdev);
/* Look for multiply registered device drivers with
distinct inodes. */
for (j = 0; j < i; j++) {
if (o->sibling_devs[j] == o->sibling_devs[i] &&
o->sibling_inodes[j] == o->sibling_inodes[i])
break;
if (o->sibling_rdevs[j] == o->sibling_rdevs[i])
no_o_excl = 1;
}
if (j < i)
continue; /* inode is already occupied */
ret = ddlpa_occupy(o, o->sibling_paths[i],
&(o->sibling_fds[i]), no_o_excl);
if (ret)
return ret;
}
}
if (o->ddlpa_flags & DDLPA_OPEN_GIVEN_PATH)
ret = ddlpa_occupy(o, o->path, &(o->fd), 0);
else
ret = ddlpa_occupy(o, o->std_path, &(o->fd), 0);
if (ret)
return ret;
/* >>> use fcntl() to adjust O_NONBLOCK */;
return 0;
}
/* ----------------------- public -------------------- */
int ddlpa_destroy(struct ddlpa_lock **lockbundle)
{
struct ddlpa_lock *o;
int i;
o= *lockbundle;
if (o == NULL)
return 0;
for (i = 0; i < o->num_siblings; i++)
if (o->sibling_fds[i] != -1)
close(o->sibling_fds[i]);
if(o->fd != -1)
close(o->fd);
if (o->path != NULL)
free(o->path);
if (o->errmsg != NULL)
free(o->errmsg);
free((char *) o);
*lockbundle = NULL;
return 0;
}
int ddlpa_lock_path(char *path, int o_flags, int ddlpa_flags,
struct ddlpa_lock **lockbundle, char **errmsg)
{
struct ddlpa_lock *o;
int ret;
*errmsg = NULL;
if (ddlpa_new(&o, o_flags, ddlpa_flags))
return ENOMEM;
*lockbundle = o;
o->path = strdup(path);
if (o->path == NULL)
return ENOMEM;
o->path_is_valid = 1;
ret = ddlpa_std_by_rdev(o);
if (ret) {
*errmsg = strdup(
"Cannot find equivalent of given path among standard paths");
return ret;
}
ret = ddlpa_open_all(o);
if (ret) {
*errmsg = o->errmsg;
o->errmsg = NULL;
ddlpa_destroy(&o);
}
return ret;
}
int ddlpa_lock_btl(int bus, int target, int lun,
int o_flags, int ddlpa_flags,
struct ddlpa_lock **lockbundle, char **errmsg)
{
struct ddlpa_lock *o;
int ret;
*errmsg = NULL;
ddlpa_flags &= ~DDLPA_OPEN_GIVEN_PATH;
if (ddlpa_new(&o, o_flags, ddlpa_flags))
return ENOMEM;
*lockbundle = o;
o->in_bus = bus;
o->in_target = target;
o->in_lun = lun;
o->inbtl_is_valid = 1;
ret = ddlpa_std_by_btl(o);
if (ret) {
*errmsg = strdup(
"Cannot find /dev/sr* with given Bus,Target,Lun");
return ret;
}
ret = ddlpa_open_all(o);
if (ret) {
*errmsg = o->errmsg;
o->errmsg = NULL;
ddlpa_destroy(&o);
return ret;
}
return 0;
}
#ifdef DDLPA_C_STANDALONE
/* ----------------------------- Test / Demo -------------------------- */
int main(int argc, char **argv)
{
struct ddlpa_lock *lck = NULL;
char *errmsg = NULL, *opened_path = NULL, *my_path = NULL;
int i, ret, fd = -1, duration = -1, bus = -1, target = -1, lun = -1;
if (argc < 3) {
usage:;
fprintf(stderr, "usage: %s device_path duration\n", argv[0]);
exit(1);
}
my_path = argv[1];
sscanf(argv[2], "%d", &duration);
if (duration < 0)
goto usage;
/* For our purpose, only O_RDWR is a suitable access mode.
But in order to allow experiments, o_flags are freely adjustable.
Warning: Do _not_ set an own O_EXCL flag with the following calls !
(This freedom to fail may get removed in a final version.)
*/
if (my_path[0] != '/' && my_path[0] != '.' &&
strchr(my_path, ',') != NULL) {
/*
cdrecord style dev=Bus,Target,Lun
*/
sscanf(my_path, "%d,%d,%d", &bus, &target, &lun);
ret = ddlpa_lock_btl(bus, target, lun, O_RDWR | O_LARGEFILE,
0, &lck, &errmsg);
} else {
/*
This substitutes for:
fd = open(my_path, O_RDWR | O_EXCL | O_LARGEFILE);
*/
ret = ddlpa_lock_path(my_path, O_RDWR | O_LARGEFILE,
0, &lck, &errmsg);
}
if (ret) {
fprintf(stderr, "Cannot exclusively open '%s'\n", my_path);
if (errmsg != NULL)
fprintf(stderr, "Reason given : %s\n",
errmsg);
free(errmsg);
fprintf(stderr, "Error condition : %d '%s'\n",
ret, strerror(ret));
exit(2);
}
fd = lck->fd;
printf("---------------------------------------------- Lock gained\n");
/* Use fd for the usual operations on the device depicted by my_path.
*/
/* This prints an overview of the impact of the lock */
if (lck->ddlpa_flags & DDLPA_OPEN_GIVEN_PATH)
opened_path = lck->path;
else
opened_path = lck->std_path;
printf("ddlpa: opened %s", opened_path);
if (strcmp(opened_path, lck->std_path) != 0)
printf(" (an alias of '%s')", lck->std_path);
printf("\n");
if (lck->num_siblings > 0) {
printf("ddlpa: opened siblings:");
for (i = 0; i < lck->num_siblings; i++)
if (lck->sibling_fds[i] != -1)
printf(" %s", lck->sibling_paths[i]);
printf("\n");
}
/* This example waits a while. So other lock candidates can collide. */
for (i = 0; i < duration; i++) {
sleep(1);
fprintf(stderr, "\rslept %d seconds of %d", i + 1, duration);
}
fprintf(stderr, "\n");
/* When finally done with the drive, this substitutes for:
close(fd);
*/
if (ddlpa_destroy(&lck)) {
/* Well, man 2 close says it can fail. */
exit(3);
}
exit(0);
}
#endif /* DDLPA_C_STANDALONE */

107
libburn/ddlpa.h Normal file
View File

@ -0,0 +1,107 @@
/* ddlpa
Implementation of Delicate Device Locking Protocol level A.
Copyright (C) 2007 Thomas Schmitt <scdbackup@gmx.net>
Provided under any of the following licenses: GPL, LGPL, BSD. Choose one.
See ../doc/ddlp.txt for a description of the protocol.
*/
#ifndef DDLPA_H_INCLUDED
#define DDLPA_H_INCLUDED 1
/* An upper limit for the length of standard paths and sibling paths */
#define DDLPA_MAX_STD_LEN 15
/* An upper limit for the number of siblings */
#define DDLPA_MAX_SIBLINGS 5
struct ddlpa_lock {
/* Recorded input parameters of locking call */
char *path;
int path_is_valid;
int in_bus, in_target, in_lun;
int inbtl_is_valid;
int ddlpa_flags;
int o_flags;
/* Result of locking call */
char std_path[DDLPA_MAX_STD_LEN + 1];
int fd;
dev_t rdev;
dev_t dev;
ino_t ino;
int host, channel, id, lun, bus;
int hcilb_is_valid;
int num_siblings;
char sibling_paths[DDLPA_MAX_SIBLINGS][DDLPA_MAX_STD_LEN + 1];
int sibling_fds[DDLPA_MAX_SIBLINGS];
dev_t sibling_rdevs[DDLPA_MAX_SIBLINGS];
dev_t sibling_devs[DDLPA_MAX_SIBLINGS];
ino_t sibling_inodes[DDLPA_MAX_SIBLINGS];
/* Is NULL if all goes well. Else it may contain a text message. */
char *errmsg;
};
/** Lock a recorder by naming a device file path. Allocate a new container.
@param path Gives the file system path of the recorder
as known to the calling program.
@param o_flags flags for open(2). Do not use O_EXCL here because this
is done automatically whenever appropriate.
Advised is O_RDWR | O_LARGEFILE, eventually | O_NDELAY.
@param ddlpa_flags 0 = default behavior: the standard path will be opened
and treated by fcntl(F_SETLK)
DDLPA_OPEN_GIVEN_PATH causes the input parameter "path"
to be used with open(2) and fcntl(2).
DDLPA_ALLOW_MISSING_SGRCD allows to grant a lock
although not all three, a sg, a sr and a scd device
file have been found during sibling search. Normally
this is counted as failure due to EBUSY.
@param lockbundle gets allocated and then represents the locking state
@param errmsg if *errmsg is not NULL after the call, it contains an
error message. Then to be released by free(3).
It is NULL in case of success or lack of memory.
@return 0=success , else an errno compatible error number
*/
int ddlpa_lock_path(char *path, int o_flags, int ddlpa_flags,
struct ddlpa_lock **lockbundle, char **errmsg);
/** Lock a recorder by naming a Bus,Target,Lun number triple.
Allocate a new container.
@param bus parameter to match ioctl(SCSI_IOCTL_GET_BUS_NUMBER)
@param target parameter to match ioctl(SCSI_IOCTL_GET_IDLUN) &0xff
@param lun parameter to match ioctl(SCSI_IOCTL_GET_IDLUN) &0xff00
@param o_flags see ddlpa_lock_path().
@param ddlpa_flags see ddlpa_lock_path(). Flag DDLPA_OPEN_GIVEN_PATH
will be ignored.
@param lockbundle see ddlpa_lock_path().
@param errmsg see ddlpa_lock_path().
@return 0=success , else an errno compatible error number
*/
int ddlpa_lock_btl(int bus, int target, int lun,
int o_flags, int ddlpa_flags,
struct ddlpa_lock **lockbundle, char **errmsg);
/** Release the lock by closing all filedescriptors and freeing memory.
@param lockbundle the lock which is to be released.
*lockbundle will be set to NULL by this call.
@return 0=success , 1=failure
*/
int ddlpa_destroy(struct ddlpa_lock **lockbundle);
/** Definitions of macros used in above functions */
#define DDLPA_OPEN_GIVEN_PATH 1
#define DDLPA_ALLOW_MISSING_SGRCD 2
#endif /* DDLPA_H_INCLUDED */

View File

@ -29,6 +29,12 @@
/* ts A70107 : to get BE_CANCELLED */
#include "error.h"
/* ts A70219 : for burn_disc_get_write_mode_demands() */
#include "options.h"
/* A70225 : to learn about eventual Libburn_dvd_r_dl_multi_no_close_sessioN */
#include "write.h"
#include "libdax_msgs.h"
extern struct libdax_msgs *libdax_messenger;
@ -200,6 +206,9 @@ int burn_drive_inquire_media(struct burn_drive *d)
} else {
if (d->current_profile == -1 || d->current_is_cd_profile)
d->read_toc(d);
/* ts A70314 */
d->status = BURN_DISC_UNSUITABLE;
}
return 1;
}
@ -347,6 +356,9 @@ int burn_drive_mark_unready(struct burn_drive *d)
/* ts A61202 */
d->current_profile = -1;
d->current_has_feat21h = 0;
d->current_feat2fh_byte4 = -1;
d->status = BURN_DISC_UNREADY;
if (d->toc_entry != NULL)
free(d->toc_entry);
@ -845,6 +857,35 @@ void burn_drive_set_speed(struct burn_drive *d, int r, int w)
d->set_speed(d, r, w);
}
/* ts A70711 API function */
int burn_drive_set_buffer_waiting(struct burn_drive *d, int enable,
int min_usec, int max_usec, int timeout_sec,
int min_percent, int max_percent)
{
if (enable >= 0)
d->wait_for_buffer_free = !!enable;
if (min_usec >= 0)
d->wfb_min_usec = min_usec;
if (max_usec >= 0)
d->wfb_max_usec = max_usec;
if (timeout_sec >= 0)
d->wfb_timeout_sec = timeout_sec;
if (min_percent >= 0) {
if (min_percent < 25 || min_percent > 100)
return 0;
d->wfb_min_percent = min_percent;
}
if (max_percent >= 0) {
if (max_percent < 25 || max_percent > 100)
return 0;
d->wfb_max_percent = max_percent;
}
return 1;
}
int burn_msf_to_sectors(int m, int s, int f)
{
return (m * 60 + s) * 75 + f;
@ -1010,7 +1051,6 @@ int burn_drive_is_enumerable_adr(char *adr)
#define BURN_DRIVE_MAX_LINK_DEPTH 20
/* ts A60922 ticket 33 */
/* Try to find an enumerated address with the given stat.st_rdev number */
int burn_drive_resolve_link(char *path, char adr[], int *recursion_count)
{
int ret;
@ -1399,13 +1439,64 @@ int burn_disc_track_lba_nwa(struct burn_drive *d, struct burn_write_opts *o,
0, 0);
return -1;
}
if (o!=NULL)
if (o != NULL)
d->send_write_parameters(d, o);
ret = d->get_nwa(d, trackno, lba, nwa);
return ret;
}
/* ts A70131 : new API function */
int burn_disc_get_msc1(struct burn_drive *d, int *start)
{
int ret, trackno;
if (burn_drive_is_released(d)) {
libdax_msgs_submit(libdax_messenger,
d->global_index, 0x0002011b,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
"Attempt to read track info from ungrabbed drive",
0, 0);
return -1;
}
if (d->busy != BURN_DRIVE_IDLE) {
libdax_msgs_submit(libdax_messenger,
d->global_index, 0x0002011c,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
"Attempt to read track info from busy drive",
0, 0);
return -1;
}
ret = d->read_multi_session_c1(d, &trackno, start);
return ret;
}
/* ts A70213 : new API function */
off_t burn_disc_available_space(struct burn_drive *d,
struct burn_write_opts *o)
{
int lba, nwa;
if (burn_drive_is_released(d))
goto ex;
if (d->busy != BURN_DRIVE_IDLE)
goto ex;
if (o != NULL)
d->send_write_parameters(d, o);
d->get_nwa(d, -1, &lba, &nwa);
ex:;
if (o != NULL) {
if (o->start_byte > 0) {
if (o->start_byte > d->media_capacity_remaining)
return 0;
return d->media_capacity_remaining - o->start_byte;
}
}
return d->media_capacity_remaining;
}
/* ts A61202 : New API function */
int burn_disc_get_profile(struct burn_drive *d, int *pno, char name[80])
{
@ -1523,9 +1614,265 @@ int burn_drive_get_speedlist(struct burn_drive *d,
}
/* ts A70713 : API function */
int burn_drive_get_best_speed(struct burn_drive *d, int speed_goal,
struct burn_speed_descriptor **best_descr, int flag)
{
struct burn_speed_descriptor *sd;
int best_speed = 0, best_lba = 0, source= 2, speed;
if (flag & 2)
source = -1;
if (speed_goal < 0)
best_speed = 2000000000;
*best_descr = NULL;
for (sd = d->mdata->speed_descriptors; sd != NULL; sd = sd->next) {
if (flag & 1)
speed = sd->read_speed;
else
speed = sd->write_speed;
if ((source >= 0 && sd->source != source) ||
speed <= 0)
continue;
if (speed_goal < 0) {
if (speed < best_speed) {
best_speed = speed;
*best_descr = sd;
}
} else if (speed_goal == 0) {
if ((source == 2 && sd->end_lba > best_lba) ||
((source !=2 || sd->end_lba == best_lba) &&
speed > best_speed)) {
best_lba = sd->end_lba;
best_speed = speed;
*best_descr = sd;
}
} else if (speed <= speed_goal) {
if (speed > best_speed) {
best_speed = speed;
*best_descr = sd;
}
}
}
if (d->current_is_cd_profile && *best_descr == NULL && ! (flag & 2))
/* Mode page 2Ah is deprecated in MMC-5 although all known
burners still support it with CD media. */
return burn_drive_get_best_speed(d, speed_goal, best_descr,
flag | 2);
return (*best_descr != NULL);
}
/* ts A61226 : API function */
int burn_drive_free_speedlist(struct burn_speed_descriptor **speed_list)
{
return burn_speed_descriptor_destroy(speed_list, 1);
}
/* ts A70203 : API function */
int burn_disc_get_multi_caps(struct burn_drive *d, enum burn_write_types wt,
struct burn_multi_caps **caps, int flag)
{
enum burn_disc_status s;
struct burn_multi_caps *o;
int status, num_formats, ret, type, i;
off_t size;
unsigned dummy;
*caps = NULL;
s = burn_disc_get_status(d);
if(s == BURN_DISC_UNGRABBED)
return -1;
*caps = o = (struct burn_multi_caps *)
malloc(sizeof(struct burn_multi_caps));
if(*caps == NULL)
return -1;
/* Default says nothing is available */
o->multi_session = o->multi_track = 0;
o-> start_adr = 0;
o->start_alignment = o->start_range_low = o->start_range_high = 0;
o->might_do_tao = o->might_do_sao = o->might_do_raw = 0;
o->advised_write_mode = BURN_WRITE_NONE;
o->selected_write_mode = wt;
o->current_profile = d->current_profile;
o->current_is_cd_profile = d->current_is_cd_profile;
o->might_simulate = 0;
if (s != BURN_DISC_BLANK && s != BURN_DISC_APPENDABLE) {
return 0;
} else if (s == BURN_DISC_APPENDABLE &&
(wt == BURN_WRITE_SAO || wt == BURN_WRITE_RAW)) {
return 0;
} else if (wt == BURN_WRITE_RAW && !d->current_is_cd_profile) {
return 0;
} else if (d->current_profile == 0x09 || d->current_profile == 0x0a) {
/* CD-R , CD-RW */
if (d->block_types[BURN_WRITE_TAO]) {
o->multi_session = o->multi_track = 1;
o->might_do_tao = 2;
if (o->advised_write_mode == BURN_WRITE_NONE)
o->advised_write_mode = BURN_WRITE_TAO;
}
if (d->block_types[BURN_WRITE_SAO]) {
o->multi_session = o->multi_track = 1;
o->might_do_sao = 1;
if (o->advised_write_mode == BURN_WRITE_NONE)
o->advised_write_mode = BURN_WRITE_SAO;
}
if (d->block_types[BURN_WRITE_RAW]) {
o->might_do_raw = 1;
if (o->advised_write_mode == BURN_WRITE_NONE)
o->advised_write_mode = BURN_WRITE_RAW;
}
if (wt == BURN_WRITE_RAW)
o->multi_session = o->multi_track = 0;
else if(wt == BURN_WRITE_NONE || wt == BURN_WRITE_SAO ||
wt == BURN_WRITE_TAO)
o->might_simulate = !!d->mdata->simulate;
} else if (d->current_profile == 0x11 || d->current_profile == 0x14 ||
d->current_profile == 0x15) {
/* DVD-R , sequential DVD-RW , DVD-R/DL Sequential */
if (s == BURN_DISC_BLANK) {
o->might_do_sao = 1;
o->advised_write_mode = BURN_WRITE_SAO;
}
if (d->current_has_feat21h) {
#ifndef Libburn_dvd_r_dl_multi_no_close_sessioN
if (d->current_profile != 0x15)
#endif
o->multi_session = 1;
o->multi_track = 1;
o->might_do_tao = 2;
o->advised_write_mode = BURN_WRITE_TAO;
}
if (wt == BURN_WRITE_SAO)
o->multi_session = o->multi_track = 0;
if (wt == BURN_WRITE_NONE || wt == BURN_WRITE_SAO ||
wt == BURN_WRITE_TAO)
o->might_simulate = 1;
} else if (d->current_profile == 0x12 || d->current_profile == 0x13 ||
d->current_profile == 0x1a) {
/* DVD-RAM, overwriteable DVD-RW, DVD+RW */
o->start_adr = 1;
ret = burn_disc_get_formats(d, &status, &size, &dummy,
&num_formats);
if (ret == 1) {
if (status == BURN_FORMAT_IS_FORMATTED)
o->start_range_high = size;
if (d->current_profile == 0x13) {
o->start_alignment = 32 * 1024;
for (i = 0; i < num_formats; i++) {
ret = burn_disc_get_format_descr(d, i,
&type, &size, &dummy);
if (ret <= 0)
continue;
if (type == 0x13) /* expandable */
break;
}
if (i >= num_formats) /* not expandable */
o->start_range_high -= 32 * 1024;
} else {
o->start_alignment = 2 * 1024;
if (d->best_format_size - 2048 >
o->start_range_high)
o->start_range_high =
d->best_format_size - 2048;
}
}
o->might_do_sao = 4;
o->might_do_tao = 2;
o->advised_write_mode = BURN_WRITE_TAO;
} else if (d->current_profile == 0x1b || d->current_profile == 0x2b) {
/* DVD+R , DVD+R/DL */
o->multi_session = o->multi_track = 1;
o->might_do_tao = 2;
o->might_do_sao = 1;
o->advised_write_mode = BURN_WRITE_TAO;
} else /* unknown media */
return 0;
if (s == BURN_DISC_APPENDABLE)
o->might_do_sao = o->might_do_raw = 0;
if (wt == BURN_WRITE_TAO && !o->might_do_tao)
return 0;
else if (wt == BURN_WRITE_SAO && !o->might_do_sao)
return 0;
else if (wt == BURN_WRITE_RAW && !o->might_do_raw)
return 0;
return 1;
}
/* ts A70203 : API function */
int burn_disc_free_multi_caps(struct burn_multi_caps **caps)
{
if (*caps == NULL)
return 0;
free((char *) *caps);
*caps = NULL;
return 1;
}
/* ts A70207 : evaluate write mode related peculiarities of a disc
@param flag bit0= fill_up_media is active
*/
int burn_disc_get_write_mode_demands(struct burn_disc *disc,
struct burn_write_opts *opts,
struct burn_disc_mode_demands *result, int flag)
{
struct burn_session *session;
struct burn_track *track;
int i, j, mode, unknown_track_sizes = 0, last_track_is_unknown = 0;
enum burn_disc_status s;
memset((char *) result, 0, sizeof(struct burn_disc_mode_demands));
if (disc == NULL)
return 2;
s = burn_disc_get_status(opts->drive);
if (s == BURN_DISC_APPENDABLE || disc->sessions > 1)
result->will_append = 1;
if (disc->sessions > 1)
result->multi_session = 1;
for (i = 0; i < disc->sessions; i++) {
session = disc->session[i];
if (session->tracks <= 0)
continue;
mode = session->track[0]->mode;
if (session->tracks > 1)
result->multi_track = 1;
for (j = 0; j < session->tracks; j++) {
track = session->track[j];
if (burn_track_is_open_ended(track)) {
if (burn_track_get_default_size(track) > 0) {
if (result->unknown_track_size == 0)
result->unknown_track_size = 2;
} else
result->unknown_track_size = 1;
unknown_track_sizes++;
last_track_is_unknown = 1;
} else
last_track_is_unknown = 0;
if (mode != track->mode)
result->mixed_mode = 1;
if (track->mode == BURN_MODE1) {
result->block_types |= BURN_BLOCK_MODE1;
} else if (track->mode == BURN_AUDIO) {
result->audio = 1;
result->block_types |= BURN_BLOCK_RAW0;
result->exotic_track = 1;
} else {
result->block_types |= opts->block_type;
result->exotic_track = 1;
}
}
}
if (flag&1) {/* fill_up_media will define the size of the last track */
if (unknown_track_sizes == 1 && last_track_is_unknown)
result->unknown_track_size = 0;
}
return (disc->sessions > 0);
}

View File

@ -95,4 +95,20 @@ int burn_mdata_free_subs(struct scsi_mode_data *m);
/* ts A61230 */
void burn_disc_format_sync(struct burn_drive *d, off_t size, int flag);
/* ts A70207 : evaluate write mode related peculiarities of a disc */
struct burn_disc_mode_demands {
int multi_session;
int multi_track;
int unknown_track_size; /* 0=known, 1=unknown, 2=unknown+defaulted */
int mixed_mode;
int audio;
int exotic_track;
int block_types;
int will_append; /* because of media state or multi session disc */
};
int burn_disc_get_write_mode_demands(struct burn_disc *disc,
struct burn_write_opts *opts,
struct burn_disc_mode_demands *result, int flag);
#endif /* __DRIVE */

View File

@ -42,7 +42,7 @@ static int file_read(struct burn_source *source,
unsigned char *buffer,
int size)
{
struct burn_source_fd *fs = source->data;
struct burn_source_file *fs = source->data;
return read_full_buffer(fs->datafd, buffer, size);
}
@ -71,14 +71,24 @@ static off_t file_size(struct burn_source *source)
struct stat buf;
struct burn_source_file *fs = source->data;
if (fs->fixed_size > 0)
return fs->fixed_size;
if (fstat(fs->datafd, &buf) == -1)
return (off_t) 0;
/* for now we keep it compatible to the old (int) return value */
if(buf.st_size >= 1308622848) /* 2 GB - 800 MB to prevent rollover */
return (off_t) 1308622848;
return (off_t) buf.st_size;
}
/* ts A70125 */
static int file_set_size(struct burn_source *source, off_t size)
{
struct burn_source_file *fs = source->data;
fs->fixed_size = size;
return 1;
}
struct burn_source *burn_file_source_new(const char *path, const char *subpath)
{
struct burn_source_file *fs;
@ -103,84 +113,43 @@ struct burn_source *burn_file_source_new(const char *path, const char *subpath)
if (subpath)
fs->subfd = fd2;
/* ts A70125 */
fs->fixed_size = 0;
src = burn_source_new();
src->read = file_read;
if (subpath)
src->read_sub = file_read_sub;
src->get_size = file_size;
src->set_size = file_set_size;
src->free_data = file_free;
src->data = fs;
return src;
}
/* ------ provisory location for the new source subclass fd --------- */
static off_t fd_get_size(struct burn_source *source)
{
struct stat buf;
struct burn_source_fd *fs = source->data;
if (fs->fixed_size > 0)
return fs->fixed_size;
if (fstat(fs->datafd, &buf) == -1)
return (off_t) 0;
/* for now we keep it compatible to the old (int) return value */
if (buf.st_size >= 1308622848) /* 2 GB - 800 MB to prevent rollover */
return (off_t) 1308622848;
return buf.st_size;
}
static int fd_read(struct burn_source *source,
unsigned char *buffer,
int size)
{
struct burn_source_fd *fs = source->data;
return read_full_buffer(fs->datafd, buffer, size);
}
static int fd_read_sub(struct burn_source *source,
unsigned char *buffer,
int size)
{
struct burn_source_fd *fs = source->data;
return read_full_buffer(fs->subfd, buffer, size);
}
static void fd_free_data(struct burn_source *source)
{
struct burn_source_fd *fs = source->data;
close(fs->datafd);
if (source->read_sub)
close(fs->subfd);
free(fs);
}
/* ts A70126 : removed class burn_source_fd in favor of burn_source_file */
struct burn_source *burn_fd_source_new(int datafd, int subfd, off_t size)
{
struct burn_source_fd *fs;
struct burn_source_file *fs;
struct burn_source *src;
if (datafd == -1)
return NULL;
fs = malloc(sizeof(struct burn_source_fd));
fs = malloc(sizeof(struct burn_source_file));
fs->datafd = datafd;
fs->subfd = subfd;
fs->fixed_size = size;
src = burn_source_new();
src->read = fd_read;
src->read = file_read;
if(subfd != -1)
src->read = fd_read_sub;
src->get_size = fd_get_size;
src->free_data = fd_free_data;
src->read = file_read_sub;
src->get_size = file_size;
src->set_size = file_set_size;
src->free_data = file_free;
src->data = fs;
return src;
}

View File

@ -4,19 +4,14 @@
#define BURN__FILE_H
struct burn_source_file
{
int datafd;
int subfd;
};
/* ------ provisory location for the new source subclass fd --------- */
struct burn_source_fd
{
int datafd;
int subfd;
off_t fixed_size;
};
/* ts A70126 : burn_source_file obsoleted burn_source_fd */
#endif /* LIBBURN__FILE_H */

View File

@ -26,9 +26,22 @@ struct libdax_msgs *libdax_messenger= NULL;
int burn_running = 0;
/* ts A60813 : wether to use O_EXCL and/or O_NONBLOCK in libburn/sg.c */
/* ts A60813 : Linux: wether to use O_EXCL on open() of device files */
int burn_sg_open_o_excl = 1;
/* ts A70403 : Linux: wether to use fcntl(,F_SETLK,)
after open() of device files */
int burn_sg_fcntl_f_setlk = 1;
/* ts A70314 : Linux: what device family to use :
0= default family
1= sr
2= scd
(3= st)
4= sg
*/
int burn_sg_use_family = 0;
/* O_NONBLOCK was hardcoded in enumerate_ata() which i hardly use.
For enumerate_sg() it seems ok.
So it should stay default mode until enumerate_ata() without O_NONBLOCK
@ -50,6 +63,10 @@ static char abort_message_prefix[81] = {"libburn : "};
static pid_t abort_control_pid= 0;
/* ts A70223 : wether implemented untested profiles are supported */
int burn_support_untested_profiles = 0;
/* ts A60925 : ticket 74 */
/** Create the messenger object for libburn. */
int burn_msgs_initialize(void)
@ -73,6 +90,7 @@ int burn_initialize(void)
if (burn_running)
return 1;
burn_support_untested_profiles = 0;
ret = burn_msgs_initialize();
if (ret <= 0)
return 0;
@ -114,10 +132,11 @@ void burn_preset_device_open(int exclusive, int blocking, int abort_on_busy)
/* a ssert(burn_running); */
if (!burn_running)
return;
burn_sg_open_o_excl= exclusive;
burn_sg_open_o_nonblock= !blocking;
burn_sg_open_abort_busy= !!abort_on_busy;
burn_sg_open_o_excl = exclusive & 3;
burn_sg_fcntl_f_setlk = !!(exclusive & 32);
burn_sg_use_family = (exclusive >> 2) & 7;
burn_sg_open_o_nonblock = !blocking;
burn_sg_open_abort_busy = !!abort_on_busy;
}
@ -274,3 +293,10 @@ void burn_set_signal_handling(void *handle, burn_abort_handler_t handler,
Cleanup_set_handlers(handle, (Cleanup_app_handler_T) handler, mode|4);
}
/* ts A70223 : API */
void burn_allow_untested_profiles(int yes)
{
burn_support_untested_profiles = !!yes;
}

View File

@ -107,22 +107,40 @@ struct burn_write_opts;
enum burn_write_types
{
/** Packet writing.
currently unsupported
currently unsupported, (for DVD Incremental Streaming use TAO)
*/
BURN_WRITE_PACKET,
/** Track At Once recording.
2s gaps between tracks, no fonky lead-ins
/** With CD: Track At Once recording
2s gaps between tracks, no fonky lead-ins
With sequential DVD-R[W]: Incremental Streaming
With DVD-RAM/+RW: Random Writeable (used sequentially)
With overwriteable DVD-RW: Rigid Restricted Overwrite
*/
BURN_WRITE_TAO,
/** Session At Once.
block type MUST be BURN_BLOCK_SAO
/** With CD: Session At Once
Block type MUST be BURN_BLOCK_SAO
ts A70122: Currently not capable of mixing data and audio tracks.
With sequential DVD-R[W]: Disc-at-once, DAO
Single session, single track, fixed size mandatory, (-dvd-compat)
*/
BURN_WRITE_SAO,
/** Raw disc at once recording.
all subcodes must be provided by lib or user
only raw block types are supported
/** With CD: Raw disc at once recording.
all subcodes must be provided by lib or user
only raw block types are supported
*/
BURN_WRITE_RAW
BURN_WRITE_RAW,
/** In replies this indicates that not any writing will work.
As parameter for inquiries it indicates that no particular write
mode shall is specified.
Do not use for setting a write mode for burning. It won't work.
*/
BURN_WRITE_NONE
};
/** Data format to send to the drive */
@ -237,9 +255,18 @@ enum burn_drive_status
};
/** Information about a track on a disc - this is from the q sub channel of the
lead-in area of a disc. The documentation here is very terse.
See a document such as mmc3 for proper information.
CAUTION : This structure is prone to future extension !
Do not restrict your application to unsigned char with any counter like
"session", "point", "pmin", ...
Do not rely on the current size of a burn_toc_entry.
ts A70201 : DVD extension, see below
*/
struct burn_toc_entry
{
@ -263,6 +290,23 @@ struct burn_toc_entry
unsigned char psec;
/** Track start time frames for normal tracks */
unsigned char pframe;
/* Indicates wether extension data are valid and eventually override
older elements in this structure:
bit0= DVD extension is valid
*/
unsigned char extensions_valid;
/* ts A70201 : DVD extension.
If invalid the members are guaranteed to be 0. */
/* Tracks and session numbers are 16 bit. Here are the high bytes. */
unsigned char session_msb;
unsigned char point_msb;
/* pmin, psec, and pframe may be too small if DVD extension is valid */
int start_lba;
/* min, sec, and frame may be too small if DVD extension is valid */
int track_blocks;
};
@ -286,6 +330,9 @@ struct burn_source {
/** Get the size of the source's data */
off_t (*get_size)(struct burn_source *);
/** Set the size of the source's data */
int (*set_size)(struct burn_source *source, off_t size);
/** Clean up the source specific data */
void (*free_data)(struct burn_source *);
@ -408,8 +455,9 @@ struct burn_progress {
/* ts A61119 */
/** The number of bytes sent to the drive buffer */
off_t buffered_bytes;
/** The minimum number of buffered bytes. (Caution: Before surely
one buffer size of bytes was processed, this value is 0xffffffff.)
/** The minimum number of bytes stored in buffer during write.
(Caution: Before surely one buffer size of bytes was processed,
this value is 0xffffffff.)
*/
unsigned buffer_min_fill;
};
@ -525,13 +573,22 @@ void burn_set_verbosity(int level);
after burn_initialize() and before any bus scan. But not mandatory at all.
Parameter value 1 enables a feature, 0 disables.
Default is (1,0,0). Have a good reason before you change it.
@param exclusive 1 = Try to open only devices which are not marked as busy
@param exclusive Linux only:
0 = no attempt to make drive access exclusive.
1 = Try to open only devices which are not marked as busy
and try to mark them busy if opened sucessfully. (O_EXCL)
There are kernels which simply don't care about O_EXCL.
Some have it off, some have it on, some are switchable.
2 = in case of a SCSI device, also try to open exclusively
the matching /dev/sr, /dev/scd and /dev/st .
0 = no attempt to make drive access exclusive.
the matching /dev/sr, /dev/scd and /dev/st .
One may select a device SCSI file family by adding
0 = default family
4 = /dev/sr%d
8 = /dev/scd%d
16 = /dev/sg%d
Do not use other values !
Add 32 to demand an exclusive lock by fcntl(,F_SETLK,)
after open() has succeeded.
@param blocking Try to wait for drives which do not open immediately but
also do not return an error as well. (O_NONBLOCK)
This might stall indefinitely with /dev/hdX hard disks.
@ -542,6 +599,19 @@ void burn_set_verbosity(int level);
void burn_preset_device_open(int exclusive, int blocking, int abort_on_busy);
/* ts A70223 */
/** Allows the use of media types which are implemented in libburn but not yet
tested. The list of those untested profiles is subject to change.
Currently it contains: 0x15 "DVD-R/DL Sequential".
If you really test such media, then please report the outcome on
libburn-hackers@pykix.org
If ever then this call should be done soon after burn_initialize() before
any drive scanning.
@param yes 1=allow all implemented profiles, 0=only tested media (default)
*/
void burn_allow_untested_profiles(int yes);
/* ts A60823 */
/** Aquire a drive with known persistent address.This is the sysadmin friendly
way to open one drive and to leave all others untouched. It bundles
@ -627,7 +697,9 @@ int burn_drive_scan(struct burn_drive_info *drive_infos[],
int burn_drive_info_forget(struct burn_drive_info *drive_info, int force);
/** Free a burn_drive_info array returned by burn_drive_scan
/** When no longer needed, free a whole burn_drive_info array which was
returned by burn_drive_scan().
For freeing single drive array elements use burn_drive_info_forget().
*/
void burn_drive_info_free(struct burn_drive_info drive_infos[]);
@ -703,8 +775,8 @@ int burn_drive_grab(struct burn_drive *drive, int load);
/** Release a drive. This should not be done until the drive is no longer
busy (see burn_drive_get_status). The drive is (O_EXCL) unlocked
afterwards.
busy (see burn_drive_get_status).
Linux: The drive is unlocked afterwards. (O_EXCL , F_SETLK).
@param drive The drive to release.
@param eject Nonzero to make the drive eject the disc in it.
*/
@ -781,11 +853,42 @@ int burn_drive_get_start_end_lba(struct burn_drive *drive,
int burn_disc_track_lba_nwa(struct burn_drive *d, struct burn_write_opts *o,
int trackno, int *lba, int *nwa);
/* ts A70131 */
/** Read start lba of the first track in the last complete session.
This is the first parameter of mkisofs option -C. The second parameter
is nwa as obtained by burn_disc_track_lba_nwa() with trackno 0.
@param d The drive to query.
@param start_lba returns the start address of that track
@return <= 0 : failure, 1 = ok
*/
int burn_disc_get_msc1(struct burn_drive *d, int *start_lba);
/* ts A70213 */
/** Return the best possible estimation of the currently available capacity of
the media. This might depend on particular write option settings. For
inquiring the space with such a set of options, the drive has to be
grabbed and BURN_DRIVE_IDLE. If not, then one will only get a canned value
from the most recent automatic inquiry (e.g. during last drive grabbing).
An eventual start address from burn_write_opts_set_start_byte() will be
subtracted from the obtained capacity estimation. Negative results get
defaulted to 0.
@param d The drive to query.
@param o If not NULL: write parameters to be set on drive before query
@return number of most probably available free bytes
*/
off_t burn_disc_available_space(struct burn_drive *d,
struct burn_write_opts *o);
/* ts A61202 */
/** Tells the MMC Profile identifier of the loaded media. The drive must be
grabbed in order to get a non-zero result.
libburn currently writes only to profiles 0x09 "CD-R", 0x0a "CD-RW",
0x12 "DVD-RAM", 0x13 "DVD-RW restricted overwrite" or 0x1a "DVD+RW".
0x11 "DVD-R", 0x12 "DVD-RAM", 0x13 "DVD-RW restricted overwrite",
0x14 "DVD-RW Sequential Recording" or 0x1a "DVD+RW".
If enabled by burn_allow_untested_profiles() it also writes to profile
0x15 "DVD-R/DL Sequential Recording".
@param d The drive where the media is inserted.
@param pno Profile Number as of mmc5r03c.pdf, table 89
@param name Profile Name (e.g "CD-RW", unknown profiles have empty name)
@ -838,6 +941,7 @@ void burn_read_opts_free(struct burn_read_opts *opts);
@param drive The drive with which to erase a disc.
@param fast Nonzero to do a fast erase, where only the disc's headers are
erased; zero to erase the entire disc.
With DVD-RW, fast blanking yields media capable only of DAO.
*/
void burn_disc_erase(struct burn_drive *drive, int fast);
@ -922,9 +1026,38 @@ int burn_disc_get_format_descr(struct burn_drive *drive, int index,
*/
void burn_disc_read(struct burn_drive *drive, const struct burn_read_opts *o);
/* ts A70222 */
/** The length of a rejection reasons string for burn_precheck_write() and
burn_write_opts_auto_write_type() .
*/
#define BURN_REASONS_LEN 4096
/* ts A70219 */
/** Examines a completed setup for burn_disc_write() wether it is permissible
with drive and media. This function is called by burn_disc_write() but
an application might be interested in this check in advance.
@param o The options for the writing operation.
@param disc The descrition of the disc to be created
@param reasons Eventually returns a list of rejection reason statements
@param silent 1= do not issue error messages , 0= report problems
@return 1 ok, -1= no recordable media detected, 0= other failure
*/
int burn_precheck_write(struct burn_write_opts *o, struct burn_disc *disc,
char reasons[BURN_REASONS_LEN], int silent);
/* <<< enabling switch for internal usage and trust in this function */
#define Libburn_precheck_write_ruleS 1
/** Write a disc in the drive. The drive must be grabbed successfully before
calling this function. Always ensure that the drive reports a status of
BURN_DISC_BLANK before calling this function.
BURN_DISC_BLANK ot BURN_DISC_APPENDABLE before calling this function.
Note: write_type BURN_WRITE_SAO is currently not capable of writing a mix
of data and audio tracks. You must use BURN_WRITE_TAO for such sessions.
To be set by burn_write_opts_set_write_type().
@param o The options for the writing operation.
@param disc The struct burn_disc * that described the disc to be created
*/
@ -980,7 +1113,7 @@ int burn_msf_to_lba(int m, int s, int f);
*/
void burn_lba_to_msf(int lba, int *m, int *s, int *f);
/** Create a new disc (for DAO recording)*/
/** Create a new disc */
struct burn_disc *burn_disc_create(void);
/** Delete disc and decrease the reference count on all its sessions
@ -988,9 +1121,7 @@ struct burn_disc *burn_disc_create(void);
*/
void burn_disc_free(struct burn_disc *d);
/** Create a new session (For SAO at once recording, or to be added to a
disc for DAO)
*/
/** Create a new session */
struct burn_session *burn_session_create(void);
/** Free a session (and decrease reference count on all tracks inside)
@ -1101,6 +1232,19 @@ struct burn_disc *burn_drive_get_disc(struct burn_drive *d);
enum burn_source_status burn_track_set_source(struct burn_track *t,
struct burn_source *s);
/* ts A70218 */
/** Set a default track size to be used only if the track turns out to be of
unpredictable length and if the effective write type demands a fixed size.
This can be useful to enable write types CD SAO or DVD DAO together with
a track source like stdin. If the track source delivers fewer bytes than
announced then the track will be padded up with zeros.
@param t The track to change
@param size The size to set
@return 0=failure 1=sucess
*/
int burn_track_set_default_size(struct burn_track *t, off_t size);
/** Free a burn_source (decrease its refcount and maybe free it)
@param s Source to free
*/
@ -1120,6 +1264,17 @@ struct burn_source *burn_file_source_new(const char *path,
*/
struct burn_source *burn_fd_source_new(int datafd, int subfd, off_t size);
/* ts A70328 */
/** Sets a fixed track size after the data source object has already been
created.
@param t The track to poperate on
@param size the number of bytes to use as track size
@return <=0 indicates failure , >0 success
*/
int burn_track_set_size(struct burn_track *t, off_t size);
/** Tells how long a track will be on disc
>>> NOTE: Not reliable with tracks of undefined length
*/
@ -1134,18 +1289,59 @@ int burn_track_get_counters(struct burn_track *t,
/** Sets drive read and write speed
Note: "k" is 1000, not 1024. 1xCD = 176.4 k/s, 1xDVD = 1385 k/s.
Fractional speeds should be rounded up. Like 4xCD = 706.
@param d The drive to set speed for
@param read Read speed in k/s (0 is max)
@param write Write speed in k/s (0 is max)
@param read Read speed in k/s (0 is max, -1 is min).
@param write Write speed in k/s (0 is max, -1 is min).
*/
void burn_drive_set_speed(struct burn_drive *d, int read, int write);
/* ts A70711 */
/** Controls the behavior with writing when the drive buffer is suspected to
be full. To check and wait for enough free buffer space before writing
will move the task of waiting from the operating system's device driver
to libburn. While writing is going on and waiting is enabled, any write
operation will be checked wether it will fill the drive buffer up to
more than max_percent. If so, then waiting will happen until the buffer
fill is predicted with at most min_percent.
Thus: if min_percent < max_percent then transfer rate will oscillate.
This may allow the driver to operate on other devices, e.g. a disk from
which to read the input for writing. On the other hand, this checking might
reduce maximum throughput to the drive or even get misled by faulty buffer
fill replies from the drive.
If a setting parameter is < 0, then this setting will stay unchanged
by the call.
Known burner or media specific pitfalls:
To have max_percent larger than the burner's best reported buffer fill has
the same effect as min_percent==max_percent. Some burners do not report
their full buffer with all media types. Some are not suitable because
they report their buffer fill with delay.
@param d The drive to control
@param enable 0= disable , 1= enable waiting , (-1 = do not change setting)
@param min_usec Shortest possible sleeping period (given in micro seconds)
@param max_usec Longest possible sleeping period (given in micro seconds)
@param timeout_sec If a single write has to wait longer than this number
of seconds, then waiting gets disabled and mindless
writing starts. A value of 0 disables this timeout.
@param min_percent Minimum of desired buffer oscillation: 25 to 100
@param max_percent Maximum of desired buffer oscillation: 25 to 100
@return 1=success , 0=failure
*/
int burn_drive_set_buffer_waiting(struct burn_drive *d, int enable,
int min_usec, int max_usec, int timeout_sec,
int min_percent, int max_percent);
/* these are for my debugging, they will disappear */
void burn_structure_print_disc(struct burn_disc *d);
void burn_structure_print_session(struct burn_session *s);
void burn_structure_print_track(struct burn_track *t);
/** Sets the write type for the write_opts struct
/** Sets the write type for the write_opts struct.
Note: write_type BURN_WRITE_SAO is currently not capable of writing a mix
of data and audio tracks. You must use BURN_WRITE_TAO for such sessions.
@param opts The write opts to change
@param write_type The write type to use
@param block_type The block type to use
@ -1155,6 +1351,26 @@ int burn_write_opts_set_write_type(struct burn_write_opts *opts,
enum burn_write_types write_type,
int block_type);
/* ts A70207 */
/** As an alternative to burn_write_opts_set_write_type() this function tries
to find a suitable write type and block type for a given write job
described by opts and disc. To be used after all other setups have been
made, i.e. immediately before burn_disc_write().
@param opts The nearly complete write opts to change
@param disc The already composed session and track model
@param reasons This text string collects reasons for decision resp. failure
@param flag Bitfield for control purposes:
bit0= do not choose type but check the one that is already set
bit1= do not issue error messages via burn_msgs queue
(is automatically set with bit0)
@return Chosen write type. BURN_WRITE_NONE on failure.
*/
enum burn_write_types burn_write_opts_auto_write_type(
struct burn_write_opts *opts, struct burn_disc *disc,
char reasons[BURN_REASONS_LEN], int flag);
/** Supplies toc entries for writing - not normally required for cd mastering
@param opts The write opts to change
@param count The number of entries
@ -1208,17 +1424,40 @@ void burn_write_opts_set_multi(struct burn_write_opts *opts, int multi);
/* ts A61222 */
/** Sets a start address for writing to media and write modes which allow to
choose this address at all (DVD+RW, DVD-RAM, DVD-RW only for now). The
address is given in bytes. If it is not -1 then a write run will fail if
choice of start address is not supported or if the block alignment of the
address is not suitable for media and write mode. (Alignment to 32 kB
blocks is advised with DVD media.)
choose this address at all (DVD+RW, DVD-RAM, formatted DVD-RW only for
now). The address is given in bytes. If it is not -1 then a write run
will fail if choice of start address is not supported or if the block
alignment of the address is not suitable for media and write mode.
(Alignment to 32 kB blocks is advised with DVD media.)
@param opts The write opts to change
@param value The address in bytes (-1 = start at default address)
*/
void burn_write_opts_set_start_byte(struct burn_write_opts *opts, off_t value);
/* ts A70213 */
/** Caution: still immature and likely to change. Problems arose with
sequential DVD-RW on one drive.
Controls wether the whole available space of the media shall be filled up
by the last track of the last session.
@param opts The write opts to change
@param fill_up_media If 1 : fill up by last track, if 0 = do not fill up
*/
void burn_write_opts_set_fillup(struct burn_write_opts *opts,
int fill_up_media);
/* ts A70303 */
/** Eventually makes libburn ignore the failure of some conformance checks:
- the check wether CD write+block type is supported by the drive
- the check wether the media profile supports simulated burning
@param opts The write opts to change
@param use_force 1=ignore above checks, 0=refuse work on failed check
*/
void burn_write_opts_set_force(struct burn_write_opts *opts, int use_force);
/** Sets whether to read in raw mode or not
@param opts The read opts to change
@param raw_mode If non-zero, reading will be done in raw mode, so that everything in the data tracks on the
@ -1315,6 +1554,26 @@ int burn_drive_get_read_speed(struct burn_drive *d);
int burn_drive_get_speedlist(struct burn_drive *d,
struct burn_speed_descriptor **speed_list);
/* ts A70713 */
/** Look up the fastest speed descriptor which is not faster than the given
speed_goal. If it is 0, then the fastest one is chosen among the
descriptors with the highest end_lba. If it is -1 then the slowest speed
descriptor is chosen regardless of end_lba. Parameter flag decides wether
the speed goal means write speed or read speed.
@param d Drive to query
@param speed_goal Upper limit for speed,
0=search for maximum speed , -1 search for minimum speed
@param best_descr Result of the search, NULL if no match
@param flag Bitfield for control purposes
bit0= look for best read speed rather than write speed
bit1= look for any source type (else look for source==2 first
and for any other source type only with CD media)
@return >0 indicates a valid best_descr, 0 = no valid best_descr
*/
int burn_drive_get_best_speed(struct burn_drive *d, int speed_goal,
struct burn_speed_descriptor **best_descr, int flag);
/* ts A61226 */
/** Dispose a speed descriptor list copy which was obtained by
burn_drive_get_speedlist().
@ -1324,6 +1583,113 @@ int burn_drive_get_speedlist(struct burn_drive *d,
int burn_drive_free_speedlist(struct burn_speed_descriptor **speed_list);
/* ts A70203 */
/** The reply structure for burn_disc_get_multi_caps()
*/
struct burn_multi_caps {
/* Multi-session capability allows to keep the media appendable after
writing a session. It also guarantees that the drive will be able
to predict and use the appropriate Next Writeable Address to place
the next session on the media without overwriting the existing ones.
It does not guarantee that the selected write type is able to do
an appending session after the next session. (E.g. CD SAO is capable
of multi-session by keeping a disc appendable. But .might_do_sao
will be 0 afterwards, when checking the appendable media.)
1= media may be kept appendable by burn_write_opts_set_multi(o,1)
0= media will not be appendable
*/
int multi_session;
/* Multi-track capability allows to write more than one track source
during a single session. The written tracks can later be found in
libburn's TOC model with their start addresses and sizes.
1= multiple tracks per session are allowed
0= only one track per session allowed
*/
int multi_track;
/* Start-address capability allows to set a non-zero address with
burn_write_opts_set_start_byte(). Eventually this has to respect
.start_alignment and .start_range_low, .start_range_high in this
structure.
1= non-zero start address is allowed
0= only start address 0 is allowed (to depict the drive's own idea
about the appropriate write start)
*/
int start_adr;
/** The alignment for start addresses.
( start_address % start_alignment ) must be 0.
*/
off_t start_alignment;
/** The lowest permissible start address.
*/
off_t start_range_low;
/** The highest addressable start address.
*/
off_t start_range_high;
/** Potential availability of write modes
4= needs no size prediction, not to be chosen automatically
3= needs size prediction, not to be chosen automatically
2= available, no size prediction necessary
1= available, needs exact size prediction
0= not available
With CD media (profiles 0x09 and 0x0a) check also the elements
*_block_types of the according write mode.
*/
int might_do_tao;
int might_do_sao;
int might_do_raw;
/** Generally advised write mode.
Not necessarily the one chosen by burn_write_opts_auto_write_type()
because the burn_disc structure might impose particular demands.
*/
enum burn_write_types advised_write_mode;
/** Write mode as given by parameter wt of burn_disc_get_multi_caps().
*/
enum burn_write_types selected_write_mode;
/** Profile number which was current when the reply was generated */
int current_profile;
/** Wether the current profile indicates CD media. 1=yes, 0=no */
int current_is_cd_profile;
/* ts A70528, added to version 0.3.7 */
/** Wether the current profile is able to perform simulated write */
int might_simulate;
};
/** Allocates a struct burn_multi_caps (see above) and fills it with values
which are appropriate for the drive and the loaded media. The drive
must be grabbed for this call. The returned structure has to be disposed
via burn_disc_free_multi_caps() when no longer needed.
@param d The drive to inquire
@param wt With BURN_WRITE_NONE the best capabilities of all write modes
get returned. If set to a write mode like BURN_WRITE_SAO the
capabilities with that particular mode are returned and the
return value is 0 if the desired mode is not possible.
@param caps returns the info structure
@param flag Bitfield for control purposes (unused yet, submit 0)
@return < 0 : error , 0 : writing seems impossible , 1 : writing possible
*/
int burn_disc_get_multi_caps(struct burn_drive *d, enum burn_write_types wt,
struct burn_multi_caps **caps, int flag);
/** Removes from memory a multi session info structure which was returned by
burn_disc_get_multi_caps(). The pointer *caps gets set to NULL.
@param caps the info structure to dispose (note: pointer to pointer)
@return 0 : *caps was already NULL, 1 : memory object was disposed
*/
int burn_disc_free_multi_caps(struct burn_multi_caps **caps);
/** Gets a copy of the toc_entry structure associated with a track
@param t Track to get the entry from
@param entry Struct for the library to fill out

View File

@ -1,7 +1,8 @@
/* libdax_msgs
Message handling facility of libdax.
Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net>, provided under GPL
Copyright (C) 2006-2007 Thomas Schmitt <scdbackup@gmx.net>,
provided under GPL
*/
@ -299,9 +300,10 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff
0x00020002 (SORRY,HIGH) = Encountered error when closing drive
0x00020003 (SORRY,HIGH) = Could not grab drive
0x00020004 (NOTE,HIGH) = Opened O_EXCL scsi sibling
0x00020005 (FATAL,HIGH) = Failed to open device
0x00020005 (SORRY,HIGH) = Failed to open device
0x00020006 (FATAL,HIGH) = Too many scsi siblings
0x00020007 (NOTE,HIGH) = Closed O_EXCL scsi siblings
0x00020008 (SORRY,HIGH) = Device busy. Failed to fcntl-lock
General library operations:
@ -347,8 +349,28 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff
0x00020127 (NOTE,HIGH) = Write start address is ...
0x00020128 (FATAL,HIGH) = Unsupported inquiry_type with mmc_get_performance
0x00020129 (SORRY,HIGH) = Will not format media type
0x0002012a (FATAL,HIGH) = Cannot inquire write mode capabilities
0x0002012b (FATAL,HIGH) = Drive offers no suitable write mode with this job
0x0002012c (SORRY,HIGH) = Too many logical tracks recorded
0x0002012d (FATAL,HIGH) = Exceeding range of permissible write addresses
0x0002012e (NOTE,HIGH) = Activated track default size
0x0002012f (SORRY,HIGH) = SAO is restricted to single fixed size session
0x00020130 (SORRY,HIGH) = Drive and media state unsuitable for blanking
0x00020131 (SORRY,HIGH) = No suitable formatting type offered by drive
0x00020132 (SORRY,HIGH) = Selected format is not suitable for libburn
0x00020133 (SORRY,HIGH) = Cannot mix data and audio in SAO mode
0x00020134 (NOTE,HIGH) = Defaulted TAO to DAO
0x00020135 (SORRY,HIGH) = Cannot perform TAO, job unsuitable for DAO
0x00020136 (SORRY,HIGH) = DAO burning restricted to single fixed size track
0x00020137 (HINT,HIGH) = TAO would be possible
0x00020138 (FATAL,HIGH) = Cannot reserve track
0x00020139 (SORRY,HIGH) = Write job parameters are unsuitable
0x0002013a (FATAL,HIGH) = No suitable media detected
0x0002013b (DEBUG,HIGH) = SCSI command indicates host or driver error
0x0002013c (SORRY,HIGH) = Malformed capabilities page 2Ah received
0x0002013d (DEBUG,LOW) = Waiting for free buffer space takes long time
0x0002013e (SORRY,HIGH) = Timeout with waiting for free buffer. Now disabled
0x0002013f (DEBUG,LOW) = Reporting total time spent with waiting for buffer
libdax_audioxtr:

File diff suppressed because it is too large Load Diff

View File

@ -69,4 +69,7 @@ int mmc_compose_mode_page_5(struct burn_drive *d,
unsigned char *pd);
/* mmc5r03c.pdf 4.3.4.4.1 d) "The maximum number of RZones is 2 302." */
#define BURN_MMC_FAKE_TOC_MAX_SIZE 2302
#endif /*__MMC*/

View File

@ -21,6 +21,10 @@ struct burn_source *burn_null_source_new(void)
src->read_sub = NULL;
src->get_size = 0;
/* ts A70126 */
src->set_size = NULL;
src->free_data = NULL;
src->data = NULL;
return src;

View File

@ -1,5 +1,6 @@
#include "libburn.h"
#include "options.h"
#include "drive.h"
#include "transport.h"
/* ts A61007 */
@ -35,6 +36,8 @@ struct burn_write_opts *burn_write_opts_new(struct burn_drive *drive)
opts->obs = -1;
opts->obs_pad = 0;
opts->start_byte = -1;
opts->fill_up_media = 0;
opts->force_is_set = 0;
opts->has_mediacatalog = 0;
opts->format = BURN_CDROM;
opts->multi = 0;
@ -121,11 +124,19 @@ void burn_write_opts_set_format(struct burn_write_opts *opts, int format)
int burn_write_opts_set_simulate(struct burn_write_opts *opts, int sim)
{
/* <<< ts A70529 :
One cannot predict the ability to simulate from page 05h
information alone. This check is now done later in
function burn_write_opts_auto_write_type().
if (opts->drive->mdata->simulate) {
opts->simulate = sim;
return 1;
}
return 0;
*/
opts->simulate = !!sim;
return 1;
}
int burn_write_opts_set_underrun_proof(struct burn_write_opts *opts,
@ -170,6 +181,203 @@ void burn_write_opts_set_start_byte(struct burn_write_opts *opts, off_t value)
}
/* ts A70207 API */
/** @param flag Bitfield for control purposes:
bit0= do not choose type but check the one that is already set
bit1= do not issue error messages via burn_msgs queue
*/
enum burn_write_types burn_write_opts_auto_write_type(
struct burn_write_opts *opts, struct burn_disc *disc,
char reasons[BURN_REASONS_LEN], int flag)
{
struct burn_multi_caps *caps = NULL;
struct burn_drive *d = opts->drive;
struct burn_disc_mode_demands demands;
enum burn_write_types wt;
int ret, would_do_sao = 0;
char *reason_pt;
reasons[0] = 0;
if (d->status != BURN_DISC_BLANK &&
d->status != BURN_DISC_APPENDABLE){
if (d->status == BURN_DISC_FULL)
strcat(reasons, "MEDIA: closed or not recordable, ");
else
strcat(reasons,"MEDIA: no writeable media detected, ");
if (!(flag & 3))
libdax_msgs_submit(libdax_messenger, d->global_index,
0x0002013a,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
"No suitable media detected", 0, 0);
return BURN_WRITE_NONE;
}
ret = burn_disc_get_write_mode_demands(disc, opts, &demands,
!!opts->fill_up_media);
if (ret <= 0) {
strcat(reasons, "cannot recognize job demands, ");
{wt = BURN_WRITE_NONE; goto ex;}
}
if (demands.exotic_track && !d->current_is_cd_profile) {
if (demands.audio)
strcat(reasons, "audio track prohibited by non-CD, ");
else
strcat(reasons, "exotic track prohibited by non-CD, ");
{wt = BURN_WRITE_NONE; goto ex;}
}
if ((flag & 1) && opts->write_type != BURN_WRITE_SAO)
goto try_tao;
reason_pt = reasons + strlen(reasons);
strcat(reasons, "SAO: ");
if (d->status != BURN_DISC_BLANK) {
strcat(reasons, "write type SAO works only on blank media, ");
goto try_tao;
}
burn_disc_free_multi_caps(&caps);
ret = burn_disc_get_multi_caps(d, BURN_WRITE_SAO, &caps, 0);
if (ret < 0) {
no_caps:;
strcat(reasons, "cannot inquire write mode capabilities, ");
{wt = BURN_WRITE_NONE; goto ex;}
} else if (ret == 0) {
strcat(reasons, "no SAO offered by drive and media, ");
goto no_sao;
}
if ((opts->multi || demands.multi_session) &&
!caps->multi_session)
strcat(reasons, "multi session capability lacking, ");
if (demands.will_append)
strcat(reasons, "appended session capability lacking, ");
if (demands.multi_track && !caps->multi_track)
strcat(reasons, "multi track capability lacking, ");
if (demands.unknown_track_size == 1 &&
(caps->might_do_sao == 1 || caps->might_do_sao == 3))
strcat(reasons, "track size unpredictable, ");
if (demands.mixed_mode)
strcat(reasons, "tracks of different modes mixed, ");
if (demands.exotic_track && !d->current_is_cd_profile)
strcat(reasons, "non-data track on non-cd, ");
else if (d->current_is_cd_profile)
if ((d->block_types[BURN_WRITE_TAO] & demands.block_types) !=
demands.block_types)
strcat(reasons, "drive dislikes block type, ");
if (d->current_is_cd_profile && opts->fill_up_media)
strcat(reasons, "cd sao cannot do media fill up yet, ");
if (strcmp(reason_pt, "SAO: ") != 0)
goto no_sao;
would_do_sao = 1;
if (demands.unknown_track_size == 2 && (!(flag & 1)) &&
(caps->might_do_sao == 1 || caps->might_do_sao == 3)) {
strcat(reasons, "would have to use default track sizes, ");
goto no_sao;
} else if (caps->might_do_sao >= 3 && !(flag & 1))
goto try_tao;
do_sao:;
if (caps->might_simulate == 0 && opts->simulate && !opts->force_is_set)
goto no_simulate;
if (!(flag & 1))
burn_write_opts_set_write_type(
opts, BURN_WRITE_SAO, BURN_BLOCK_SAO);
{wt = BURN_WRITE_SAO; goto ex;}
no_sao:;
try_tao:;
if ((flag & 1) && opts->write_type != BURN_WRITE_TAO)
goto try_raw;
reason_pt = reasons + strlen(reasons);
strcat(reasons, "TAO: ");
burn_disc_free_multi_caps(&caps);
ret = burn_disc_get_multi_caps(d, BURN_WRITE_TAO, &caps, 0);
if (ret < 0)
goto no_caps;
if (ret == 0) {
strcat(reasons, "no TAO offered by drive and media, ");
goto no_tao;
}
if ((opts->multi || demands.multi_session) && !caps->multi_session)
strcat(reasons, "multi session capability lacking, ");
if (demands.multi_track && !caps->multi_track)
strcat(reasons, "multi track capability lacking, ");
if (demands.exotic_track && !d->current_is_cd_profile)
strcat(reasons, "non-data track on non-cd, ");
if (d->current_is_cd_profile && !opts->force_is_set)
if ((d->block_types[BURN_WRITE_TAO] & demands.block_types) !=
demands.block_types)
strcat(reasons, "drive dislikes block type, ");
if (strcmp(reason_pt, "TAO: ") != 0)
goto no_tao;
/* ( TAO data/audio block size will be handled automatically ) */
if (caps->might_simulate == 0 && opts->simulate && !opts->force_is_set)
goto no_simulate;
if (!(flag & 1))
burn_write_opts_set_write_type(
opts, BURN_WRITE_TAO, BURN_BLOCK_MODE1);
{wt = BURN_WRITE_TAO; goto ex;}
no_tao:;
if (would_do_sao && !(flag & 1))
goto do_sao;
if (!d->current_is_cd_profile)
goto no_write_mode;
try_raw:;
if ((flag & 1) && opts->write_type != BURN_WRITE_RAW)
goto no_write_mode;
if (!(flag & 1)) /* For now: no automatic raw write modes */
goto no_write_mode;
reason_pt = reasons + strlen(reasons);
strcat(reasons, "RAW: ");
if (!d->current_is_cd_profile)
strcat(reasons, "write type RAW prohibited by non-cd, ");
else if (d->status != BURN_DISC_BLANK)
strcat(reasons, "write type RAW works only on blank media, ");
else if ((d->block_types[BURN_WRITE_TAO] & demands.block_types) !=
demands.block_types)
strcat(reasons, "drive dislikes block type, ");
if (strcmp(reason_pt, "RAW: ") != 0)
goto no_write_mode;
if (!opts->force_is_set)
goto no_simulate;
/* For now: no setting of raw write modes */
{wt = BURN_WRITE_RAW; goto ex;}
no_write_mode:;
{wt = BURN_WRITE_NONE; goto ex;}
no_simulate:;
strcat(reasons,
"simulation of write job not supported by drive and media, ");
{wt = BURN_WRITE_NONE; goto ex;}
ex:;
burn_disc_free_multi_caps(&caps);
if (wt == BURN_WRITE_NONE && !(flag & 3)) {
libdax_msgs_submit(libdax_messenger, d->global_index,
0x0002012b,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
"Drive offers no suitable write mode with this job",
0, 0);
}
return wt;
}
/* ts A70213 : new API function */
void burn_write_opts_set_fillup(struct burn_write_opts *opts,int fill_up_media)
{
opts->fill_up_media = !!fill_up_media;
return;
}
/* ts A70303: API */
void burn_write_opts_set_force(struct burn_write_opts *opts, int use_force)
{
opts->force_is_set = !!use_force;
}
void burn_read_opts_set_raw(struct burn_read_opts *opts, int raw)
{
opts->raw = raw;

View File

@ -41,6 +41,14 @@ struct burn_write_opts
/* ts A61222 : Start address for media which allow a choice */
off_t start_byte;
/* ts A70213 : Wether to fill up the available space on media */
int fill_up_media;
/* ts A70303 : Wether to override conformance checks:
- the check wether CD write+block type is supported by the drive
*/
int force_is_set;
/** A disc can have a media catalog number */
int has_mediacatalog;
unsigned char mediacatalog[13];

View File

@ -7,10 +7,6 @@
Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net>, provided under GPL
*/
#ifndef BURN_OS_H_INCLUDED
#define BURN_OS_H_INCLUDED 1
/** List of all signals which shall be caught by signal handlers and trigger
a graceful abort of libburn. (See man 7 signal.)
*/
@ -52,14 +48,9 @@ SIGKILL, SIGCHLD, SIGSTOP, SIGURG, SIGWINCH
which are now local in sg_enumerate() . So that sg_give_next_adr()
can work in BSD and sg_enumerate() can use it.
*/
#define BURN_OS_DEFINE_DRIVE_ENUMERATOR_T \
struct burn_drive_enumeration_state { \
union ccb ccb; \
int bufsize, fd; \
unsigned int i; \
int skip_device; \
}; \
typedef struct burn_drive_enumeration_state burn_drive_enumerator_t;
#define BURN_OS_DEFINE_DRIVE_ENUMERATOR_T \
struct burn_drive_enumeration_state; \
typedef struct burn_drive_enumeration_state *burn_drive_enumerator_t;
/* The list of operating system dependent elements in struct burn_drive.
@ -68,6 +59,3 @@ typedef struct burn_drive_enumeration_state burn_drive_enumerator_t;
#define BURN_OS_TRANSPORT_DRIVE_ELEMENTS \
struct cam_device* cam;
#endif /* ! BURN_OS_H_INCLUDED */

View File

@ -42,7 +42,10 @@ SIGKILL, SIGCHLD, SIGSTOP, SIGURG, SIGWINCH
/* The maximum size for a (SCSI) i/o transaction */
/* Important : MUST be at least 32768 ! */
/* ts A70523 : >32k seems not good with kernel 2.4 USB drivers and audio
#define BURN_OS_TRANSPORT_BUFFER_SIZE 65536
*/
#define BURN_OS_TRANSPORT_BUFFER_SIZE 32768
/* To hold the index number of the most recently delivered address from
@ -52,6 +55,10 @@ SIGKILL, SIGCHLD, SIGSTOP, SIGURG, SIGWINCH
typedef int burn_drive_enumerator_t;
/* Parameters for sibling list. See sibling_fds, sibling_fnames */
#define BURN_OS_SG_MAX_SIBLINGS 5
#define BURN_OS_SG_MAX_NAMELEN 16
/* The list of operating system dependent elements in struct burn_drive.
Usually they are initialized in sg-*.c:enumerate_common().
*/
@ -60,5 +67,7 @@ int fd; \
\
/* ts A60926 : trying to lock against growisofs /dev/srN, /dev/scdN */ \
int sibling_count; \
int sibling_fds[LIBBURN_SG_MAX_SIBLINGS];
int sibling_fds[BURN_OS_SG_MAX_SIBLINGS]; \
/* ts A70409 : DDLP */ \
char sibling_fnames[BURN_OS_SG_MAX_SIBLINGS][BURN_OS_SG_MAX_NAMELEN];

View File

@ -3,37 +3,45 @@
/* scsi block commands */
#include <string.h>
#include <unistd.h>
#include "transport.h"
#include "sbc.h"
#include "spc.h"
#include "options.h"
/* spc command set */
static char SBC_LOAD[] = { 0x1b, 0, 0, 0, 3, 0 };
static char SBC_UNLOAD[] = { 0x1b, 0, 0, 0, 2, 0 };
static char SBC_START_UNIT[] = { 0x1b, 0, 0, 0, 1, 0 };
static unsigned char SBC_LOAD[] = { 0x1b, 0, 0, 0, 3, 0 };
static unsigned char SBC_UNLOAD[] = { 0x1b, 0, 0, 0, 2, 0 };
static unsigned char SBC_START_UNIT[] = { 0x1b, 0, 0, 0, 1, 0 };
void sbc_load(struct burn_drive *d)
{
struct command c;
scsi_init_command(&c, SBC_LOAD, sizeof(SBC_LOAD));
/*
memcpy(c.opcode, SBC_LOAD, sizeof(SBC_LOAD));
c.retry = 1;
c.oplen = sizeof(SBC_LOAD);
c.dir = NO_TRANSFER;
c.page = NULL;
*/
c.retry = 1;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
spc_wait_unit_attention(d, 60);
}
void sbc_eject(struct burn_drive *d)
{
struct command c;
c.page = NULL;
scsi_init_command(&c, SBC_UNLOAD, sizeof(SBC_UNLOAD));
/*
memcpy(c.opcode, SBC_UNLOAD, sizeof(SBC_UNLOAD));
c.oplen = 1;
c.oplen = sizeof(SBC_UNLOAD);
c.page = NULL;
*/
c.page = NULL;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
}
@ -43,11 +51,14 @@ int sbc_start_unit(struct burn_drive *d)
{
struct command c;
scsi_init_command(&c, SBC_START_UNIT, sizeof(SBC_START_UNIT));
/*
memcpy(c.opcode, SBC_START_UNIT, sizeof(SBC_START_UNIT));
c.retry = 1;
c.oplen = sizeof(SBC_START_UNIT);
c.dir = NO_TRANSFER;
c.page = NULL;
*/
c.retry = 1;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
return (c.error==0);
}

View File

@ -218,7 +218,8 @@ static unsigned char *get_sector(struct burn_write_opts *opts,
seclen += burn_subcode_length(outmode);
/* ts A61219 : opts->obs is eventually a 32k trigger for DVD */
if (out->bytes + (seclen) > BUFFER_SIZE || out->bytes == opts->obs) {
if (out->bytes + seclen > BUFFER_SIZE ||
(opts->obs > 0 && out->bytes + seclen > opts->obs)) {
int err;
err = d->write(d, d->nwa, out);
if (err == BE_CANCELLED)

View File

@ -1,19 +1,5 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* Revives old enumerate_common(). New version delegates much work
to methods in drive, mmc, spc, and sbc .
*/
#define Scsi_freebsd_make_own_enumeratE 1
/* Revives old scsi_enumerate_drives(). New version delegates most work to
sg_give_next_adr().
*/
#define Scsi_freebsd_old_scsi_enumeratE 1
#include <assert.h>
#include <errno.h>
#include <unistd.h>
@ -45,6 +31,13 @@
#include "libdax_msgs.h"
extern struct libdax_msgs *libdax_messenger;
struct burn_drive_enumeration_state {
int fd;
union ccb ccb;
unsigned int i;
int skip_device;
};
static void enumerate_common(char *fname, int bus_no, int host_no,
int channel_no, int target_no, int lun_no);
@ -57,33 +50,20 @@ int burn_drive_is_banned(char *device_address);
int mmc_function_spy(char * text);
#ifdef Scsi_freebsd_old_scsi_enumeratE
int sg_give_next_adr(burn_drive_enumerator_t *idx,
char adr[], int adr_size, int initialize)
{
return (0);
}
int sg_is_enumerable_adr(char* adr)
{
return (0);
}
int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
int *target_no, int *lun_no)
{
return (0);
}
#else /* Scsi_freebsd_old_scsi_enumeratE */
/* ts A61021 : Moved most code from scsi_enumerate_drives under
sg_give_next_adr() */
/* Some helper functions for scsi_give_next_adr() */
static int sg_init_enumerator(burn_drive_enumerator_t *idx)
static int sg_init_enumerator(burn_drive_enumerator_t *idx_)
{
struct burn_drive_enumeration_state *idx;
int bufsize;
idx = malloc(sizeof(*idx));
if (idx == NULL) {
warnx("can't malloc memory for enumerator");
return -1;
}
idx->skip_device = 0;
if ((idx->fd = open(XPT_DEVICE, O_RDWR)) == -1) {
@ -98,12 +78,13 @@ static int sg_init_enumerator(burn_drive_enumerator_t *idx)
idx->ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
idx->ccb.ccb_h.func_code = XPT_DEV_MATCH;
idx->bufsize = sizeof(struct dev_match_result) * 100;
idx->ccb.cdm.match_buf_len = idx->bufsize;
idx->ccb.cdm.matches = (struct dev_match_result *)malloc(idx->bufsize);
bufsize = sizeof(struct dev_match_result) * 100;
idx->ccb.cdm.match_buf_len = bufsize;
idx->ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
if (idx->ccb.cdm.matches == NULL) {
warnx("can't malloc memory for matches");
close(idx->fd);
free(idx);
return -1;
}
idx->ccb.cdm.num_matches = 0;
@ -116,12 +97,28 @@ static int sg_init_enumerator(burn_drive_enumerator_t *idx)
idx->ccb.cdm.num_patterns = 0;
idx->ccb.cdm.pattern_buf_len = 0;
*idx_ = idx;
return 1;
}
static int sg_next_enumeration_buffer(burn_drive_enumerator_t *idx)
static void sg_destroy_enumerator(burn_drive_enumerator_t *idx_)
{
struct burn_drive_enumeration_state *idx = *idx_;
if(idx->fd != -1)
close(idx->fd);
free(idx->ccb.cdm.matches);
free(idx);
*idx_ = NULL;
}
static int sg_next_enumeration_buffer(burn_drive_enumerator_t *idx_)
{
struct burn_drive_enumeration_state *idx = *idx_;
/*
* We do the ioctl multiple times if necessary, in case there are
* more than 100 nodes in the EDT.
@ -152,95 +149,94 @@ static int sg_next_enumeration_buffer(burn_drive_enumerator_t *idx)
@return 1 = reply is a valid address , 0 = no further address available
-1 = severe error (e.g. adr_size too small)
*/
int sg_give_next_adr(burn_drive_enumerator_t *idx,
int sg_give_next_adr(burn_drive_enumerator_t *idx_,
char adr[], int adr_size, int initialize)
{
struct burn_drive_enumeration_state *idx;
int ret;
if (initialize == 1) {
ret = sg_init_enumerator(idx);
ret = sg_init_enumerator(idx_);
if (ret<=0)
return ret;
} else if (initialize == -1) {
if(idx->fd != -1)
close(idx->fd);
idx->fd = -1;
sg_destroy_enumerator(idx_);
return 0;
}
idx = *idx_;
try_item:; /* This spaghetti loop keeps the number of tabs small */
do {
if (idx->i >= idx->ccb.cdm.num_matches) {
ret = sg_next_enumeration_buffer(idx_);
if (ret<=0)
return -1;
idx->i = 0;
} else
(idx->i)++;
/* Loop content from old scsi_enumerate_drives() */
while (idx->i < idx->ccb.cdm.num_matches) {
switch (idx->ccb.cdm.matches[idx->i].type) {
case DEV_MATCH_BUS:
break;
case DEV_MATCH_DEVICE: {
struct device_match_result* result;
while (idx->i >= idx->ccb.cdm.num_matches) {
ret = sg_next_enumeration_buffer(idx);
if (ret<=0)
return -1;
if (!((idx->ccb.ccb_h.status == CAM_REQ_CMP)
&& (idx->ccb.cdm.status == CAM_DEV_MATCH_MORE)) )
return 0;
idx->i = 0;
}
result = &(idx->ccb.cdm.matches[idx->i].result.device_result);
if (result->flags & DEV_RESULT_UNCONFIGURED)
idx->skip_device = 1;
else
idx->skip_device = 0;
break;
}
case DEV_MATCH_PERIPH: {
struct periph_match_result* result;
switch (idx->ccb.cdm.matches[idx->i].type) {
case DEV_MATCH_BUS:
break;
case DEV_MATCH_DEVICE: {
struct device_match_result* result;
result = &(idx->ccb.cdm.matches[idx->i].result.periph_result);
if (idx->skip_device ||
strcmp(result->periph_name, "pass") == 0)
break;
ret = snprintf(adr, adr_size, "/dev/%s%d",
result->periph_name, result->unit_number);
if(ret >= adr_size)
return -1;
result = &(idx->ccb.cdm.matches[i].result.device_result);
if (result->flags & DEV_RESULT_UNCONFIGURED)
idx->skip_device = 1;
else
idx->skip_device = 0;
break;
}
case DEV_MATCH_PERIPH: {
struct periph_match_result* result;
char buf[64];
/* Found next enumerable address */
return 1;
result = &(idx->ccb.cdm.matches[i].result.periph_result);
if (idx->skip_device ||
strcmp(result->periph_name, "pass") == 0)
break;
snprintf(buf, sizeof (buf), "/dev/%s%d",
result->periph_name, result->unit_number);
if(adr_size <= strlen(buf)
return -1;
strcpy(adr, buf);
}
default:
/* printf(stderr, "unknown match type\n"); */
break;
}
(idx->i)++;
}
} while ((idx->ccb.ccb_h.status == CAM_REQ_CMP)
&& (idx->ccb.cdm.status == CAM_DEV_MATCH_MORE));
/* Found next enumerable address */
return 1;
}
default:
/* printf(stderr, "unknown match type\n"); */
break;
}
(idx->i)++;
goto try_item; /* Regular function exit is return 1 above */
return 0;
}
int sg_is_enumerable_adr(char* adr)
{
burn_drive_enumerator_t idx;
int initialize = 1;
int ret;
char buf[64];
ret = sg_init_enumerator(&idx);
if (ret <= 0)
return 0;
while(1) {
ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
initialize = 0;
ret = sg_give_next_adr(&idx, buf, sizeof(buf), 0);
if (ret <= 0)
break;
break;
if (strcmp(adr, buf) == 0) {
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
sg_destroy_enumerator(&idx);
return 1;
}
}
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
sg_destroy_enumerator(&idx);
return (0);
}
@ -252,32 +248,32 @@ int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
int *target_no, int *lun_no)
{
burn_drive_enumerator_t idx;
int initialize = 1;
int ret;
char buf[64];
struct periph_match_result* result;
ret = sg_init_enumerator(&idx);
if (ret <= 0)
return 0;
while(1) {
ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
initialize = 0;
ret = sg_give_next_adr(&idx, buf, sizeof(buf), 0);
if (ret <= 0)
break;
if (strcmp(adr, buf) != 0)
continue;
result = &(idx->ccb.cdm.matches[i].result.periph_result);
*bus_no = result->path_id;
*host_no = result->path_id;
*channel_no = 0;
*target_no = result->target_id
*lun_no = result->target_lun;
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
return 1;
break;
if (strcmp(path, buf) == 0) {
result = &(idx->ccb.cdm.matches[idx->i].result.periph_result);
*bus_no = result->path_id;
*host_no = result->path_id;
*channel_no = 0;
*target_no = result->target_id;
*lun_no = result->target_lun;
sg_destroy_enumerator(&idx);
return 1;
}
}
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
sg_destroy_enumerator(&idx);
return (0);
}
#endif /* ! Scsi_freebsd_old_scsi_enumeratE */
int sg_close_drive(struct burn_drive * d)
{
@ -295,125 +291,28 @@ int sg_drive_is_open(struct burn_drive * d)
int scsi_enumerate_drives(void)
{
#ifdef Scsi_freebsd_old_scsi_enumeratE
union ccb ccb;
int bufsize, fd;
unsigned int i;
int skip_device = 0;
if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
warn("couldn't open %s", XPT_DEVICE);
return;
}
bzero(&ccb, sizeof(union ccb));
ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
ccb.ccb_h.func_code = XPT_DEV_MATCH;
bufsize = sizeof(struct dev_match_result) * 100;
ccb.cdm.match_buf_len = bufsize;
ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
if (ccb.cdm.matches == NULL) {
warnx("can't malloc memory for matches");
close(fd);
return;
}
ccb.cdm.num_matches = 0;
/*
* We fetch all nodes, since we display most of them in the default
* case, and all in the verbose case.
*/
ccb.cdm.num_patterns = 0;
ccb.cdm.pattern_buf_len = 0;
/*
* We do the ioctl multiple times if necessary, in case there are
* more than 100 nodes in the EDT.
*/
do {
if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
warn("error sending CAMIOCOMMAND ioctl");
break;
}
if ((ccb.ccb_h.status != CAM_REQ_CMP)
|| ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
&& (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
warnx("got CAM error %#x, CDM error %d\n",
ccb.ccb_h.status, ccb.cdm.status);
break;
}
for (i = 0; i < ccb.cdm.num_matches; i++) {
switch (ccb.cdm.matches[i].type) {
case DEV_MATCH_BUS:
break;
case DEV_MATCH_DEVICE: {
struct device_match_result* result;
result = &ccb.cdm.matches[i].result.device_result;
if (result->flags & DEV_RESULT_UNCONFIGURED)
skip_device = 1;
else
skip_device = 0;
break;
}
case DEV_MATCH_PERIPH: {
struct periph_match_result* result;
char buf[64];
result = &ccb.cdm.matches[i].result.periph_result;
if (skip_device || strcmp(result->periph_name, "pass") == 0)
break;
snprintf(buf, sizeof (buf), "/dev/%s%d", result->periph_name, result->unit_number);
/* ts A51221 */
if (burn_drive_is_banned(buf))
break;
enumerate_common(buf, result->path_id, result->path_id, 0,
result->target_id, result->target_lun);
break;
}
default:
fprintf(stdout, "unknown match type\n");
break;
}
}
} while ((ccb.ccb_h.status == CAM_REQ_CMP)
&& (ccb.cdm.status == CAM_DEV_MATCH_MORE));
close(fd);
#else /* Scsi_freebsd_old_scsi_enumeratE */
burn_drive_enumerator_t idx;
int initialize = 1;
int ret;
char buf[64];
struct periph_match_result* result;
ret = sg_init_enumerator(&idx);
if (ret <= 0)
return 0;
while(1) {
ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
initialize = 0;
ret = sg_give_next_adr(&idx, buf, sizeof(buf), 0);
if (ret <= 0)
break;
break;
if (burn_drive_is_banned(buf))
continue;
enumerate_common(buf, idx.result->path_id, idx.result->path_id,
0, idx.result->target_id,
idx.result->target_lun);
continue;
result = &idx->ccb.cdm.matches[idx->i].result.periph_result;
enumerate_common(buf, result->path_id, result->path_id,
0, result->target_id,
result->target_lun);
}
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
#endif /* ! Scsi_freebsd_old_scsi_enumeratE */
sg_destroy_enumerator(&idx);
return 1;
}
@ -551,7 +450,10 @@ int sg_grab(struct burn_drive *d)
mmc_function_spy("sg_grab");
assert(d->cam == NULL);
if (burn_drive_is_open(d)) {
d->released = 0;
return 1;
}
cam = cam_open_device(d->devname, O_RDWR);
if (cam == NULL) {
@ -591,6 +493,7 @@ int sg_release(struct burn_drive *d)
mmc_function_spy("sg_release ----------- closing.");
sg_close_drive(d);
d->released = 1;
return 0;
}

View File

@ -71,14 +71,26 @@ Hint: You should also look into sg-freebsd-port.c, which is a younger and
#include <sys/poll.h>
#include <linux/hdreg.h>
#include <stdlib.h>
#include <scsi/sg.h>
#include <sys/utsname.h>
#include <scsi/scsi.h>
/* ts A61211 : to recognize CD devices on /dev/sr* */
#include <scsi/sg.h>
/* Values within sg_io_hdr_t indicating success after ioctl(SG_IO) : */
/* .host_status : from http://tldp.org/HOWTO/SCSI-Generic-HOWTO/x291.html */
#define Libburn_sg_host_oK 0
/* .driver_status : from http://tldp.org/HOWTO/SCSI-Generic-HOWTO/x322.html */
#define Libburn_sg_driver_oK 0
/* ts A61211 : to eventually recognize CD devices on /dev/sr* */
#include <linux/cdrom.h>
/* ts A61211 : preparing for exploration of recent Linux ATA adventures */
/** Indication of the Linux kernel this software is running on */
/* -1 = not evaluated , 0 = unrecognizable , 1 = 2.4 , 2 = 2.6 */
static int sg_kernel_age = -1;
/** PORTING : Device file families for bus scanning and drive access.
Both device families must support the following ioctls:
SG_IO,
@ -104,22 +116,22 @@ static int linux_sg_enumerate_debug = 0;
in the range of 0 to 31 . The resulting addresses must provide SCSI
address parameters Host, Channel, Id, Lun and also Bus.
E.g.: "/dev/sg%d"
sr%d is supposed to map only CD-ROM style devices. Additionally a test
with ioctl(CDROM_DRIVE_STATUS) is made to assert that it is such a drive,
This initial setting may be overridden in sg_select_device_family() by
settings made via burn_preset_device_open().
*/
/* NEW INFO: If hard disks at /dev/sr allow ioctl(CDROM_DRIVE_STATUS), they
are in danger.
If you want it less dangerous:
#undef CDROM_DRIVE_STATUS
but then you might need linux_sg_accept_any_type = 1 which
is _more dangerous_.
*/
/* !!! DO NOT SET TO sr%d UNLESS YOU PROTECTED ALL INDISPENSIBLE DEVICES
by chmod -rw . A test wether non-CD devices are properly excluded would
be well needed though. Heroic disks, scanners, etc. wanted !!! */
static char linux_sg_device_family[80] = {"/dev/sg%d"};
/* Set this to 1 if you want the default linux_sg_device_family chosen
depending on kernel release: sg for <2.6 , sr for >=2.6
*/
static int linux_sg_auto_family = 1;
/* Set this to 1 in order to accept any TYPE_* (see scsi/scsi.h) */
/* NEW INFO: Try with 0 first. There is hope via CDROM_DRIVE_STATUS. */
/* But try with 0 first. There is hope via CDROM_DRIVE_STATUS. */
/* !!! DO NOT SET TO 1 UNLESS YOU PROTECTED ALL INDISPENSIBLE DEVICES
chmod -rw !!! */
static int linux_sg_accept_any_type = 0;
@ -168,12 +180,15 @@ static void enumerate_common(char *fname, int bus_no, int host_no,
int channel_no, int target_no, int lun_no);
/* >>> ts A61115 : this needs mending. A Linux aspect shows up in cdrskin. */
/* ts A60813 : storage objects are in libburn/init.c
wether to use O_EXCL
wether to use O_EXCL with open(2) of devices
wether to use fcntl(,F_SETLK,) after open(2) of devices
what device family to use : 0=default, 1=sr, 2=scd, (3=st), 4=sg
wether to use O_NOBLOCK with open(2) on devices
wether to take O_EXCL rejection as fatal error */
extern int burn_sg_open_o_excl;
extern int burn_sg_fcntl_f_setlk;
extern int burn_sg_use_family;
extern int burn_sg_open_o_nonblock;
extern int burn_sg_open_abort_busy;
@ -188,6 +203,53 @@ int mmc_function_spy(char * text);
/* (Public functions are listed below) */
/* ------------------------------------------------------------------------ */
/* ts A70413 */
/* This finds out wether the software is running on kernel >= 2.6
*/
static void sg_evaluate_kernel(void)
{
struct utsname buf;
if (sg_kernel_age >= 0)
return;
sg_kernel_age = 0;
if (uname(&buf) == -1)
return;
sg_kernel_age = 1;
if (strcmp(buf.release, "2.6") >= 0)
sg_kernel_age = 2;
}
/* ts A70314 */
/* This installs the device file family if one was chosen explicitely
by burn_preset_device_open()
*/
static void sg_select_device_family(void)
{
/* >>> ??? do we need a mutex here ? */
/* >>> (It might be concurrent but is supposed to have always
the same effect. Any race condition should be harmless.) */
if (burn_sg_use_family == 1)
strcpy(linux_sg_device_family, "/dev/sr%d");
else if (burn_sg_use_family == 2)
strcpy(linux_sg_device_family, "/dev/scd%d");
else if (burn_sg_use_family == 3)
strcpy(linux_sg_device_family, "/dev/st%d");
else if (burn_sg_use_family == 4)
strcpy(linux_sg_device_family, "/dev/sg%d");
else if (linux_sg_auto_family) {
sg_evaluate_kernel();
if (sg_kernel_age >= 2)
strcpy(linux_sg_device_family, "/dev/sr%d");
else
strcpy(linux_sg_device_family, "/dev/sg%d");
linux_sg_auto_family = 0;
}
}
static int sgio_test(int fd)
{
@ -229,12 +291,86 @@ static int sg_handle_busy_device(char *fname, int os_errno)
}
/* ts A60925 : ticket 74 */
static int sg_close_drive_fd(char *fname, int driveno, int *fd, int sorry)
{
int ret, os_errno, sevno= LIBDAX_MSGS_SEV_DEBUG;
char msg[4096+100];
if(*fd < 0)
return(0);
ret = close(*fd);
*fd = -1337;
if(ret != -1) {
/* ts A70409 : DDLP-B */
/* >>> release single lock on fname */
return 1;
}
os_errno= errno;
sprintf(msg, "Encountered error when closing drive '%s'", fname);
if (sorry)
sevno = LIBDAX_MSGS_SEV_SORRY;
libdax_msgs_submit(libdax_messenger, driveno, 0x00020002,
sevno, LIBDAX_MSGS_PRIO_HIGH, msg, os_errno, 0);
return 0;
}
/* ts A70401 :
fcntl() has the unappealing property to work only after open().
So libburn will by default use open(O_EXCL) first and afterwards
as second assertion will use fcntl(F_SETLK). One lock more should not harm.
*/
static int sg_fcntl_lock(int *fd, char *fd_name, int l_type, int verbous)
{
struct flock lockthing;
char msg[81];
int ret;
if (!burn_sg_fcntl_f_setlk)
return 1;
memset(&lockthing, 0, sizeof(lockthing));
lockthing.l_type = l_type;
lockthing.l_whence = SEEK_SET;
lockthing.l_start = 0;
lockthing.l_len = 0;
/*
fprintf(stderr,"LIBBURN_EXPERIMENTAL: fcntl(%d, F_SETLK, %s)\n",
*fd, l_type == F_WRLCK ? "F_WRLCK" : "F_RDLCK");
*/
ret = fcntl(*fd, F_SETLK, &lockthing);
if (ret == -1) {
if (verbous) {
sprintf(msg, "Device busy. Failed to fcntl-lock '%s'",
fd_name);
libdax_msgs_submit(libdax_messenger, -1, 0x00020008,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
msg, errno, 0);
}
close(*fd);
*fd = -1;
/* ts A70409 : DDLP-B */
/* >>> release single lock on fd_name */
return(0);
}
return 1;
}
/* ts A60926 */
static int sg_open_drive_fd(char *fname, int scan_mode)
{
int open_mode = O_RDWR, fd;
char msg[81];
/* ts A70409 : DDLP-B */
/* >>> obtain single lock on fname */
/* ts A60813 - A60927
O_EXCL with devices is a non-POSIX feature
of Linux kernels. Possibly introduced 2002.
@ -244,17 +380,22 @@ static int sg_open_drive_fd(char *fname, int scan_mode)
/* ts A60813
O_NONBLOCK was already hardcoded in ata_ but not in sg_.
There must be some reason for this. So O_NONBLOCK is
default mode for both now. Disable on own risk. */
default mode for both now. Disable on own risk.
ts A70411
Switched to O_NDELAY for LKML statement 2007/4/11/141 by Alan Cox:
"open() has side effects. The CD layer allows you to open
with O_NDELAY if you want to avoid them."
*/
if(burn_sg_open_o_nonblock)
open_mode |= O_NONBLOCK;
open_mode |= O_NDELAY;
/* <<< debugging
fprintf(stderr,
"\nlibburn: experimental: o_excl= %d , o_nonblock= %d, abort_on_busy= %d\n",
burn_sg_open_o_excl,burn_sg_open_o_nonblock,burn_sg_open_abort_busy);
fprintf(stderr,
"libburn: experimental: O_EXCL= %d , O_NONBLOCK= %d\n",
!!(open_mode&O_EXCL),!!(open_mode&O_NONBLOCK));
"libburn: experimental: O_EXCL= %d , O_NDELAY= %d\n",
!!(open_mode&O_EXCL),!!(open_mode&O_NDELAY));
*/
fd = open(fname, open_mode);
@ -273,50 +414,25 @@ static int sg_open_drive_fd(char *fname, int scan_mode)
return -1;
sprintf(msg, "Failed to open device '%s'",fname);
libdax_msgs_submit(libdax_messenger, -1, 0x00020005,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
msg, errno, 0);
return -1;
}
sg_fcntl_lock(&fd, fname, F_WRLCK, 1);
return fd;
}
/* ts A60925 : ticket 74 */
static int sg_close_drive_fd(char *fname, int driveno, int *fd, int sorry)
{
int ret, os_errno, sevno= LIBDAX_MSGS_SEV_DEBUG;
char msg[4096+100];
if(*fd < 0)
return(0);
ret = close(*fd);
*fd = -1337;
if(ret != -1)
return 1;
os_errno= errno;
if (fname != NULL)
sprintf(msg, "Encountered error when closing drive '%s'",
fname);
else
sprintf(msg, "Encountered error when closing drive");
if (sorry)
sevno = LIBDAX_MSGS_SEV_SORRY;
libdax_msgs_submit(libdax_messenger, driveno, 0x00020002,
sevno, LIBDAX_MSGS_PRIO_HIGH, msg, os_errno, 0);
return 0;
}
/* ts A60926 */
static int sg_release_siblings(int sibling_fds[], int *sibling_count)
static int sg_release_siblings(int sibling_fds[],
char sibling_fnames[][BURN_OS_SG_MAX_NAMELEN],
int *sibling_count)
{
int i;
char msg[81];
for(i= 0; i < *sibling_count; i++)
sg_close_drive_fd(NULL, -1, &(sibling_fds[i]), 0);
sg_close_drive_fd(sibling_fnames[i], -1, &(sibling_fds[i]), 0);
if(*sibling_count > 0) {
sprintf(msg, "Closed %d O_EXCL scsi siblings", *sibling_count);
libdax_msgs_submit(libdax_messenger, -1, 0x00020007,
@ -334,7 +450,8 @@ static int sg_close_drive(struct burn_drive *d)
if (!burn_drive_is_open(d))
return 0;
sg_release_siblings(d->sibling_fds, &(d->sibling_count));
sg_release_siblings(d->sibling_fds, d->sibling_fnames,
&(d->sibling_count));
ret = sg_close_drive_fd(d->devname, d->global_index, &(d->fd), 0);
return ret;
}
@ -342,29 +459,45 @@ static int sg_close_drive(struct burn_drive *d)
/* ts A60926 */
static int sg_open_scsi_siblings(char *path, int driveno,
int sibling_fds[], int *sibling_count,
int host_no, int channel_no, int id_no, int lun_no)
int sibling_fds[],
char sibling_fnames[][BURN_OS_SG_MAX_NAMELEN],
int *sibling_count,
int host_no, int channel_no, int id_no, int lun_no)
{
int tld, i, ret, fd, i_bus_no = -1;
int i_host_no = -1, i_channel_no = -1, i_target_no = -1, i_lun_no = -1;
char msg[161], fname[81];
struct stat stbuf;
dev_t last_rdev = 0, path_rdev;
static char tldev[][81]= {"/dev/sr%d", "/dev/scd%d", "/dev/st%d",
"/dev/sg%d", ""};
static char tldev[][81]= {"/dev/sr%d", "/dev/scd%d", "/dev/sg%d", ""};
/* ts A70609: removed "/dev/st%d" */
if(stat(path, &stbuf) == -1)
return 0;
path_rdev = stbuf.st_rdev;
sg_select_device_family();
if (linux_sg_device_family[0] == 0)
return 1;
if(host_no < 0 || id_no < 0 || channel_no < 0 || lun_no < 0)
return(2);
if(*sibling_count > 0)
sg_release_siblings(sibling_fds, sibling_count);
sg_release_siblings(sibling_fds, sibling_fnames,
sibling_count);
for (tld = 0; tldev[tld][0] != 0; tld++) {
if (strcmp(tldev[tld], linux_sg_device_family)==0)
continue;
for (i = 0; i < 32; i++) {
sprintf(fname, tldev[tld], i);
if(stat(fname, &stbuf) == -1)
continue;
if (path_rdev == stbuf.st_rdev)
continue;
if (*sibling_count > 0 && last_rdev == stbuf.st_rdev)
continue;
ret = sg_obtain_scsi_adr(fname, &i_bus_no, &i_host_no,
&i_channel_no, &i_target_no, &i_lun_no);
if (ret <= 0)
@ -378,7 +511,7 @@ static int sg_open_scsi_siblings(char *path, int driveno,
if (fd < 0)
goto failed;
if (*sibling_count>=LIBBURN_SG_MAX_SIBLINGS) {
if (*sibling_count>=BURN_OS_SG_MAX_SIBLINGS) {
sprintf(msg, "Too many scsi siblings of '%s'",
path);
libdax_msgs_submit(libdax_messenger,
@ -388,18 +521,20 @@ static int sg_open_scsi_siblings(char *path, int driveno,
goto failed;
}
sprintf(msg, "Opened O_EXCL scsi sibling '%s' of '%s'",
fname, path);
fname, path);
libdax_msgs_submit(libdax_messenger, driveno,
0x00020004,
LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
msg, 0, 0);
sibling_fds[*sibling_count] = fd;
strcpy(sibling_fnames[*sibling_count], fname);
(*sibling_count)++;
last_rdev= stbuf.st_rdev;
}
}
return 1;
failed:;
sg_release_siblings(sibling_fds, sibling_count);
sg_release_siblings(sibling_fds, sibling_fnames, sibling_count);
return 0;
}
@ -477,10 +612,13 @@ static void ata_enumerate(void)
static void sg_enumerate(void)
{
struct sg_scsi_id sid;
int i, fd, sibling_fds[LIBBURN_SG_MAX_SIBLINGS], sibling_count= 0, ret;
int i, fd, sibling_fds[BURN_OS_SG_MAX_SIBLINGS], sibling_count= 0, ret;
int sid_ret = 0;
int bus_no= -1, host_no= -1, channel_no= -1, target_no= -1, lun_no= -1;
char fname[10];
char sibling_fnames[BURN_OS_SG_MAX_SIBLINGS][BURN_OS_SG_MAX_NAMELEN];
sg_select_device_family();
if (linux_sg_enumerate_debug)
fprintf(stderr, "libburn_debug: linux_sg_device_family = %s\n",
@ -520,6 +658,16 @@ static void sg_enumerate(void)
"ioctl(SG_GET_SCSI_ID) failed, errno=%d '%s' , ",
errno, strerror(errno));
if (sgio_test(fd) == -1) {
if (linux_sg_enumerate_debug)
fprintf(stderr,
"FATAL: sgio_test() failed: errno=%d '%s'",
errno, strerror(errno));
sg_close_drive_fd(fname, -1, &fd, 0);
continue;
}
#ifdef CDROM_DRIVE_STATUS
/* ts A61211 : not widening old acceptance range */
if (strcmp(linux_sg_device_family,"/dev/sg%d") != 0) {
@ -581,7 +729,8 @@ static void sg_enumerate(void)
/* ts A60927 : trying to do locking with growisofs */
if(burn_sg_open_o_excl>1) {
ret = sg_open_scsi_siblings(
fname, -1, sibling_fds, &sibling_count,
fname, -1, sibling_fds, sibling_fnames,
&sibling_count,
sid.host_no, sid.channel,
sid.scsi_id, sid.lun);
if (ret<=0) {
@ -591,7 +740,8 @@ static void sg_enumerate(void)
continue;
}
/* the final occupation will be done in sg_grab() */
sg_release_siblings(sibling_fds, &sibling_count);
sg_release_siblings(sibling_fds, sibling_fnames,
&sibling_count);
}
#ifdef SCSI_IOCTL_GET_BUS_NUMBER
if(bus_no == -1)
@ -645,7 +795,7 @@ static void enumerate_common(char *fname, int bus_no, int host_no,
/* Adapter specific handles and data */
out.fd = -1337;
out.sibling_count = 0;
for(i= 0; i<LIBBURN_SG_MAX_SIBLINGS; i++)
for(i= 0; i<BURN_OS_SG_MAX_SIBLINGS; i++)
out.sibling_fds[i] = -1337;
/* PORTING: ---------------- end of non portable part ------------ */
@ -698,6 +848,7 @@ int sg_give_next_adr(burn_drive_enumerator_t *idx,
if (initialize == -1)
return 0;
sg_select_device_family();
if (linux_sg_device_family[0] == 0)
sg_limit = 0;
if (linux_ata_device_family[0] == 0)
@ -793,9 +944,12 @@ int sg_grab(struct burn_drive *d)
open_mode |= O_EXCL;
/* ts A60813
O_NONBLOCK was hardcoded here. So it should stay default mode. */
O_NONBLOCK was hardcoded here. So it should stay default mode.
ts A70411
Switched to O_NDELAY for LKML statement 2007/4/11/141
*/
if(burn_sg_open_o_nonblock)
open_mode |= O_NONBLOCK;
open_mode |= O_NDELAY;
/* ts A60813 - A60822
After enumeration the drive fd is probably still open.
@ -808,12 +962,15 @@ int sg_grab(struct burn_drive *d)
<<< debug: for tracing calls which might use open drive fds */
mmc_function_spy("sg_grab ----------- opening");
/* ts A70409 : DDLP-B */
/* >>> obtain single lock on d->devname */
/* ts A60926 */
if(burn_sg_open_o_excl>1) {
fd = -1;
ret = sg_open_scsi_siblings(d->devname,
d->global_index,d->sibling_fds,
&(d->sibling_count),
d->sibling_fnames,&(d->sibling_count),
d->host, d->channel, d->id, d->lun);
if(ret <= 0)
goto drive_is_in_use;
@ -821,6 +978,11 @@ int sg_grab(struct burn_drive *d)
fd = open(d->devname, open_mode);
os_errno = errno;
if (fd >= 0) {
sg_fcntl_lock(&fd, d->devname, F_WRLCK, 1);
if (fd < 0)
goto drive_is_in_use;
}
} else
fd= d->fd;
@ -872,6 +1034,71 @@ int sg_release(struct burn_drive *d)
}
/** ts A70518:
Debugging log facility. Controlled by existence of macros:
Libburn_log_sg_commandS enables logging to file
/tmp/libburn_sg_command_log
Libburn_fflush_log_sg_commandS enables fflush after each output line
Libburn_log_sg_command_stderR enables additional log to stderr
*/
/*
#define Libburn_log_sg_commandS 1
#define Libburn_fflush_log_sg_commandS 1
#define Libburn_log_sg_command_stderR 1
*/
#ifdef Libburn_log_sg_commandS
/** Logs command (before execution) */
static int sg_log_cmd(struct command *c, FILE *fp, int flag)
{
int i;
if (fp != NULL) {
for(i = 0; i < 16 && i < c->oplen; i++)
fprintf(fp,"%2.2x ", c->opcode[i]);
fprintf(fp, "\n");
#ifdef Libburn_fflush_log_sg_commandS
fflush(fp);
#endif
}
if (fp == stderr)
return 1;
#ifdef Libburn_log_sg_command_stderR
sg_log_cmd(c, stderr, flag);
#endif
return 1;
}
/** logs outcome of a sg command. flag&1 causes an error message */
static int sg_log_err(struct command *c, FILE *fp,
sg_io_hdr_t *s,
int flag)
{
if(fp!=NULL) {
if(flag & 1)
fprintf(fp,
"+++ key=%X asc=%2.2Xh ascq=%2.2Xh (%6d ms)\n",
s->sbp[2], s->sbp[12], s->sbp[13],s->duration);
else
fprintf(fp,"%6d ms\n", s->duration);
#ifdef Libburn_fflush_log_sg_commandS
fflush(fp);
#endif
}
if (fp == stderr)
return 1;
#ifdef Libburn_log_sg_command_stderR
sg_log_err(c, stderr, s, flag);
#endif
return 1;
}
#endif /* Libburn_log_sg_commandS */
/** Sends a SCSI command to the drive, receives reply and evaluates wether
the command succeeded or shall be retried or finally failed.
Returned SCSI errors shall not lead to a return value indicating failure.
@ -886,15 +1113,10 @@ int sg_issue_command(struct burn_drive *d, struct command *c)
int done = 0, no_c_page = 0;
int err;
sg_io_hdr_t s;
/*
#define Libburn_log_sg_commandS 1
*/
#ifdef Libburn_log_sg_commandS
/* ts A61030 */
static FILE *fp= NULL;
static int fpcount= 0;
int i;
#endif /* Libburn_log_sg_commandS */
/* <<< ts A60821
@ -910,12 +1132,7 @@ int sg_issue_command(struct burn_drive *d, struct command *c)
fp= fopen("/tmp/libburn_sg_command_log","a");
fprintf(fp,"\n-----------------------------------------\n");
}
if(fp!=NULL) {
for(i=0;i<10;i++)
fprintf(fp,"%2.2x ", c->opcode[i]);
fprintf(fp,"\n");
fpcount++;
}
sg_log_cmd(c,fp,0);
#endif /* Libburn_log_sg_commandS */
@ -950,7 +1167,15 @@ int sg_issue_command(struct burn_drive *d, struct command *c)
if (c->page && !no_c_page) {
s.dxferp = c->page->data;
if (c->dir == FROM_DRIVE) {
s.dxfer_len = BUFFER_SIZE;
/* ts A70519 : kernel 2.4 usb-storage seems to
expect exact dxfer_len for data
fetching commands.
*/
if (c->dxfer_len >= 0)
s.dxfer_len = c->dxfer_len;
else
s.dxfer_len = BUFFER_SIZE;
/* touch page so we can use valgrind */
memset(c->page->data, 0, BUFFER_SIZE);
} else {
@ -1013,16 +1238,27 @@ int sg_issue_command(struct burn_drive *d, struct command *c)
ex:;
if (c->error) {
scsi_notify_error(d, c, s.sbp, s.sb_len_wr, 0);
} else if (s.host_status != Libburn_sg_host_oK ||
s.driver_status != Libburn_sg_driver_oK) {
char msg[161];
sprintf(msg,
"SCSI command %2.2Xh indicates host or driver error:",
(unsigned int) c->opcode[0]);
sprintf(msg+strlen(msg),
" host_status= %xh , driver_status= %xh",
(unsigned int) s.host_status,
(unsigned int) s.driver_status);
libdax_msgs_submit(libdax_messenger, d->global_index,
0x0002013b,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
msg, 0, 0);
}
#ifdef Libburn_log_sg_commandS
if(fp!=NULL) {
fprintf(fp,"+++ key=%X asc=%2.2Xh ascq=%2.2Xh\n",
s.sbp[2], s.sbp[12], s.sbp[13]);
fpcount++;
}
sg_log_err(c, fp, &s, c->error != 0);
#endif /* Libburn_log_sg_commandS */
}
return 1;
}
@ -1034,19 +1270,33 @@ ex:;
int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
int *target_no, int *lun_no)
{
int fd, ret, l;
int fd, ret, l, open_mode = O_RDONLY;
struct my_scsi_idlun {
int x;
int host_unique_id;
};
struct my_scsi_idlun idlun;
l = strlen(linux_ata_device_family) - 2;
if (l > 0 && strncmp(path, linux_ata_device_family, l) == 0
&& path[7] >= 'a' && path[7] <= 'z' && path[8] == 0)
return 0; /* on RIP 14 all hdx return SCSI adr 0,0,0,0 */
fd = open(path, O_RDONLY | O_NONBLOCK);
/* ts A70409 : DDLP-B */
/* >>> obtain single lock on path */
if(burn_sg_open_o_nonblock)
open_mode |= O_NDELAY;
if(burn_sg_open_o_excl) {
/* O_EXCL | O_RDONLY does not work with /dev/sg* on
SuSE 9.0 (kernel 2.4) and SuSE 9.3 (kernel 2.6) */
/* so skip it for now */;
}
fd = open(path, open_mode);
if(fd < 0)
return 0;
sg_fcntl_lock(&fd, path, F_RDLCK, 0);
if(fd < 0)
return 0;

View File

@ -29,7 +29,8 @@ extern struct libdax_msgs *libdax_messenger;
/* spc command set */
static unsigned char SPC_INQUIRY[] = { 0x12, 0, 0, 0, 255, 0 };
/* ts A70519 : allocation length byte 3+4 was 0,255 */
static unsigned char SPC_INQUIRY[] = { 0x12, 0, 0, 0, 36, 0 };
/*static char SPC_TEST[]={0,0,0,0,0,0};*/
static unsigned char SPC_PREVENT[] = { 0x1e, 0, 0, 0, 1, 0 };
@ -40,28 +41,84 @@ static unsigned char SPC_MODE_SELECT[] =
static unsigned char SPC_REQUEST_SENSE[] = { 0x03, 0, 0, 0, 18, 0 };
static unsigned char SPC_TEST_UNIT_READY[] = { 0x00, 0, 0, 0, 0, 0 };
int spc_test_unit_ready(struct burn_drive *d)
/* ts A70519 : An initializer for the abstract SCSI command structure */
int scsi_init_command(struct command *c, unsigned char *opcode, int oplen)
{
if (oplen > 16)
return 0;
memcpy(c->opcode, opcode, oplen);
c->oplen = oplen;
c->dir = NO_TRANSFER;
c->dxfer_len = -1;
memset(c->sense, 0, sizeof(c->sense));
c->error = 0;
c->retry = 0;
c->page = NULL;
return 1;
}
int spc_test_unit_ready_r(struct burn_drive *d, int *key, int *asc, int *ascq)
{
struct command c;
c.retry = 0;
scsi_init_command(&c, SPC_TEST_UNIT_READY,sizeof(SPC_TEST_UNIT_READY));
/*
c.oplen = sizeof(SPC_TEST_UNIT_READY);
memcpy(c.opcode, SPC_TEST_UNIT_READY, sizeof(SPC_TEST_UNIT_READY));
c.page = NULL;
*/
c.retry = 0;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
if (c.error)
if (c.error) {
*key= c.sense[2];
*asc= c.sense[12];
*ascq= c.sense[13];
return (c.sense[2] & 0xF) == 0;
}
return 1;
}
int spc_test_unit_ready(struct burn_drive *d)
{
int key,asc,ascq;
return spc_test_unit_ready_r(d, &key, &asc, &ascq);
}
/* ts A70315 */
/** Wait until the drive state becomes clear or until max_usec elapsed */
int spc_wait_unit_attention(struct burn_drive *d, int max_sec)
{
int i, ret, key, asc, ascq;
for(i=0; i < max_sec; i++) {
ret = spc_test_unit_ready_r(d, &key, &asc, &ascq);
if(ret > 0 || key!=0x2 || asc!=0x4) /* ready or error */
break;
usleep(1000000);
}
if (i < max_sec)
return (ret > 0);
return 0;
}
void spc_request_sense(struct burn_drive *d, struct buffer *buf)
{
struct command c;
scsi_init_command(&c, SPC_REQUEST_SENSE, sizeof(SPC_REQUEST_SENSE));
c.retry = 0;
/*
c.oplen = sizeof(SPC_REQUEST_SENSE);
memcpy(c.opcode, SPC_REQUEST_SENSE, sizeof(SPC_REQUEST_SENSE));
*/
c.dxfer_len= c.opcode[4];
c.retry = 0;
c.page = buf;
c.page->sectors = 0;
c.page->bytes = 0;
@ -83,24 +140,29 @@ void spc_inquiry(struct burn_drive *d)
struct burn_scsi_inquiry_data *id;
struct command c;
scsi_init_command(&c, SPC_INQUIRY, sizeof(SPC_INQUIRY));
/*
memcpy(c.opcode, SPC_INQUIRY, sizeof(SPC_INQUIRY));
c.retry = 1;
c.oplen = sizeof(SPC_INQUIRY);
*/
c.dxfer_len= (c.opcode[3] << 8) | c.opcode[4];
c.retry = 1;
c.page = &buf;
c.page->bytes = 0;
c.page->sectors = 0;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
id = (struct burn_scsi_inquiry_data *)d->idata;
id->vendor[8] = 0;
id->product[16] = 0;
id->revision[4] = 0;
memset(id->vendor, 0, 9);
memset(id->product, 0, 17);
memset(id->revision, 0, 5);
if (c.error) {
id->valid = -1;
return;
}
memcpy(id->vendor, c.page->data + 8, 8);
memcpy(id->product, c.page->data + 16, 16);
memcpy(id->revision, c.page->data + 32, 4);
id->valid = 1;
return;
}
@ -109,10 +171,13 @@ void spc_prevent(struct burn_drive *d)
{
struct command c;
scsi_init_command(&c, SPC_PREVENT, sizeof(SPC_PREVENT));
/*
memcpy(c.opcode, SPC_PREVENT, sizeof(SPC_PREVENT));
c.retry = 1;
c.oplen = sizeof(SPC_PREVENT);
c.page = NULL;
*/
c.retry = 1;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
}
@ -121,19 +186,27 @@ void spc_allow(struct burn_drive *d)
{
struct command c;
scsi_init_command(&c, SPC_ALLOW, sizeof(SPC_ALLOW));
/*
memcpy(c.opcode, SPC_ALLOW, sizeof(SPC_ALLOW));
c.retry = 1;
c.oplen = sizeof(SPC_ALLOW);
c.page = NULL;
*/
c.retry = 1;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
}
void spc_sense_caps(struct burn_drive *d)
/*
ts A70518 : Do not call with *alloc_len < 8
*/
/** flag&1= do only inquire alloc_len */
static int spc_sense_caps_al(struct burn_drive *d, int *alloc_len, int flag)
{
struct buffer buf;
struct scsi_mode_data *m;
int size, page_length, num_write_speeds = 0, i, speed, ret;
int old_alloc_len, was_error = 0;
unsigned char *page;
struct command c;
struct burn_speed_descriptor *sd;
@ -141,15 +214,30 @@ void spc_sense_caps(struct burn_drive *d)
/* ts A61225 : 1 = report about post-MMC-1 speed descriptors */
static int speed_debug = 0;
if (*alloc_len < 8)
return 0;
memset(&buf, 0, sizeof(buf));
scsi_init_command(&c, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
/*
memcpy(c.opcode, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
c.retry = 1;
c.oplen = sizeof(SPC_MODE_SENSE);
*/
c.dxfer_len = *alloc_len;
c.opcode[7] = (c.dxfer_len >> 8) & 0xff;
c.opcode[8] = c.dxfer_len & 0xff;
c.retry = 1;
c.opcode[2] = 0x2A;
c.page = &buf;
c.page->bytes = 0;
c.page->sectors = 0;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
if (c.error) {
memset(&buf, 0, sizeof(buf));
d->mdata->valid = -1;
was_error = 1;
}
size = c.page->data[0] * 256 + c.page->data[1];
m = d->mdata;
@ -162,6 +250,14 @@ void spc_sense_caps(struct burn_drive *d)
set of speed descriptors. In MMC-5 E.11 it is declared "legacy".
*/
page_length = page[1];
old_alloc_len = *alloc_len;
*alloc_len = page_length + 8;
if (flag & 1)
return !was_error;
if (page_length + 8 > old_alloc_len)
page_length = old_alloc_len - 8;
if (page_length < 22)
return 0;
m->valid = 0;
burn_mdata_free_subs(m);
@ -211,6 +307,18 @@ void spc_sense_caps(struct burn_drive *d)
num_write_speeds = page[30] * 256 + page[31];
m->max_write_speed = m->min_write_speed = m->cur_write_speed;
if (32 + 4 * num_write_speeds > page_length + 2) {
char msg[161];
sprintf(msg, "Malformed capabilities page 2Ah received (len=%d, #speeds=%d)", page_length, num_write_speeds);
libdax_msgs_submit(libdax_messenger, d->global_index,
0x0002013c,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
msg, 0, 0);
return 0;
}
for (i = 0; i < num_write_speeds; i++) {
speed = page[32 + 4*i + 2] * 256 + page[32 + 4*i + 3];
@ -252,6 +360,24 @@ try_mmc_get_performance:;
fprintf(stderr,
"LIBBURN_DEBUG: ACh min_write_speed = %d , max_write_speed = %d\n",
m->min_write_speed, m->max_write_speed);
return !was_error;
}
void spc_sense_caps(struct burn_drive *d)
{
int alloc_len, start_len = 22, ret;
/* first command execution to learn Allocation Length */
alloc_len = start_len;
ret = spc_sense_caps_al(d, &alloc_len, 1);
/*
fprintf(stderr,"LIBBURN_DEBUG: 5Ah alloc_len = %d , ret = %d\n",
alloc_len, ret);
*/
if (alloc_len >= start_len && ret > 0)
/* second execution with announced length */
spc_sense_caps_al(d, &alloc_len, 0);
}
@ -259,13 +385,19 @@ void spc_sense_error_params(struct burn_drive *d)
{
struct buffer buf;
struct scsi_mode_data *m;
int size;
int size, alloc_len = 12 ;
unsigned char *page;
struct command c;
scsi_init_command(&c, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
/*
memcpy(c.opcode, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
c.retry = 1;
c.oplen = sizeof(SPC_MODE_SENSE);
*/
c.dxfer_len = alloc_len;
c.opcode[7] = (c.dxfer_len >> 8) & 0xff;
c.opcode[8] = c.dxfer_len & 0xff;
c.retry = 1;
c.opcode[2] = 0x01;
c.page = &buf;
c.page->bytes = 0;
@ -287,9 +419,12 @@ void spc_select_error_params(struct burn_drive *d,
struct buffer buf;
struct command c;
scsi_init_command(&c, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
/*
memcpy(c.opcode, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
c.retry = 1;
c.oplen = sizeof(SPC_MODE_SELECT);
*/
c.retry = 1;
c.opcode[8] = 8 + 2 + d->mdata->retry_page_length;
c.page = &buf;
c.page->bytes = 0;
@ -318,7 +453,7 @@ void spc_sense_write_params(struct burn_drive *d)
{
struct buffer buf;
struct scsi_mode_data *m;
int size;
int size, dummy, alloc_len = 10;
unsigned char *page;
struct command c;
@ -326,9 +461,15 @@ void spc_sense_write_params(struct burn_drive *d)
/* a ssert(d->mdata->cdr_write || d->mdata->cdrw_write ||
d->mdata->dvdr_write || d->mdata->dvdram_write); */
scsi_init_command(&c, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
/*
memcpy(c.opcode, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
c.retry = 1;
c.oplen = sizeof(SPC_MODE_SENSE);
*/
c.dxfer_len = alloc_len;
c.opcode[7] = (c.dxfer_len >> 8) & 0xff;
c.opcode[8] = c.dxfer_len & 0xff;
c.retry = 1;
c.opcode[2] = 0x05;
c.page = &buf;
c.page->bytes = 0;
@ -343,26 +484,35 @@ void spc_sense_write_params(struct burn_drive *d)
m->write_page_length = page[1];
m->write_page_valid = 1;
mmc_read_disc_info(d);
/* ts A70212 : try to setup d->media_capacity_remaining */
if (d->current_profile == 0x1a || d->current_profile == 0x13 ||
d->current_profile == 0x12)
d->read_format_capacities(d, -1);
else if (d->status == BURN_DISC_BLANK ||
(d->current_is_cd_profile && d->status == BURN_DISC_APPENDABLE)) {
d->get_nwa(d, -1, &dummy, &dummy);
}
/* others are hopefully up to date from mmc_read_disc_info() */
/*
fprintf(stderr, "LIBBURN_DEBUG: media_capacity_remaining = %.f\n",
(double) d->media_capacity_remaining);
*/
}
/* ts A61229 */
#define Libburn_mmc_compose_mode_page_5 1
/* remark ts A61104 :
Although command MODE SELECT is SPC, the content of the
Write Parameters Mode Page (05h) is MMC (Table 108 in MMC-1).
Thus the filling of the mode page should be done by a mmc_ function.
Thus the filling of the mode page is done by mmc_compose_mode_page_5().
*/
void spc_select_write_params(struct burn_drive *d,
const struct burn_write_opts *o)
{
struct buffer buf;
struct command c;
#ifndef Libburn_mmc_compose_mode_page_5
int bufe, sim;
#endif
/* ts A61007 : All current callers are safe. */
/* a ssert(o->drive == d); */
@ -374,9 +524,12 @@ void spc_select_write_params(struct burn_drive *d,
o->block_type,spc_block_type(o->block_type));
*/
scsi_init_command(&c, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
/*
memcpy(c.opcode, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
c.retry = 1;
c.oplen = sizeof(SPC_MODE_SELECT);
*/
c.retry = 1;
c.opcode[8] = 8 + 2 + d->mdata->write_page_length;
c.page = &buf;
c.page->bytes = 0;
@ -391,40 +544,10 @@ void spc_select_write_params(struct burn_drive *d,
burn_print(12, "using write page length %d (valid %d)\n",
d->mdata->write_page_length, d->mdata->write_page_valid);
#ifdef Libburn_mmc_compose_mode_page_5
/* ts A61229 */
if (mmc_compose_mode_page_5(d, o, c.page->data + 8) <= 0)
return;
#else
c.page->data[8] = 5;
c.page->data[9] = d->mdata->write_page_length;
bufe = o->underrun_proof;
sim = o->simulate;
c.page->data[10] = (bufe << 6)
+ (sim << 4)
+ o->write_type;
/* ts A61106 : MMC-1 table 110 : multi==0 or multi==3 */
c.page->data[11] = ((3 * !!o->multi) << 6) | o->control;
c.page->data[12] = spc_block_type(o->block_type);
/* ts A61104 */
if(!(o->control&4)) /* audio (MMC-1 table 61) */
if(o->write_type == BURN_WRITE_TAO) /* ??? for others too ? */
c.page->data[12] = 0; /* Data Block Type: Raw Data */
c.page->data[22] = 0;
c.page->data[23] = 150; /* audio pause length */
/*XXX need session format! */
#endif /* ! Libburn_mmc_compose_mode_page_5 */
c.dir = TO_DRIVE;
d->issue_command(d, &c);
}
@ -434,16 +557,9 @@ void spc_getcaps(struct burn_drive *d)
spc_inquiry(d);
spc_sense_caps(d);
spc_sense_error_params(d);
/* <<< for debugging. >>> ??? to be fixely included here ?
mmc_read_format_capacities(d, -1);
*/
}
/*
only called when a blank is present, so we set type to blank
(on the last pass)
don't check totally stupid modes (raw/raw0)
some drives say they're ok, and they're not.
*/
@ -453,15 +569,30 @@ void spc_probe_write_modes(struct burn_drive *d)
struct buffer buf;
int try_write_type = 1;
int try_block_type = 0;
int key, asc, ascq;
int key, asc, ascq, useable_write_type = -1, useable_block_type = -1;
int last_try = 0;
struct command c;
while (try_write_type != 4) {
/* ts A70213 : added pseudo try_write_type 4 to set a suitable mode */
while (try_write_type != 5) {
burn_print(9, "trying %d, %d\n", try_write_type,
try_block_type);
/* ts A70213 */
if (try_write_type == 4) {
/* Pseudo write type NONE . Set a useable write mode */
if (useable_write_type == -1)
break;
try_write_type = useable_write_type;
try_block_type = useable_block_type;
last_try= 1;
}
scsi_init_command(&c, SPC_MODE_SELECT,sizeof(SPC_MODE_SELECT));
/*
memcpy(c.opcode, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
c.retry = 1;
c.oplen = sizeof(SPC_MODE_SELECT);
*/
c.retry = 1;
c.opcode[8] = 8 + 2 + 0x32;
c.page = &buf;
@ -483,6 +614,9 @@ void spc_probe_write_modes(struct burn_drive *d)
d->issue_command(d, &c);
d->silent_on_scsi_error = 0;
if (last_try)
break;
key = c.sense[2];
asc = c.sense[12];
ascq = c.sense[13];
@ -498,6 +632,15 @@ void spc_probe_write_modes(struct burn_drive *d)
else
d->block_types[try_write_type] |=
1 << try_block_type;
/* ts A70213 */
if ((useable_write_type < 0 && try_write_type > 0) ||
(try_write_type == 1 && try_block_type == 8)) {
/* Packet is not supported yet.
Prefer TAO MODE_1. */
useable_write_type = try_write_type;
useable_block_type = try_block_type;
}
}
switch (try_block_type) {
case 0:

View File

@ -20,8 +20,16 @@ void spc_probe_write_modes(struct burn_drive *);
void spc_request_sense(struct burn_drive *d, struct buffer *buf);
int spc_block_type(enum burn_block_types b);
int spc_get_erase_progress(struct burn_drive *d);
/* ts A70315 : test_unit_ready with result parameters */
int spc_test_unit_ready_r(struct burn_drive *d, int *key, int *asc, int *ascq);
int spc_test_unit_ready(struct burn_drive *d);
/* ts A70315 */
/** Wait until the drive state becomes clear in or until max_sec elapsed */
int spc_wait_unit_attention(struct burn_drive *d, int max_sec);
/* ts A61021 : the spc specific part of sg.c:enumerate_common()
*/
int spc_setup_drive(struct burn_drive *d);
@ -47,4 +55,7 @@ enum response scsi_error_msg(struct burn_drive *d, unsigned char *sense,
int scsi_notify_error(struct burn_drive *, struct command *c,
unsigned char *sense, int senselen, int flag);
/* ts A70519 */
int scsi_init_command(struct command *c, unsigned char *opcode, int oplen);
#endif /*__SPC*/

View File

@ -113,6 +113,12 @@ struct burn_track *burn_track_create(void)
t->mode = BURN_MODE1;
t->isrc.has_isrc = 0;
t->pad = 1;
/* ts A70213 */
t->fill_up_media = 0;
/* ts A70218 */
t->default_size = 0;
t->entry = NULL;
t->source = NULL;
t->eos = 0;
@ -317,7 +323,8 @@ void burn_track_clear_isrc(struct burn_track *t)
int burn_track_get_sectors(struct burn_track *t)
{
int size;
/* ts A70125 : was int */
off_t size;
int sectors, seclen;
seclen = burn_sector_length(t->mode);
@ -329,12 +336,92 @@ int burn_track_get_sectors(struct burn_track *t)
return sectors;
}
/* ts A70125 */
int burn_track_set_sectors(struct burn_track *t, int sectors)
{
off_t size, seclen;
int ret;
seclen = burn_sector_length(t->mode);
size = seclen * (off_t) sectors - (off_t) t->offset - (off_t) t->tail;
if (size < 0)
return 0;
ret = t->source->set_size(t->source, size);
t->open_ended = (t->source->get_size(t->source) <= 0);
return ret;
}
/* ts A70218 , API since A70328 */
int burn_track_set_size(struct burn_track *t, off_t size)
{
if (t->source == NULL)
return 0;
if (t->source->set_size == NULL)
return 0;
t->open_ended = (size <= 0);
return t->source->set_size(t->source, size);
}
/* ts A70213 */
int burn_track_set_fillup(struct burn_track *t, int fill_up_media)
{
t->fill_up_media = fill_up_media;
if (fill_up_media)
t->open_ended = 0;
return 1;
}
/* ts A70213 */
/**
@param flag bit0= force new size even if existing track size is larger
*/
int burn_track_apply_fillup(struct burn_track *t, off_t max_size, int flag)
{
int max_sectors, ret = 2;
char msg[160];
if (t->fill_up_media <= 0)
return 2;
max_sectors = max_size / 2048;
if (burn_track_get_sectors(t) < max_sectors || (flag & 1)) {
sprintf(msg, "Setting total track size to %ds (payload %ds)\n",
max_sectors, (int) (t->source->get_size(t->source)/2048));
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
msg, 0, 0);
ret = burn_track_set_sectors(t, max_sectors);
t->open_ended = 0;
}
return ret;
}
/* ts A61031 */
int burn_track_is_open_ended(struct burn_track *t)
{
return !!t->open_ended;
}
/* ts A70218 : API */
int burn_track_set_default_size(struct burn_track *t, off_t size)
{
t->default_size = size;
return 1;
}
/* ts A70218 */
off_t burn_track_get_default_size(struct burn_track *t)
{
return t->default_size;
}
/* ts A61101 : API function */
int burn_track_get_counters(struct burn_track *t,
off_t *read_bytes, off_t *written_bytes)

View File

@ -27,6 +27,13 @@ struct burn_track
int tailcount;
/** 1 means Pad with zeros, 0 means start reading the next track */
int pad;
/* ts A70213 : wether to expand this track to full available media */
int fill_up_media;
/* ts A70218 : a track size to use if it is mandarory to have some */
off_t default_size;
/** Data source */
struct burn_source *source;
/** End of Source flag */
@ -88,5 +95,18 @@ int burn_track_get_shortage(struct burn_track *t);
int burn_track_is_open_ended(struct burn_track *t);
int burn_track_is_data_done(struct burn_track *t);
/* ts A70125 : sets overall sectors of a track: offset+payload+padding */
int burn_track_set_sectors(struct burn_track *t, int sectors);
/* ts A70218 : sets the payload size alone */
int burn_track_set_size(struct burn_track *t, off_t size);
/* ts A70213 */
int burn_track_set_fillup(struct burn_track *t, int fill_up_media);
int burn_track_apply_fillup(struct burn_track *t, off_t max_size, int flag);
/* ts A70218 */
off_t burn_track_get_default_size(struct burn_track *t);
#endif /* BURN__STRUCTURE_H */

View File

@ -128,9 +128,14 @@ void toc_find_modes(struct burn_drive *d)
if (e && !(e->control & 4)) {
t->mode = BURN_AUDIO;
} else {
t->mode = BURN_MODE1;
/* ts A70519 : this does not work with Linux 2.4 USB because one cannot
predict the exact dxfer_size without knowing the sector type.
mem.sectors = 1;
d->read_sectors(d, lba, mem.sectors, &o, &mem);
t->mode = sector_identify(mem.data);
*/
}
}
}

View File

@ -51,6 +51,7 @@ struct command
unsigned char opcode[16];
int oplen;
int dir;
int dxfer_len;
unsigned char sense[128];
int error;
int retry;
@ -117,8 +118,6 @@ struct burn_format_descr {
};
#define LIBBURN_SG_MAX_SIBLINGS 16
/** Gets initialized in enumerate_common() and burn_drive_register() */
struct burn_drive
{
@ -129,6 +128,9 @@ struct burn_drive
int lun;
char *devname;
/* ts A70302: mmc5r03c.pdf 5.3.2 Physical Interface Standard */
int phys_if_std; /* 1=SCSI, 2=ATAPI, 3,4,6=FireWire, 7=SATA, 8=USB */
char phys_if_name[80]; /* MMC-5 5.3.2 table 91 , e.g. "SCSI Family" */
/* see os.h for name of particular os-*.h where this is defined */
BURN_OS_TRANSPORT_DRIVE_ELEMENTS
@ -152,11 +154,29 @@ struct burn_drive
int current_is_cd_profile;
int current_is_supported_profile;
/* ts A70128 : MMC-to-MMC feature info from 46h for DVD-RW.
Quite internal. Regard as opaque :)
*/
/* 1 = incremental recording available, 0 = not available */
int current_has_feat21h;
/* Link Size item number 0 from feature 0021h descriptor */
int current_feat21h_link_size;
/* Flags from feature 002Fh feature descriptor mmc5r03c.pdf 5.3.25 :
bit1= DVD-RW supported
bit2= Test Write available
bit3= DVD-R DL supported
bit6= Buffer Under-run Free recording available (page 05h BUFE)
Value -1 indicates that no 002Fh was current in the features list.
*/
int current_feat2fh_byte4;
/* ts A70114 : wether a DVD-RW media holds an incomplete session
(which could need closing after write) */
int dvd_minus_rw_incomplete;
int needs_close_session;
/* ts A61218 from 46h GET CONFIGURATION */
/* ts A61218 from 51h READ DISC INFORMATION */
int bg_format_status; /* 0=needs format start, 1=needs format restart*/
/* ts A70108 from 23h READ FORMAT CAPACITY mmc5r03c.pdf 6.24 */
@ -181,12 +201,44 @@ struct burn_drive
int rlba; /* relative lba in section */
int start_lba;
int end_lba;
/* ts A70131 : from 51h READ DISC INFORMATION Number of Sessions (-1)*/
int complete_sessions;
/* ts A70129 :
from 51h READ DISC INFORMATION Last Track Number in Last Session */
int last_track_no;
/* ts A70212 : from various sources : free space on media (in bytes)
With CD this might change after particular write
parameters have been set and nwa has been inquired.
(e.g. by d->send_write_parameters() ; d->get_nwa()).
*/
off_t media_capacity_remaining;
/* ts A70215 : if > 0 : first lba on media that is too high for write*/
int media_lba_limit;
int toc_temp;
struct burn_disc *disc; /* disc structure */
int block_types[4];
struct buffer *buffer;
struct burn_progress progress;
/* ts A70711 : keeping an eye on the drive buffer */
off_t pessimistic_buffer_free;
int pbf_altered;
int wait_for_buffer_free;
int nominal_write_speed;
unsigned wfb_min_usec;
unsigned wfb_max_usec;
unsigned wfb_timeout_sec;
unsigned wfb_min_percent;
unsigned wfb_max_percent;
unsigned pessimistic_writes;
unsigned waited_writes;
unsigned waited_tries;
unsigned waited_usec;
volatile int cancel;
volatile enum burn_drive_status busy;
/* transport functions */
@ -224,10 +276,19 @@ struct burn_drive
void (*send_write_parameters) (struct burn_drive *,
const struct burn_write_opts *);
void (*send_cue_sheet) (struct burn_drive *, struct cue_sheet *);
/* ts A70205 : Announce size of a DVD-R[W] DAO session. */
int (*reserve_track) (struct burn_drive *d, off_t size);
void (*sync_cache) (struct burn_drive *);
int (*get_erase_progress) (struct burn_drive *);
int (*get_nwa) (struct burn_drive *, int trackno, int *lba, int *nwa);
/* ts A70131 : obtain (possibly fake) TOC number and start lba of
first track in last complete session */
int (*read_multi_session_c1)(struct burn_drive *d,
int *trackno, int *start);
/* ts A61009 : removed d in favor of o->drive */
/* void (*close_disc) (struct burn_drive * d,
struct burn_write_opts * o);

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,8 @@ int burn_sector_length(int trackmode);
int burn_subcode_length(int trackmode);
/* ts A61009 */
int burn_disc_write_is_ok(struct burn_write_opts *o, struct burn_disc *disc);
int burn_disc_write_is_ok(struct burn_write_opts *o, struct burn_disc *disc,
int flag);
void burn_disc_write_sync(struct burn_write_opts *o, struct burn_disc *disc);
int burn_write_leadin(struct burn_write_opts *o,
@ -32,4 +33,16 @@ int burn_write_close_track(struct burn_write_opts *o, struct burn_session *s,
int tnum);
int burn_write_close_session(struct burn_write_opts *o,struct burn_session *s);
/* mmc5r03c.pdf 6.3.3.3.3: DVD-R DL: Close Function 010b: Close Session
"When the recording mode is Incremental Recording,
the disc is single session."
Enable this macro to get away from growisofs which uses Close Session
but also states "// DVD-R DL Seq has no notion of multi-session".
#define Libburn_dvd_r_dl_multi_no_close_sessioN 1
*/
#endif /* BURN__WRITE_H */

View File

@ -8,8 +8,9 @@
libburner is a minimal demo application for the library libburn as provided
on http://libburnia.pykix.org . It can list the available devices, can
blank a CD-RW, can format a DVD-RW, and can burn to CD-R, CD-RW, DVD+RW,
DVD-RAM or DVD-RW.
blank a CD-RW or DVD-RW, can format a DVD-RW, can burn to CD-R, CD-RW, DVD-R,
DVD+R, DVD+RW, DVD-RAM or DVD-RW. Not supported yet: double layer media.
It's main purpose, nevertheless, is to show you how to use libburn and also
to serve the libburnia team as reference application. libburner.c does indeed
define the standard way how above three gestures can be implemented and
@ -261,19 +262,21 @@ int libburner_blank_disc(struct burn_drive *drive, int blank_fast)
{
enum burn_disc_status disc_state;
struct burn_progress p;
int percent = 1;
double percent = 1.0;
disc_state = burn_disc_get_status(drive);
printf(
"Drive media status: %d (see libburn/libburn.h BURN_DISC_*)\n",
disc_state);
if (disc_state == BURN_DISC_BLANK) {
if (current_profile == 0x13) {
; /* formatted DVD-RW will get blanked to sequential state */
} else if (disc_state == BURN_DISC_BLANK) {
fprintf(stderr,
"IDLE: Blank media detected. Will leave it untouched\n");
return 2;
} else if (disc_state == BURN_DISC_FULL ||
disc_state == BURN_DISC_APPENDABLE) {
; /* this is what libburn is willing to blank */
; /* this is what libburner is willing to blank */
} else if (disc_state == BURN_DISC_EMPTY) {
fprintf(stderr,"FATAL: No media detected in drive\n");
return 0;
@ -295,7 +298,7 @@ int libburner_blank_disc(struct burn_drive *drive, int blank_fast)
if(p.sectors>0 && p.sector>=0) /* display 1 to 99 percent */
percent = 1.0 + ((double) p.sector+1.0)
/ ((double) p.sectors) * 98.0;
printf("Blanking ( %d%% done )\n", percent);
printf("Blanking ( %.1f%% done )\n", percent);
sleep(1);
}
printf("Done\n");
@ -303,15 +306,16 @@ int libburner_blank_disc(struct burn_drive *drive, int blank_fast)
}
/** Persistently changes DVD-RW profile 0014h "Sequential Recording"
to profile 0013h "Restricted Overwrite" which is usable with libburner.
/** Persistently changes DVD-RW profile 0014h "Sequential Recording" to
profile 0013h "Restricted Overwrite" which needs no blanking for re-use
but is not capable of multi-session.
Expect a behavior similar to blanking with unusual noises from the drive.
*/
int libburner_format_row(struct burn_drive *drive)
{
struct burn_progress p;
int percent = 1;
double percent = 1.0;
if (current_profile == 0x13) {
fprintf(stderr, "IDLE: DVD-RW media is already formatted\n");
@ -328,7 +332,7 @@ int libburner_format_row(struct burn_drive *drive)
if(p.sectors>0 && p.sector>=0) /* display 1 to 99 percent */
percent = 1.0 + ((double) p.sector+1.0)
/ ((double) p.sectors) * 98.0;
printf("Formatting ( %d%% done )\n", percent);
printf("Formatting ( %.1f%% done )\n", percent);
sleep(1);
}
burn_disc_get_profile(drive_list[0].drive, &current_profile,
@ -346,11 +350,14 @@ int libburner_format_row(struct burn_drive *drive)
/** Brings preformatted track images (ISO 9660, audio, ...) onto media.
To make sure a data image is fully readable on any Linux machine, this
function adds 300 kB of padding to the (usualy single) track.
function adds 300 kiB of padding to the (usualy single) track.
Audio tracks get padded to complete their last sector.
In case of external signals expect abort handling of an ongoing burn to
last up to a minute. Wait the normal burning timespan before any kill -9.
For simplicity, this function allows memory leaks in case of failure.
In apps which do not abort immediately, one should clean up better.
*/
int libburner_payload(struct burn_drive *drive,
char source_adr[][4096], int source_adr_count,
@ -364,14 +371,14 @@ int libburner_payload(struct burn_drive *drive,
struct burn_track *track, *tracklist[99];
struct burn_progress progress;
time_t start_time;
int last_sector = 0, padding = 0, trackno, write_mode_tao = 0, fd;
int last_sector = 0, padding = 0, trackno, unpredicted_size = 0, fd;
off_t fixed_size;
char *adr;
char *adr, reasons[BURN_REASONS_LEN];
struct stat stbuf;
if (all_tracks_type != BURN_AUDIO) {
all_tracks_type = BURN_MODE1;
/* a padding of 300 kB helps to avoid the read-ahead bug */
/* a padding of 300 kiB helps to avoid the read-ahead bug */
padding = 300*1024;
}
@ -395,7 +402,7 @@ int libburner_payload(struct burn_drive *drive,
fixed_size = stbuf.st_size;
}
if (fixed_size==0)
write_mode_tao = 1;
unpredicted_size = 1;
data_src = NULL;
if (fd>=0)
data_src = burn_fd_source_new(fd, -1, fixed_size);
@ -419,9 +426,8 @@ int libburner_payload(struct burn_drive *drive,
/* Evaluate drive and media */
disc_state = burn_disc_get_status(drive);
if (disc_state == BURN_DISC_APPENDABLE) {
write_mode_tao = 1;
} else if (disc_state != BURN_DISC_BLANK) {
if (disc_state != BURN_DISC_BLANK &&
disc_state != BURN_DISC_APPENDABLE) {
if (disc_state == BURN_DISC_FULL) {
fprintf(stderr, "FATAL: Closed media with data detected. Need blank or appendable media.\n");
if (burn_disc_erasable(drive))
@ -437,18 +443,17 @@ int libburner_payload(struct burn_drive *drive,
burn_options = burn_write_opts_new(drive);
burn_write_opts_set_perform_opc(burn_options, 0);
burn_write_opts_set_multi(burn_options, !!multi);
if (write_mode_tao)
burn_write_opts_set_write_type(burn_options,
BURN_WRITE_TAO, BURN_BLOCK_MODE1);
else
burn_write_opts_set_write_type(burn_options,
BURN_WRITE_SAO, BURN_BLOCK_SAO);
if(simulate_burn)
printf("\n*** Will TRY to SIMULATE burning ***\n\n");
burn_write_opts_set_simulate(burn_options, simulate_burn);
burn_structure_print_disc(target_disc);
burn_drive_set_speed(drive, 0, 0);
burn_write_opts_set_underrun_proof(burn_options, 1);
if (burn_write_opts_auto_write_type(burn_options, target_disc,
reasons, 0) == BURN_WRITE_NONE) {
fprintf(stderr, "FATAL: Failed to find a suitable write mode with this media.\n");
fprintf(stderr, "Reasons given:\n%s\n", reasons);
return 0;
}
printf("Burning starts. With e.g. 4x media expect up to a minute of zero progress.\n");
start_time = time(0);
@ -462,7 +467,7 @@ int libburner_payload(struct burn_drive *drive,
printf(
"Thank you for being patient since %d seconds.\n",
(int) (time(0) - start_time));
else if(write_mode_tao)
else if(unpredicted_size)
printf("Track %d : sector %d\n", progress.track+1,
progress.sector);
else
@ -498,8 +503,6 @@ static int all_tracks_type = BURN_MODE1;
/** Converts command line arguments into above setup parameters.
drive_adr[] must provide at least BURN_DRIVE_ADR_LEN bytes.
source_adr[] must provide at least 4096 bytes.
*/
int libburner_setup(int argc, char **argv)
{
@ -590,9 +593,11 @@ int libburner_setup(int argc, char **argv)
printf(" %s --drive /dev/hdc my_image_file\n", argv[0]);
printf("Blank a used CD-RW (is combinable with burning in one run):\n");
printf(" %s --drive /dev/hdc --blank_fast\n",argv[0]);
printf("Format a DVD-RW once before first use with libburner:\n");
printf("Blank a used DVD-RW (is combinable with burning in one run):\n");
printf(" %s --drive /dev/hdc --blank_full\n",argv[0]);
printf("Format a DVD-RW to avoid need for blanking before re-use:\n");
printf(" %s --drive /dev/hdc --format_overwrite\n", argv[0]);
printf("Burn two audio tracks:\n");
printf("Burn two audio tracks (to CD only):\n");
printf(" lame --decode -t /path/to/track1.mp3 track1.cd\n");
printf(" test/dewav /path/to/track2.wav -o track2.cd\n");
printf(" %s --drive /dev/hdc --audio track1.cd track2.cd\n", argv[0]);

133
test/open-cd-excl.c Normal file
View File

@ -0,0 +1,133 @@
/*
* open-cd-excl.c --- This program tries to open a block device
* by various exclusive and non-exclusive gestures in order to explore
* their impact on running CD/DVD recordings.
*
* Copyright 2007, by Theodore Ts'o.
*
* Detail modifications 2007, by Thomas Schmitt.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#define _GNU_SOURCE /* for O_LARGEFILE *//*ts A70417: or _LARGEFILE64_SOURCE */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <getopt.h>
const char *progname;
static void usage(void)
{
fprintf(stderr, "Usage: %s [-feirw] device\n", progname);
exit(1);
}
/* ts A70417: added parameter do_rdwr */
static void init_flock(struct flock *fl, int do_rdwr)
{
memset(fl, 0, sizeof(struct flock));
if (do_rdwr)
fl->l_type = F_WRLCK;
else
fl->l_type = F_RDLCK;
fl->l_whence = SEEK_SET;
fl->l_start = 0;
fl->l_len = 0;
}
int main(int argc, char **argv)
{
struct flock fl;
char *device_name;
int fd, c, f_opt = 0, do_rdwr = 0, end_immediately = 0;
int flags = O_NONBLOCK|O_LARGEFILE;
progname = argv[0];
/* ts A70417: added -w , -r , -i */
while ((c = getopt (argc, argv, "feirw")) != EOF) {
switch (c) {
case 'e':
flags |= O_EXCL;
break;
case 'f':
f_opt++;
break;
case 'i':
end_immediately = 1;
break;
case 'r':
do_rdwr = 0;
break;
case 'w':
do_rdwr = 1;
break;
case '?':
usage();
exit(1);
}
}
if (optind == argc)
usage();
device_name = argv[optind++];
/* ts A70417 : made read-write adjustable independently of f_opt */
if (do_rdwr) {
flags |= O_RDWR;
printf("Using O_RDWR\n");
} else {
flags |= O_RDONLY;
printf("Using O_RDONLY\n");
}
if (flags & O_EXCL)
printf("Trying to open %s with O_EXCL ...\n", device_name);
fd = open(device_name, flags, 0);
if (fd < 0) {
perror("open");
printf("failed\n");
exit(1);
}
if (flags & O_EXCL)
printf("succeeded\n");
if (f_opt) {
init_flock(&fl, do_rdwr);
if (fcntl(fd, F_GETLK, &fl) < 0) {
perror("fcntl: F_GETLK: ");
exit(1);
}
printf("fcntl lock apparently %sLOCKED\n",
(fl.l_type == F_UNLCK) ? "NOT " : "");
init_flock(&fl, do_rdwr);
printf("Trying to grab fcntl lock...\n");
if (fcntl(fd, F_SETLK, &fl) < 0) {
perror("fcntl: F_SETLK: ");
printf("failed\n");
exit(1);
}
printf("succeeded\n");
}
/* ts A70417: added end_immediately */
printf("Holding %s open.\n", device_name);
usleep(100000);
if (end_immediately)
exit(0);
printf("Press ^C to exit.\n");
while (1) {
sleep(300);
}
/* NOTREACHED */
return 0;
}

View File

@ -5,9 +5,9 @@
/** Overview
telltoc is a minimal demo application for the library libburn as provided
on http://libburn.pykix.org . It can list the available devices, can display
some drive properties, the type of media, eventual table of content and
multisession info for mkisofs option -C .
on http://libburnia.pykix.org . It can list the available devices, can
display some drive properties, the type of media, eventual table of content
and multisession info for mkisofs option -C .
It's main purpose, nevertheless, is to show you how to use libburn and also
to serve the libburn team as reference application. telltoc.c does indeed
define the standard way how above gestures can be implemented and stay upward
@ -200,11 +200,11 @@ int telltoc_aquire_by_driveno(int *driveno, int silent_drive)
}
/** This gesture is necessary to get my NEC DVD_RW ND-4570A out of a state
of noisy overexcitement after it was inquired for Next Writeable Address.
of noisy overexcitement after its tray was loaded and it then was inquired
for Next Writeable Address.
The noise then still lasts 20 seconds. Same with cdrecord -toc, btw.
It opens a small gap for losing the drive to another libburn instance.
This opens a small gap for losing the drive to another libburn instance.
Not a problem in telltoc. This is done as very last drive operation.
Eventually the other libburn instance will have the same sanitizing effect.
*/
@ -226,8 +226,11 @@ int telltoc_media(struct burn_drive *drive)
{
int ret, media_found = 0, profile_no = -1;
double max_speed = 0.0, min_speed = 0.0, speed_conv;
off_t available = 0;
enum burn_disc_status s;
char profile_name[80], speed_unit[40];
struct burn_multi_caps *caps;
struct burn_write_opts *o = NULL;
printf("Media current: ");
ret = burn_disc_get_profile(drive, &profile_no, profile_name);
@ -250,16 +253,16 @@ int telltoc_media(struct burn_drive *drive)
printf("Media status : ");
s = burn_disc_get_status(drive);
if (s==BURN_DISC_FULL) {
if (s == BURN_DISC_FULL) {
printf("is written , is closed\n");
media_found = 1;
} else if (s==BURN_DISC_APPENDABLE) {
} else if (s == BURN_DISC_APPENDABLE) {
printf("is written , is appendable\n");
media_found = 1;
} else if (s==BURN_DISC_BLANK) {
} else if (s == BURN_DISC_BLANK) {
printf("is blank\n");
media_found = 1;
} else if (s==BURN_DISC_EMPTY)
} else if (s == BURN_DISC_EMPTY)
printf("is not present\n");
else
printf("is not recognizable\n");
@ -273,9 +276,73 @@ int telltoc_media(struct burn_drive *drive)
} else
printf("is not recognizable\n");
ret= burn_drive_get_write_speed(drive);
ret = burn_disc_get_multi_caps(drive, BURN_WRITE_NONE, &caps, 0);
if (ret > 0) {
/* Media appears writeable */
printf("Write multi : ");
printf("%s multi-session , ",
caps->multi_session == 1 ? "allows" : "prohibits");
if (caps->multi_track)
printf("allows multiple tracks\n");
else
printf("enforces single track\n");
printf("Write start : ");
if (caps->start_adr == 1)
printf(
"allows addresses [%.f , %.f]s , alignment=%.fs\n",
(double) caps->start_range_low / 2048 ,
(double) caps->start_range_high / 2048 ,
(double) caps->start_alignment / 2048 );
else
printf("prohibits write start addressing\n");
printf("Write modes : ");
if (caps->might_do_tao)
printf("TAO%s",
caps->advised_write_mode == BURN_WRITE_TAO ?
" (advised)" : "");
if (caps->might_do_sao)
printf("%sSAO%s",
caps->might_do_tao ? " , " : "",
caps->advised_write_mode == BURN_WRITE_SAO ?
" (advised)" : "");
if (caps->might_do_raw)
printf("%sRAW%s",
caps->might_do_tao | caps->might_do_sao ?
" , " : "",
caps->advised_write_mode == BURN_WRITE_RAW ?
" (advised)" : "");
printf("\n");
printf("Write dummy : ");
if (caps->might_simulate)
printf("supposed to work with non-RAW modes\n");
else
printf("will not work\n");
o= burn_write_opts_new(drive);
if (o != NULL) {
burn_write_opts_set_perform_opc(o, 0);
if(caps->advised_write_mode == BURN_WRITE_TAO)
burn_write_opts_set_write_type(o,
BURN_WRITE_TAO, BURN_BLOCK_MODE1);
else if (caps->advised_write_mode == BURN_WRITE_SAO)
burn_write_opts_set_write_type(o,
BURN_WRITE_SAO, BURN_BLOCK_SAO);
else {
burn_write_opts_free(o);
o = NULL;
}
}
available = burn_disc_available_space(drive, o);
printf("Write space : %.1f MiB (%.fs)\n",
((double) available) / 1024.0 / 1024.0,
((double) available) / 2048.0);
burn_disc_free_multi_caps(&caps);
if (o != NULL)
burn_write_opts_free(o);
}
ret = burn_drive_get_write_speed(drive);
max_speed = ((double ) ret) / speed_conv;
ret= burn_drive_get_min_write_speed(drive);
ret = burn_drive_get_min_write_speed(drive);
min_speed = ((double ) ret) / speed_conv;
if (!media_found)
printf("Drive speed : max=%.1f , min=%.1f\n",
@ -286,11 +353,11 @@ int telltoc_media(struct burn_drive *drive)
ret = 0;
if (media_found)
ret= burn_disc_read_atip(drive);
ret = burn_disc_read_atip(drive);
if(ret>0) {
ret= burn_drive_get_min_write_speed(drive);
ret = burn_drive_get_min_write_speed(drive);
min_speed = ((double ) ret) / speed_conv;
ret= burn_drive_get_write_speed(drive);
ret = burn_drive_get_write_speed(drive);
max_speed = ((double ) ret) / speed_conv;
printf("Media speed : max=%.1f , min=%.1f\n",
max_speed, min_speed);
@ -375,7 +442,7 @@ int telltoc_formatlist(struct burn_drive *drive)
int telltoc_toc(struct burn_drive *drive)
{
int num_sessions = 0 , num_tracks = 0 , lba = 0;
int num_sessions = 0 , num_tracks = 0 , lba = 0, pmin, psec, pframe;
int track_count = 0;
int session_no, track_no;
struct burn_disc *disc= NULL;
@ -397,27 +464,36 @@ int telltoc_toc(struct burn_drive *drive)
for(track_no= 0; track_no<num_tracks; track_no++) {
track_count++;
burn_track_get_entry(tracks[track_no], &toc_entry);
lba= burn_msf_to_lba(toc_entry.pmin, toc_entry.psec,
toc_entry.pframe);
if (toc_entry.extensions_valid & 1) {
/* DVD extension valid */
lba = toc_entry.start_lba;
burn_lba_to_msf(lba, &pmin, &psec, &pframe);
} else {
pmin = toc_entry.pmin;
psec = toc_entry.psec;
pframe = toc_entry.pframe;
lba= burn_msf_to_lba(pmin, psec, pframe);
}
printf("Media content: session %2d ", session_no+1);
printf("track %2d %s lba: %9d %2.2u:%2.2u:%2.2u\n",
printf("track %2d %s lba: %9d %4.2d:%2.2d:%2.2d\n",
track_count,
((toc_entry.control&7)<4?"audio":"data "),
lba,
toc_entry.pmin,
toc_entry.psec,
toc_entry.pframe);
lba, pmin, psec, pframe);
}
burn_session_get_leadout_entry(sessions[session_no],
&toc_entry);
lba = burn_msf_to_lba(toc_entry.pmin,
toc_entry.psec, toc_entry.pframe);
if (toc_entry.extensions_valid & 1) {
lba = toc_entry.start_lba;
burn_lba_to_msf(lba, &pmin, &psec, &pframe);
} else {
pmin = toc_entry.pmin;
psec = toc_entry.psec;
pframe = toc_entry.pframe;
lba= burn_msf_to_lba(pmin, psec, pframe);
}
printf("Media content: session %2d ", session_no+1);
printf("leadout lba: %9d %2.2u:%2.2u:%2.2u\n",
lba,
toc_entry.pmin,
toc_entry.psec,
toc_entry.pframe);
printf("leadout lba: %9d %4.2d:%2.2d:%2.2d\n",
lba, pmin, psec, pframe);
}
if (disc!=NULL)
burn_disc_free(disc);
@ -428,13 +504,8 @@ int telltoc_toc(struct burn_drive *drive)
int telltoc_msinfo(struct burn_drive *drive,
int msinfo_explicit, int msinfo_alone)
{
int num_sessions, session_no, ret, num_tracks;
int nwa = -123456789, lba = -123456789, aux_lba, lout_lba;
int ret, lba, nwa = -123456789, aux_lba;
enum burn_disc_status s;
struct burn_disc *disc= NULL;
struct burn_session **sessions;
struct burn_track **tracks;
struct burn_toc_entry toc_entry;
struct burn_write_opts *o= NULL;
s = burn_disc_get_status(drive);
@ -450,34 +521,17 @@ int telltoc_msinfo(struct burn_drive *drive,
The first number is the sector number of the first sector in
the last session of the disk that should be appended to.
*/
disc = burn_drive_get_disc(drive);
if (disc==NULL) {
fprintf(stderr,"SORRY: Cannot obtain info about CD content\n");
return 2;
}
sessions = burn_disc_get_sessions(disc, &num_sessions);
for (session_no = 0; session_no<num_sessions; session_no++) {
tracks = burn_session_get_tracks(sessions[session_no],
&num_tracks);
if (tracks==NULL || num_tracks<=0)
continue;
burn_track_get_entry(tracks[0], &toc_entry);
lba= burn_msf_to_lba(toc_entry.pmin, toc_entry.psec,
toc_entry.pframe);
}
if(lba==-123456789) {
fprintf(stderr,"SORRY: Cannot find any track on media\n");
ret = burn_disc_get_msc1(drive, &lba);
if (ret <= 0) {
fprintf(stderr,
"SORRY: Cannot obtain start address of last session\n");
{ ret = 0; goto ex; }
}
/* Prepare a qualified guess as fallback for nwa inquiry */
burn_session_get_leadout_entry(sessions[num_sessions-1], &toc_entry);
lout_lba= burn_msf_to_lba(toc_entry.pmin,toc_entry.psec,
toc_entry.pframe);
/* man mkisofs , option -C :
The second number is the starting sector number of the new session.
*/
/* Set some write opts to be sent to drive. LG GSA-4082B needs it. */
/* Set some roughly suitable write opts to be sent to drive. */
o= burn_write_opts_new(drive);
if(o!=NULL) {
burn_write_opts_set_perform_opc(o, 0);
@ -489,22 +543,16 @@ int telltoc_msinfo(struct burn_drive *drive,
telltoc_regrab(drive); /* necessary to calm down my NEC drive */
if(ret<=0) {
fprintf(stderr,
"NOTE: Guessing next writeable address from leadout\n");
if(num_sessions>0)
nwa= lout_lba+6900;
else
nwa= lout_lba+11400;
"SORRY: Cannot obtain next writeable address\n");
{ ret = 0; goto ex; }
}
if (!msinfo_alone)
printf("Media msinfo : mkisofs ... -C ");
printf("%d,%d\n",lba,nwa);
ret = 1;
ex:;
if (disc!=NULL)
burn_disc_free(disc);
if (o!=NULL)
if (o != NULL)
burn_write_opts_free(o);
return ret;
}
@ -615,7 +663,7 @@ int main(int argc, char **argv)
full_default = do_media = do_msinfo = do_capacities= do_toc = 1;
}
fprintf(stderr, "Initializing libburn.pykix.org ...\n");
fprintf(stderr, "Initializing libburnia.pykix.org ...\n");
if (burn_initialize())
fprintf(stderr, "Done\n");
else {