Compare commits
155 Commits
ZeroTwoTwo
...
CdrskinZer
Author | SHA1 | Date | |
---|---|---|---|
fc7bc39a75 | |||
26260059ba | |||
f456e20d5c | |||
f37076e95a | |||
59415f667c | |||
a9004de1fe | |||
78984536f5 | |||
a9fa6315f0 | |||
218e8df61b | |||
d992163908 | |||
be66006d44 | |||
64f2e555d7 | |||
04a0b7e8fc | |||
4b98af6011 | |||
7d6e1b18e6 | |||
f95d7aa6aa | |||
0d26beb2ed | |||
f78cc40041 | |||
c51a93fd9a | |||
404067bfda | |||
efaa934a2e | |||
a4d7710063 | |||
3b57183e91 | |||
8f232d1133 | |||
e5ed5f1856 | |||
6f0643b7cf | |||
6971f3f96d | |||
b6a04cb493 | |||
4718ad99f9 | |||
af44cbccf2 | |||
8610c9bd1d | |||
84ecb57b47 | |||
fe7552e55d | |||
d9891ee17f | |||
13999f533e | |||
1477b9097f | |||
1f11d1c462 | |||
4dbae90e80 | |||
a8d9882280 | |||
82bddb6e4c | |||
8961d47fed | |||
401329f710 | |||
a6f394f626 | |||
362bcc9cc0 | |||
1e80ad2187 | |||
f8fd6a21f4 | |||
398d068820 | |||
e326e9aac9 | |||
fdfc4ebf36 | |||
cb42e2fcd9 | |||
1851f3f82a | |||
e423bda96f | |||
9d3f1292d6 | |||
6cdfb35c09 | |||
e28798d8a0 | |||
0710bbb4fb | |||
6ad8e2e251 | |||
170eb96356 | |||
1d570af0b5 | |||
5fd59b1858 | |||
86bfcea2b3 | |||
16086d5a7b | |||
ac6eed7aef | |||
6310bd0c74 | |||
be991c61d7 | |||
6c3f912561 | |||
96af620334 | |||
bd1577debd | |||
cf8aacb27d | |||
5d0b8265b2 | |||
f5603c7519 | |||
2403532242 | |||
988622c3b6 | |||
c6bd87af59 | |||
b202e3be5b | |||
d252d1fc9b | |||
a8921e4f59 | |||
ff0be0eeae | |||
91f2a231f3 | |||
16d3089ba8 | |||
b6831605b2 | |||
1fe7f68b43 | |||
3b16ef699f | |||
b3bea43074 | |||
5aa2729766 | |||
9c48ad4dff | |||
6dbcf6a8f4 | |||
22202a4301 | |||
5c45c2aa1b | |||
c70fc7215d | |||
b81aa81c61 | |||
29d630b141 | |||
886b8d1f81 | |||
927352c609 | |||
84ee76f564 | |||
70a14832b0 | |||
6127dade34 | |||
c430359a99 | |||
e66581f3b3 | |||
2d2495db29 | |||
0ee5e11a8f | |||
81f56e8bbd | |||
facd49dc4e | |||
bbcf7c269c | |||
12ad9100ff | |||
a27361b3b0 | |||
f2c87eae59 | |||
6f1a0c91d4 | |||
15b3f2627c | |||
1a69a09766 | |||
5038e2afb0 | |||
bcaf610800 | |||
6e01855f40 | |||
187fc90edf | |||
eadef2c51d | |||
81ceaf0cdd | |||
c9a3fd3140 | |||
e388a6396f | |||
8e73ee88e9 | |||
faaefaa4b8 | |||
8c0b17b382 | |||
b3c2e76975 | |||
3f7289d104 | |||
7e4f284f18 | |||
c1baf5c6d4 | |||
9d4b327adc | |||
b67c555b30 | |||
d0d0af1ba5 | |||
f580ef6637 | |||
7937cb5d9b | |||
bf5073e7c1 | |||
7ea38bbd31 | |||
1e70b67999 | |||
c5d849516c | |||
e8d71b321f | |||
db8dbbf2c3 | |||
0fe8ae2ef6 | |||
ff16978824 | |||
d47767021f | |||
7ad4f989d4 | |||
e4e671aa6e | |||
27e9e35916 | |||
ccf39cbab9 | |||
c4e6974c21 | |||
496e027f89 | |||
8ee6839513 | |||
c343d2f9b8 | |||
ba2b5aea0f | |||
600a2ebf02 | |||
4ade058cf7 | |||
8f201c0bd7 | |||
171fce7fc8 | |||
1d010c7c98 | |||
c4e484ff76 | |||
83b175c172 |
@ -1,2 +0,0 @@
|
||||
Note: this is a libburn-0.2.2 release candidate
|
||||
|
2
CONTRIBUTORS
Normal file
2
CONTRIBUTORS
Normal file
@ -0,0 +1,2 @@
|
||||
Joe Neeman
|
||||
Philippe Rouquier
|
52
Makefile.am
52
Makefile.am
@ -8,10 +8,13 @@ lib_LTLIBRARIES = libburn/libburn.la libisofs/libisofs.la
|
||||
# Build libraries
|
||||
libburn_libburn_la_LDFLAGS = \
|
||||
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
|
||||
libburn_libburn_la_LIBADD = $(LIBBURN_ARCH_LIBS) $(THREAD_LIBS)
|
||||
libburn_libburn_la_SOURCES = \
|
||||
libburn/async.c \
|
||||
libburn/async.h \
|
||||
libburn/back_hacks.h \
|
||||
libburn/cleanup.c \
|
||||
libburn/cleanup.h \
|
||||
libburn/crc.c \
|
||||
libburn/crc.h \
|
||||
libburn/debug.c \
|
||||
@ -26,8 +29,10 @@ libburn_libburn_la_SOURCES = \
|
||||
libburn/lec.c \
|
||||
libburn/lec.h \
|
||||
libburn/libburn.h \
|
||||
libburn/message.c \
|
||||
libburn/message.h \
|
||||
libburn/libdax_audioxtr.h \
|
||||
libburn/libdax_audioxtr.c \
|
||||
libburn/libdax_msgs.h \
|
||||
libburn/libdax_msgs.c \
|
||||
libburn/mmc.c \
|
||||
libburn/mmc.h \
|
||||
libburn/null.c \
|
||||
@ -57,6 +62,8 @@ libburn_libburn_la_SOURCES = \
|
||||
libburn/write.h \
|
||||
version.h
|
||||
|
||||
## libburn/sg-@ARCH@.c \
|
||||
|
||||
libisofs_libisofs_la_LDFLAGS = \
|
||||
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
|
||||
libisofs_libisofs_la_SOURCES = \
|
||||
@ -90,11 +97,10 @@ libinclude_HEADERS = \
|
||||
## Build test applications
|
||||
noinst_PROGRAMS = \
|
||||
test/libburner \
|
||||
test/burn \
|
||||
test/dewav \
|
||||
test/fake_au \
|
||||
test/iso \
|
||||
test/master \
|
||||
test/poll \
|
||||
test/rip \
|
||||
test/toc \
|
||||
test/structest
|
||||
|
||||
@ -104,21 +110,18 @@ bin_PROGRAMS = \
|
||||
test_libburner_CPPFLAGS = -Ilibburn
|
||||
test_libburner_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
|
||||
test_libburner_SOURCES = test/libburner.c
|
||||
test_dewav_CPPFLAGS = -Ilibburn
|
||||
test_dewav_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
|
||||
test_dewav_SOURCES = test/dewav.c
|
||||
test_fake_au_CPPFLAGS =
|
||||
test_fake_au_LDADD =
|
||||
test_fake_au_SOURCES = test/fake_au.c
|
||||
test_poll_CPPFLAGS = -Ilibburn
|
||||
test_poll_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
|
||||
test_poll_SOURCES = test/poll.c
|
||||
test_toc_CPPFLAGS = -Ilibburn
|
||||
test_toc_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
|
||||
test_toc_SOURCES = test/toc.c
|
||||
test_rip_CPPFLAGS = -Ilibburn
|
||||
test_rip_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
|
||||
test_rip_SOURCES = test/rip.c
|
||||
test_burn_CPPFLAGS = -Ilibburn
|
||||
test_burn_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
|
||||
test_burn_SOURCES = test/burn.c
|
||||
test_master_CPPFLAGS = -Ilibburn
|
||||
test_master_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
|
||||
test_master_SOURCES = test/master.c
|
||||
test_structest_CPPFLAGS = -Ilibburn
|
||||
test_structest_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
|
||||
test_structest_SOURCES = test/structest.c
|
||||
@ -128,9 +131,10 @@ test_iso_SOURCES = test/iso.c
|
||||
|
||||
## cdrskin construction site - ts A60816
|
||||
cdrskin_cdrskin_CPPFLAGS = -Ilibburn
|
||||
cdrskin_cdrskin_CFLAGS = -DCdrskin_libburn_0_2_2
|
||||
cdrskin_cdrskin_CFLAGS = -DCdrskin_libburn_0_2_3
|
||||
cdrskin_cdrskin_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
|
||||
cdrskin_cdrskin_SOURCES = cdrskin/cdrskin.c cdrskin/cdrfifo.c cdrskin/cdrfifo.h cdrskin/cleanup.c cdrskin/cleanup.h cdrskin/cdrskin_timestamp.h
|
||||
cdrskin_cdrskin_SOURCES = cdrskin/cdrskin.c cdrskin/cdrfifo.c cdrskin/cdrfifo.h cdrskin/cdrskin_timestamp.h
|
||||
## cdrskin_cdrskin_SOURCES = cdrskin/cdrskin.c cdrskin/cdrfifo.c cdrskin/cdrfifo.h cdrskin/cleanup.c cdrskin/cleanup.h cdrskin/cdrskin_timestamp.h
|
||||
##
|
||||
## Open questions: how to compute $timestamp and express -DX="$timestamp"
|
||||
##
|
||||
@ -173,15 +177,11 @@ indent_files = \
|
||||
$(libisofs_libisofs_la_SOURCES) \
|
||||
$(libburn_libburn_la_SOURCES) \
|
||||
$(test_libburner_SOURCES) \
|
||||
$(test_devices_SOURCES) \
|
||||
$(test_poll_SOURCES) \
|
||||
$(test_toc_SOURCES) \
|
||||
$(test_rip_SOURCES) \
|
||||
$(test_burn_SOURCES) \
|
||||
$(test_burniso_SOURCES) \
|
||||
$(test_master_SOURCES) \
|
||||
$(test_structest_SOURCES) \
|
||||
$(test_blank_SOURCES)
|
||||
$(test_iso_SOURCES)
|
||||
|
||||
|
||||
indent: $(indent_files)
|
||||
indent -bad -bap -nbbb -nbbo -nbc -bli0 -br -bls \
|
||||
@ -203,13 +203,21 @@ EXTRA_DIST = \
|
||||
libburn-1.pc.in \
|
||||
libisofs-1.pc.in \
|
||||
version.h.in \
|
||||
doc/comments \
|
||||
doc/doxygen.conf.in \
|
||||
README \
|
||||
AUTHORS \
|
||||
CONTRIBUTORS \
|
||||
COPYRIGHT \
|
||||
cdrskin/README \
|
||||
cdrskin/cdrecord_spy.sh \
|
||||
cdrskin/compile_cdrskin.sh \
|
||||
cdrskin/changelog.txt \
|
||||
cdrskin/cdrskin_eng.html \
|
||||
cdrskin/wiki_plain.txt \
|
||||
cdrskin/cleanup.h \
|
||||
cdrskin/cleanup.c \
|
||||
libburn/sg-freebsd.c \
|
||||
libburn/sg-linux.c \
|
||||
COPYING
|
||||
|
||||
|
21
README
21
README
@ -24,12 +24,18 @@ This libburn.pykix.org toplevel README (C) 2006 Thomas Schmitt
|
||||
|
||||
Build and Installation
|
||||
|
||||
Our build system is based on autotools.
|
||||
User experience tells us that you will need at least autotools version 1.7.
|
||||
Our build system is based on autotools. For preparing the build of a SVN
|
||||
snapshot you will need autotools of at least version 1.7.
|
||||
Check out from SVN by
|
||||
svn co http://libburn-svn.pykix.org/trunk libburn_pykix
|
||||
and apply autotools by
|
||||
./bootstrap
|
||||
|
||||
Alternatively you may unpack a release tarball for which you do not need
|
||||
autotools installed.
|
||||
|
||||
To build libburn.pykix.org and its subprojects it should be sufficient to go
|
||||
into its toplevel directory and execute
|
||||
./bootstrap (needed if you downloaded from SVN and not a release tarball)
|
||||
into its toplevel directory (here: "libburn_pykix") and execute
|
||||
./configure
|
||||
make
|
||||
|
||||
@ -146,6 +152,13 @@ Project history as far as known to me:
|
||||
|
||||
- 16th September 2006 feature freeze for release of libburn-0.2.2 .
|
||||
|
||||
- 20th September 2006 release of libburn-0.2.2 .
|
||||
|
||||
- 26th October 2006 feature freeze for cdrskin-0.2.4 based on libburn-0.2.3 .
|
||||
This version of cdrskin is much more cdrecord compatible in repect
|
||||
to drive addressing and audio features.
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
25
acinclude.m4
25
acinclude.m4
@ -1,18 +1,3 @@
|
||||
dnl Function to link an architecture specific file
|
||||
dnl LINK_ARCH_SRC(source_dir, arch, source_file)
|
||||
AC_DEFUN([COPY_ARCH_SRC],
|
||||
[
|
||||
echo "copying $1/$2/$3 -> $1/$3"
|
||||
old="$srcdir/$1/$2/$3"
|
||||
new="$srcdir/$1/$3"
|
||||
cat >$new <<__EOF__
|
||||
/* WARNING: This file was automatically generated!
|
||||
* Original: $old
|
||||
*/
|
||||
__EOF__
|
||||
cat >>$new <$old
|
||||
])
|
||||
|
||||
AC_DEFUN([TARGET_SHIZZLE],
|
||||
[
|
||||
ARCH=""
|
||||
@ -22,6 +7,11 @@ AC_DEFUN([TARGET_SHIZZLE],
|
||||
case $target in
|
||||
*-*-linux*)
|
||||
ARCH=linux
|
||||
LIBBURN_ARCH_LIBS=
|
||||
;;
|
||||
*-*-freebsd*)
|
||||
ARCH=freebsd
|
||||
LIBBURN_ARCH_LIBS=-lcam
|
||||
;;
|
||||
*)
|
||||
AC_ERROR([You are attempting to compile for an unsupported platform])
|
||||
@ -29,9 +19,4 @@ AC_DEFUN([TARGET_SHIZZLE],
|
||||
esac
|
||||
|
||||
AC_MSG_RESULT([$ARCH])
|
||||
|
||||
# this doesn't actually do anything yet.. but it will someday when we port
|
||||
# libburn
|
||||
|
||||
#COPY_ARCH_SRC(libburn, $ARCH, transport.c)
|
||||
])
|
||||
|
@ -3,4 +3,5 @@
|
||||
aclocal
|
||||
libtoolize --copy --force
|
||||
autoconf
|
||||
autoheader
|
||||
automake --foreign --add-missing --copy --include-deps
|
||||
|
165
cdrskin/README
165
cdrskin/README
@ -26,12 +26,12 @@ following possible.
|
||||
cdrskin. By Thomas Schmitt <scdbackup@gmx.net>
|
||||
Integrated sub project of libburn.pykix.org but also published via:
|
||||
http://scdbackup.sourceforge.net/cdrskin_eng.html
|
||||
http://scdbackup.sourceforge.net/cdrskin-0.2.2.tar.gz
|
||||
http://scdbackup.sourceforge.net/cdrskin-0.2.4.tar.gz
|
||||
Copyright (C) 2006 Thomas Schmitt
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
On top of libburn there is implemented cdrskin 0.2.2, a limited cdrecord
|
||||
On top of libburn there is implemented cdrskin 0.2.4, 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
|
||||
@ -46,9 +46,10 @@ protection against possible damages. You use this on your own risk.
|
||||
Don't blame me or other authors of libburn if anything goes wrong.
|
||||
|
||||
I used it on my own risk with :
|
||||
SuSE 7.2, kernel 2.4.4, ide-scsi emulation, LITE-ON LTR48125S CD burner
|
||||
SuSE 9.0, kernel 2.4.21, ide-scsi emulation, LG GSA-4082B CD/DVD burner
|
||||
RIP-14.4, kernel 2.6.14, no ide-scsi, with both above burners
|
||||
SuSE 7.2, kernel 2.4.4, ide-scsi emulation, LITE-ON LTR48125S CD burner, 2002
|
||||
SuSE 9.0, kernel 2.4.21, ide-scsi emulation, LG GSA-4082B CD/DVD burner, 2004
|
||||
NEC ND-4570A CD/DVD burner, 2006
|
||||
RIP-14.4, kernel 2.6.14, no ide-scsi, with all above burners
|
||||
|
||||
It fails to compile or run on SuSE 6.4 (kernel 2.2.14).
|
||||
It does not find the IDE CD burner on SuSE 7.2 without ide-scsi.
|
||||
@ -58,16 +59,16 @@ systems, including 64 bit systems. (Further reports are welcome.)
|
||||
|
||||
Compilation, First Glimpse, Installation
|
||||
|
||||
Obtain cdrskin-0.2.2.tar.gz , take it to a directory of your choice and do:
|
||||
Obtain cdrskin-0.2.4.tar.gz , take it to a directory of your choice and do:
|
||||
|
||||
tar xzf cdrskin-0.2.2.tar.gz
|
||||
cd cdrskin-0.2.2
|
||||
tar xzf cdrskin-0.2.4.tar.gz
|
||||
cd cdrskin-0.2.4
|
||||
|
||||
Or obtain a libburn.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.2 or libburn then execute:
|
||||
Within that toplevel directory of either cdrskin-0.2.4 or libburn then execute:
|
||||
|
||||
./configure
|
||||
make
|
||||
@ -124,17 +125,13 @@ On Linux 2.4 this would be some /dev/sgN and on 2.6. some /dev/hdX.
|
||||
|
||||
The output of cdrskin --devices might look like
|
||||
|
||||
0 dev='/dev/sg0' rwrwr- : 'TEAC' 'CD-ROM CD-532S'
|
||||
1 dev='/dev/sg1' rwrw-- : 'LITE-ON' 'LTR-48125S'
|
||||
0 dev='/dev/sg0' rwrwr- : '_NEC' 'DVD_RW ND-4570A'
|
||||
1 dev='/dev/sg1' 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
|
||||
|
||||
(The CD-ROM is in these examples only for demonstrating the presence of another
|
||||
SCSI device. This /dev/sg0 may be left as it is and stay invisible for normal
|
||||
users.)
|
||||
|
||||
I strongly discourage to run cdrskin with setuid root or via sudo !
|
||||
It is not checked for the necessary degree of hacker safety.
|
||||
|
||||
@ -143,43 +140,57 @@ It is not checked for the necessary degree of hacker safety.
|
||||
|
||||
Get an overview of cdrecord style addresses of available devices
|
||||
cdrskin -scanbus
|
||||
cdrskin dev=ATA -scanbus
|
||||
|
||||
Note: Adresses reported with dev=ATA are to be used with prefix "ATA:". You may
|
||||
well use device file addresses as reported with --devices. Examples:
|
||||
dev=0,1,0 dev=/dev/sg1 dev=ATA:1,0,0 dev=/dev/hdc
|
||||
See also "Drive Addressing".
|
||||
Note: Address numbers have changed since cdrskin-0.2.2 in order to become
|
||||
compatible with cdrecord numbers. To get the old number scheme, use
|
||||
option --old_pseudo_scsi_adr . See also "Pseudo-SCSI Adresses".
|
||||
Sorry for any inconvenience.
|
||||
|
||||
|
||||
Obtain some info about the drive
|
||||
cdrskin dev=1,1,0 -checkdrive
|
||||
cdrskin dev=0,1,0 -checkdrive
|
||||
|
||||
Obtain some info about the drive and the inserted media
|
||||
cdrskin dev=1,1,0 -atip
|
||||
cdrskin dev=0,1,0 -atip
|
||||
|
||||
Thoroughly blank a CD-RW
|
||||
cdrskin -v dev=1,1,0 blank=all -eject
|
||||
cdrskin -v dev=0,1,0 blank=all -eject
|
||||
|
||||
Blank CD-RW sufficiently for making it ready for overwrite
|
||||
cdrskin -v dev=1,1,0 blank=fast -eject
|
||||
cdrskin -v dev=0,1,0 blank=fast -eject
|
||||
|
||||
Burn image file my_image.iso to CD
|
||||
cdrskin -v dev=1,1,0 speed=12 fs=8m -sao driveropts=burnfree padsize=300k \
|
||||
cdrskin -v dev=0,1,0 speed=12 fs=8m -sao driveropts=burnfree padsize=300k \
|
||||
-eject my_image.iso
|
||||
|
||||
Burn a compressed afio archive to CD on-the-fly
|
||||
find . | afio -oZ - | cdrskin -v dev=1,1,0 fs=32m speed=8 -sao \
|
||||
find . | afio -oZ - | cdrskin -v dev=0,1,0 fs=32m speed=8 -sao \
|
||||
driveropts=burnfree padsize=300k tsize=650m -
|
||||
|
||||
Burn 5 audio tracks to CD
|
||||
Burn 6 audio tracks from files with different formats to CD.
|
||||
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
|
||||
oggdec -R -o track02.cd /path/to/track2.ogg
|
||||
lame --decode -t /path/to/track3.mp3 track03.cd
|
||||
madplay -o raw:track04.cd /path/to/track4.mp3
|
||||
mppdec --raw-le /path/to/track5.mpc track05.cd
|
||||
cdrskin dev=/dev/hdc blank=fast fs=0 -eject -audio track0[1-5].cd
|
||||
|
||||
cdrskin dev=0,1,0 blank=fast -eject speed=48 -sao \
|
||||
-audio -swab track0[1-5].cd /path/to/track6.wav
|
||||
|
||||
|
||||
Usage example with http://scdbackup.sourceforge.net
|
||||
|
||||
Address may be a cdrecord-style "scsibus,target,lun" as listed with
|
||||
cdrskin -scanbus (but not as listed with cdrecord -scanbus) :
|
||||
cdrskin -scanbus (and hopefully as listed with cdrecord -scanbus) :
|
||||
|
||||
export SCDBACKUP_SCSI_ADR="1,1,0"
|
||||
export SCDBACKUP_SCSI_ADR="0,1,0"
|
||||
|
||||
or a device file address as listed by --devices with an accessible drive :
|
||||
|
||||
@ -201,11 +212,6 @@ Therefore it has to be defaulted to mode SAO which needs to know the track
|
||||
size in advance. non-cdrecord option tao_to_sao_tsize=650m causes each CD
|
||||
to get burned up to 650 MB regardless of the payload size.
|
||||
|
||||
Audio features are incomplete in respect to cdrecord. Well prepaired track
|
||||
files should get burned flawlessly, thanks to Lorenzo Taylor.
|
||||
Builtin extraction of raw audio data from filetypes .au and .wav is not
|
||||
implemented yet. See chapter "Audio CD" for details.
|
||||
|
||||
No multi session yet ... Please report your wishes.
|
||||
|
||||
|
||||
@ -226,12 +232,45 @@ 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.
|
||||
|
||||
|
||||
Drive Addressing
|
||||
|
||||
Drives get addressed either via their cdrecord-style addresses as listed
|
||||
with option -scanbus (see below "Pseudo-SCSI Adresses") or via the paths
|
||||
of device files.
|
||||
Not only device files listed by --devices may be used but also device files
|
||||
which via their major,minor numbers point to the same device driver as
|
||||
a listed device file.
|
||||
|
||||
Helpful with Linux kernel 2.4 is a special SCSI feature:
|
||||
It is possible to address a scsi(-emulated) drive via associated device files
|
||||
which are not listed by option --devices but point to the same SCSI addresses
|
||||
as listed device files. This addressing via e.g. /dev/sr0 or /dev/scd1 is
|
||||
compatible with generic read programs like dd and with write program growisofs.
|
||||
|
||||
Pseudo-SCSI Adresses
|
||||
|
||||
cdrecord and cdrskin share only some syntax of addresses but not the meaning
|
||||
of the components. A cdrecord-style address for cdrskin
|
||||
[[prefix:]scsibus,]target,lun
|
||||
corresponds either to a device file address or to a libburn drive number.
|
||||
cdrecord and cdrskin share the syntax of SCSI addresses but not necessarily
|
||||
the meaning of the components. A cdrecord-style address for cdrskin
|
||||
[prefix:]scsibus,target,lun
|
||||
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 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
|
||||
where target only may have the values 0 or 1.
|
||||
|
||||
In this mode, option -scanbus will list only SCSI devices unless option
|
||||
dev=ATA or dev=ATAPI are given, which will suppress SCSI devices and only
|
||||
show IDE drives (i.e. /dev/hdX without ide-scsi emulation).
|
||||
|
||||
|
||||
In mode --old_pseudo_scsi_adr there is a scsibus,target,lun representation
|
||||
which has nothing to do with SCSI and thus is not compatible to cdrecord.
|
||||
Each number triple corresponds either to a device file address or to a
|
||||
libburn drive number.
|
||||
Component "scsibus" indicates the translation method. Defined busses are:
|
||||
0 target is the libburn drivenumber as listed with --devices
|
||||
1 associated to device file /dev/sgN , target chooses N
|
||||
@ -246,17 +285,24 @@ drive accessability.
|
||||
Further busses may emerge as libburn evolves. "prefix" and "lun" may get
|
||||
a meaning. To stay upward compatible, use addresses as printed by -scanbus.
|
||||
|
||||
User Defined Device Address Translation
|
||||
|
||||
Some programs or users have their own ideas about the address of their burner.
|
||||
K3b 0.10 for example derives cdrecord addresses by own examination of the
|
||||
devices and not by calling cdrecord -scanbus.
|
||||
To direct such callers to the appropriate drives, cdrskin allows to define
|
||||
device address aliases. Like
|
||||
Standard mode will hopefully be fully compatible with their ideas.
|
||||
|
||||
Old frontends which do not know dev=ATA or dev=ATAPI and which do ask their
|
||||
"cdrecord" via -scanbus may be well served with option --old_pseudo_scsi_adr .
|
||||
|
||||
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 \
|
||||
dev_translation=-"cd+dvd"-1,1,0 \
|
||||
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 its standard alias 1,1,0.
|
||||
/dev/sg1 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 "-".)
|
||||
|
||||
@ -282,31 +328,42 @@ arguments from the following three files:
|
||||
/etc/opt/cdrskin/rc
|
||||
$HOME/.cdrskinrc
|
||||
The files are read in the sequence given above.
|
||||
Each readable line is treated as one single argument. No extra blanks,
|
||||
no comments, no empty lines are permitted.
|
||||
Each readable line is treated as one single argument. No extra blanks.
|
||||
A first character '#' marks a comment, empty lines are ignored.
|
||||
|
||||
Example content of a startup file:
|
||||
dev=1,1,0
|
||||
dev_translation=+1,0,0+1,1,0
|
||||
# This is the default device
|
||||
dev=0,1,0
|
||||
# To accomodate to eventual remnant cdrskin-0.2.2 addresses
|
||||
dev_translation=+1,0,0+0,1,0
|
||||
|
||||
# Some more options
|
||||
--fifo_start_empty
|
||||
fs=16m
|
||||
|
||||
|
||||
Audio CD
|
||||
|
||||
Builtin extraction of raw audio data from filetypes .au and .wav is not
|
||||
implemented yet. Lorenzo Taylor enabled option -audio in cdrskin (thanks !)
|
||||
and reports neat results with audio data files which are :
|
||||
headerless
|
||||
44100Hz
|
||||
16bit, stereo (or 4-channel if the 4-channel bit is set),
|
||||
little-endian byte order
|
||||
He proposes to extract them from usual audio formats by commands like
|
||||
given above under "Usage examples".
|
||||
Lorenzo Taylor enabled option -audio in cdrskin (thanks !) and reports neat
|
||||
results with audio data files which are :
|
||||
headerless PCM (i.e. uncompressed)
|
||||
44100 Hz sampling rate
|
||||
16 bits per sample
|
||||
stereo (2 channels)
|
||||
little-endian byte order with option -swab, or big-endian without -swab
|
||||
|
||||
Files with name extension .wav get examined wether they are in Microsoft WAVE
|
||||
format with above parameters and eventually get extracted by cdrskin itself.
|
||||
In the same way files with name extension .au get examined wether they are
|
||||
in SUN's audio format. For both formats, track format -audio and eventual
|
||||
endianness option -swab are enabled automatically.
|
||||
|
||||
Any other formats are to be converted to format .wav with above parameters
|
||||
or to be extracted as raw CD track data by commands like those given above
|
||||
under "Usage examples". Those raw files need option -audio and in most cases
|
||||
option -swab to mark them as little-endian/Intel/LSB-first 16-bit data.
|
||||
Incorrect endianness setting results in random noise on CD.
|
||||
|
||||
The existence of cdrecord-builtin .wav extraction seems to have
|
||||
hampered the development of a standalone stripping tool. If you know
|
||||
a command line that would do the trick, contact me or libburn.pykix.org .
|
||||
I myself am not into audio. So libburn-hackers@pykix.org might be the
|
||||
best address for suggestions, requests and bug reports.
|
||||
|
||||
|
@ -20,18 +20,23 @@ 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 SVN of Aug 15 2006
|
||||
# packed up in a tarball just to save it from inadverted changes.
|
||||
# libburn version used: http://libburn.pykix.org
|
||||
# Downloaded by:
|
||||
# $ svn co http://libburn-svn.pykix.org/trunk libburn_pykix
|
||||
# packed up in a tarball just to save it from inadverted changes by
|
||||
# $ tar czf libburn_svn.tgz libburn_pykix
|
||||
original="./libburn_svn.tgz"
|
||||
# Historic moments:
|
||||
# original="./libburn_svn_A60815.tgz"
|
||||
original="./libburn_cdrskin_A60819.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.1.ts.develop , mainly in ./cdrskin
|
||||
# My changes are in libburn-0.2.3.ts.develop , mainly in ./cdrskin
|
||||
|
||||
changes="./libburn-0.2.1.ts.develop"
|
||||
skin_rev="0.1.5"
|
||||
changes="./libburn-0.2.3.ts.develop"
|
||||
skin_rev="0.2.4"
|
||||
|
||||
# The result directory and the name of the result tarballs
|
||||
target="./cdrskin-${skin_rev}"
|
||||
@ -46,9 +51,7 @@ compile_cmd="./cdrskin/compile_cdrskin.sh"
|
||||
compile_static_opts="-static"
|
||||
compile_result="cdrskin/cdrskin"
|
||||
|
||||
|
||||
# addresses relative to compile_dir :
|
||||
bintarget_dynamic="../cdrskin_${skin_rev}-x86-suse9_0"
|
||||
bintarget_dynamic="cdrskin_${skin_rev}-x86-suse9_0"
|
||||
bintarget_static="$bintarget_dynamic"-static
|
||||
|
||||
if test -d "$changes"
|
||||
@ -105,9 +108,24 @@ fi
|
||||
cp -a "$cdrskin_dir" "$cdrskin_target"
|
||||
|
||||
# Remove copied binaries
|
||||
rm "$cdrskin_target"/*.o
|
||||
rm "$cdrskin_target"/cdrfifo
|
||||
rm "$cdrskin_target"/cdrskin
|
||||
rm "$cdrskin_target"/cleanup
|
||||
for i in std new make old
|
||||
do
|
||||
if test -e "$cdrskin_target"/cdrskin_"$i"
|
||||
then
|
||||
rm "$cdrskin_target"/cdrskin_"$i"
|
||||
fi
|
||||
done
|
||||
for i in .deps .dirstamp .libs
|
||||
do
|
||||
if test -e "$cdrskin_target"/"$i"
|
||||
then
|
||||
rm -rf "$cdrskin_target"/"$i"
|
||||
fi
|
||||
done
|
||||
|
||||
# Remove unwanted SVN stuff (TODO: avoid downloading it)
|
||||
for i in "$target"/.svn "$target"/*/.svn
|
||||
@ -123,15 +141,14 @@ do
|
||||
fi
|
||||
done
|
||||
|
||||
# For now: Add own libburn-README in toplevel
|
||||
cp -a "$changes"/README "$target"
|
||||
## No more : Add own libburn-README in toplevel
|
||||
# cp -a "$changes"/README "$target"
|
||||
|
||||
# Add modified Makefile.am
|
||||
cp -a "$changes"/Makefile.am "$target"
|
||||
## No more : Add modified Makefile.am
|
||||
# cp -a "$changes"/Makefile.am "$target"
|
||||
|
||||
|
||||
# Make SVN state tarball for the libburn team
|
||||
# TODO: will probably be obsoleted after sucessful merge
|
||||
tar czf "$cdrskin_tarball_svn" "$target"
|
||||
|
||||
|
||||
@ -141,6 +158,20 @@ tar czf "$cdrskin_tarball_svn" "$target"
|
||||
#
|
||||
( cd "$target" ; ./bootstrap )
|
||||
|
||||
# Remove unwanted stuff after bootstrap
|
||||
for i in "$target"/autom4te.cache
|
||||
do
|
||||
if echo "$i" | grep '\*' >/dev/null
|
||||
then
|
||||
dummy=dummy
|
||||
else
|
||||
if test -e "$i"
|
||||
then
|
||||
rm -rf "$i"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
# Pack it up to the new libburn+cdrskin-tarball
|
||||
tar czf "$cdrskin_tarball" "$target"
|
||||
@ -151,15 +182,22 @@ tar czf "$cdrskin_tarball" "$target"
|
||||
./configure
|
||||
make
|
||||
$compile_cmd -do_strip
|
||||
cp "$compile_result" "$bintarget_dynamic"
|
||||
cp "$compile_result" "../$bintarget_dynamic"
|
||||
if test -n "$compile_static_opts"
|
||||
then
|
||||
$compile_cmd $compile_static_opts -do_strip
|
||||
cp "$compile_result" "$bintarget_static"
|
||||
cp "$compile_result" "../$bintarget_static"
|
||||
fi
|
||||
)
|
||||
|
||||
# Remove the build area
|
||||
# Disable this for debugging the merge process
|
||||
rm -rf "$target"
|
||||
|
||||
# Show the result
|
||||
./"$bintarget_dynamic" -version
|
||||
./"$bintarget_static" -version
|
||||
ls -l "$cdrskin_tarball"
|
||||
ls -l "$bintarget_dynamic"
|
||||
ls -l "$bintarget_static"
|
||||
|
1264
cdrskin/cdrskin.c
1264
cdrskin/cdrskin.c
File diff suppressed because it is too large
Load Diff
@ -51,7 +51,7 @@ A CD recorder suitable for
|
||||
GPL software included:<BR>
|
||||
</H2>
|
||||
<DL>
|
||||
<DT>libburn-0.2.1 (inofficially stable SVN snapshot)</DT>
|
||||
<DT>libburn-0.2.3 stabilized SVN snapshot</DT>
|
||||
<DD>(by Derek Foreman, Ben Jansens, and team of libburn.pykix.org)</DD>
|
||||
<DD>transfers data to CD</DD>
|
||||
</DL>
|
||||
@ -80,10 +80,31 @@ Ports to other usable systems are appreciated. Reports are welcome.
|
||||
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>).<BR>
|
||||
(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>
|
||||
<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 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 -sao tsize=650m -</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>
|
||||
<DT><A HREF="cdrskin_help">cdrskin -help</A></DT>
|
||||
<DD>reports the cdrecord compatible options</DD>
|
||||
<DT><A HREF="cdrskin__help">cdrskin --help</A></DT>
|
||||
@ -94,15 +115,6 @@ wishes as well as on the development of libburn.</DT>
|
||||
(Be cursed if you install cdrskin as "cdrecord" without clearly forwarding
|
||||
this "don't bother Joerg" demand.)
|
||||
</DD>
|
||||
<DT>Currently (and sparsely) supported gestures :</DT>
|
||||
<DD>$ cdrskin -scanbus</DD>
|
||||
<DD>$ cdrskin dev=1,1,0 -checkdrive</DD>
|
||||
<DD>$ cdrskin dev=1,1,0 -atip</DD>
|
||||
<DD>$ cdrskin -v dev=1,1,0 blank=all eject_device=/dev/cdrom -eject</DD>
|
||||
<DD>$ cdrskin -v dev=1,1,0 blank=fast eject_device=/dev/cdrom -eject</DD>
|
||||
<DD>$ cdrskin -v dev=1,1,0 speed=12 fs=8m -sao driveropts=burnfree eject_device=/dev/cdrom -eject padsize=300k my_image.iso</DD>
|
||||
<DD>$ cdrskin -v dev=1,1,0 ... ... track_1.iso padsize=300k track_2.afio</DD>
|
||||
<DD>$ find . | afio -oZ - | cdrskin -v dev=1,1,0 fs=32m speed=8 -sao driveropts=burnfree padsize=300k tsize=650m -</DD>
|
||||
</DL>
|
||||
</P>
|
||||
|
||||
@ -111,10 +123,6 @@ wishes as well as on the development of libburn.</DT>
|
||||
<UL>
|
||||
<DT></DT>
|
||||
<LI>
|
||||
No audio features yet. (Note: Option -audio is enabled in cdrskin-0.1.5 as
|
||||
offered below, but no beheading of .au or .wav files takes place yet.)
|
||||
</LI>
|
||||
<LI>
|
||||
Burns only a single closed session. No -multi option yet.
|
||||
</LI>
|
||||
<LI>
|
||||
@ -133,12 +141,6 @@ 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.
|
||||
<LI>
|
||||
Burners other than /dev/sg0 and /dev/hdX (i.e. without ide-scsi) need a user
|
||||
supplied device address for program eject.
|
||||
(Note: -eject is now working in libburn-0.2.1 SVN and the workaround described
|
||||
here is obsolete with cdrskin-0.1.5 as offered below.)
|
||||
</LI>
|
||||
</UL>
|
||||
</P>
|
||||
|
||||
@ -147,30 +149,29 @@ here is obsolete with cdrskin-0.1.5 as offered below.)
|
||||
<P>
|
||||
<DL>
|
||||
<DT>Download as source code (see README):</DT>
|
||||
<DD><A HREF="cdrskin-0.1.4.tar.gz">cdrskin-0.1.4.tar.gz</A>
|
||||
(580 KB).
|
||||
<DD><A HREF="cdrskin-0.2.4.tar.gz">cdrskin-0.2.4.tar.gz</A>
|
||||
(510 KB).
|
||||
</DD>
|
||||
<DD>
|
||||
The "stable" cdrskin tarballs are tested and eventually slightly modified
|
||||
SVN snapshots from libburn.pykix.org . All modifications are to be re-merged
|
||||
into that SVN repository.<BR>
|
||||
The "stable" cdrskin tarballs are source code identical with "stable"
|
||||
libburn releases or with "stabilized" libburn SVN snapshots. They get
|
||||
produced via a different procedure, though.<BR>
|
||||
cdrskin is part of libburn - full libburn is provided with cdrskin releases.
|
||||
</DD>
|
||||
<DD> </DD>
|
||||
<DT>Download as single x86 binaries (untar and move to /usr/bin/cdrskin):</DT>
|
||||
<DD><A HREF="cdrskin_0.1.4-x86-suse9_0.tar.gz">
|
||||
cdrskin_0.1.4-x86-suse9_0.tar.gz</A>, (50 KB),
|
||||
<DD><A HREF="cdrskin_0.2.4-x86-suse9_0.tar.gz">
|
||||
cdrskin_0.2.4-x86-suse9_0.tar.gz</A>, (60 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.1.4-x86-suse9_0-static.tar.gz">
|
||||
cdrskin_0.1.4-x86-suse9_0-static.tar.gz</A>, (250 KB), -static compiled,
|
||||
<DD><A HREF="cdrskin_0.2.4-x86-suse9_0-static.tar.gz">
|
||||
cdrskin_0.2.4-x86-suse9_0-static.tar.gz</A>, (260 KB), -static compiled,
|
||||
<DL>
|
||||
<DD>runs on SuSE 7.2 (2.4.4), and on the systems above.</DD>
|
||||
</DL>
|
||||
</DD>
|
||||
<DD> </DD>
|
||||
</DL>
|
||||
<DL><DT>Documentation:</DT>
|
||||
<DD><A HREF="README_cdrskin">README</A> a short introduction</DD>
|
||||
@ -189,16 +190,44 @@ cdrskin_0.1.4-x86-suse9_0-static.tar.gz</A>, (250 KB), -static compiled,
|
||||
|
||||
<HR>
|
||||
|
||||
<P>
|
||||
Enhancements towards previous stable version cdrskin-0.2.2:
|
||||
<UL>
|
||||
<LI>cdrecord compatibility with drive addresses of form [ATA:]Bus,Target,Lun.
|
||||
<BR>(use option --old_pseudo_scsi_adr to get back the incompatible
|
||||
Bus,Traget,Lun addressing of version 0.2.2)
|
||||
</LI>
|
||||
<LI>Drives adressable via links and device siblings (/dev/cdrom , /dev/scd0).
|
||||
</LI>
|
||||
<LI>Automatic -audio extraction with .wav files and .au files.
|
||||
</LI>
|
||||
<LI>Bug fix about failure to eject.</LI>
|
||||
<LI>Comments and empty lines allowed in startup files.</LI>
|
||||
<LI>Options -scanbus and --devices print SORRY messages about busy drives.
|
||||
</LI>
|
||||
<LI>Drive buffer fill indicator reports realistic percentage numbers.</LI>
|
||||
<LI>Option -toc is supported, drive firmware revision gets displayed.</LI>
|
||||
</UL>
|
||||
</P>
|
||||
|
||||
<HR>
|
||||
|
||||
<P>
|
||||
<DL>
|
||||
<DT>Development snapshot:</DT>
|
||||
<DT>Development snapshot, version 0.2.5 :</DT>
|
||||
<DD> </DD>
|
||||
<DD><A HREF="README_cdrskin_devel">README 0.1.5</A>
|
||||
<DD><A HREF="cdrskin__help_devel">cdrskin_0.1.5 --help</A></DD>
|
||||
<DD><A HREF="cdrskin_help_devel">cdrskin_0.1.5 -help</A></DD>
|
||||
<DD>Enhancements towards stable version 0.2.4:
|
||||
<UL>
|
||||
<LI>-none for now-</LI>
|
||||
</UL>
|
||||
</DD>
|
||||
<DD> </DD>
|
||||
<DD>Maintainers of cdrskin unstable packages please use SVN of
|
||||
<A HREF="http://libburn.pykix.org"> libburn.pykix.org</A></DD>
|
||||
<DD><A HREF="README_cdrskin_devel">README 0.2.5</A>
|
||||
<DD><A HREF="cdrskin__help_devel">cdrskin_0.2.5 --help</A></DD>
|
||||
<DD><A HREF="cdrskin_help_devel">cdrskin_0.2.5 -help</A></DD>
|
||||
<DD> </DD>
|
||||
<DT>Maintainers of cdrskin unstable packages please use SVN of
|
||||
<A HREF="http://libburn.pykix.org"> libburn.pykix.org</A></DT>
|
||||
<DD>Download: <KBD><B>svn co http://libburn-svn.pykix.org/trunk libburn_pykix</B>
|
||||
</KBD></DD>
|
||||
<DD>Build: <KBD><B>cd libburn_pykix ; ./bootstrap ; ./configure ; make</B>
|
||||
@ -211,19 +240,19 @@ vanilla tools like make and gcc are needed.</DD>
|
||||
<DD> </DD>
|
||||
<DT>The following downloads are intended for adventurous end users or
|
||||
admins with full system souvereignty.</DT>
|
||||
<DT>Source (./bootstrap is already applied, build tested, for more see above
|
||||
<DD>Source (./bootstrap is already applied, build tested, for more see above
|
||||
<A HREF="README_cdrskin_devel">upcoming README</A> ):
|
||||
</DT>
|
||||
</DD>
|
||||
<DD>
|
||||
<A HREF="cdrskin-0.1.5.tar.gz">cdrskin-0.1.5.tar.gz</A>
|
||||
(580 KB).
|
||||
<A HREF="cdrskin-0.2.5.tar.gz">cdrskin-0.2.5.tar.gz</A>
|
||||
(500 KB).
|
||||
</DD>
|
||||
<DT>Binary (untar and move to /usr/bin/cdrskin):</DT>
|
||||
<DD><A HREF="cdrskin_0.1.5-x86-suse9_0.tar.gz">
|
||||
cdrskin_0.1.5-x86-suse9_0.tar.gz</A>, (50 KB).
|
||||
<DD>Binary (untar and move to /usr/bin/cdrskin):</DD>
|
||||
<DD><A HREF="cdrskin_0.2.5-x86-suse9_0.tar.gz">
|
||||
cdrskin_0.2.5-x86-suse9_0.tar.gz</A>, (60 KB).
|
||||
</DD>
|
||||
<DD><A HREF="cdrskin_0.1.5-x86-suse9_0-static.tar.gz">
|
||||
cdrskin_0.1.5-x86-suse9_0-static.tar.gz</A>, (250 KB)
|
||||
<DD><A HREF="cdrskin_0.2.5-x86-suse9_0-static.tar.gz">
|
||||
cdrskin_0.2.5-x86-suse9_0-static.tar.gz</A>, (260 KB)
|
||||
</DD>
|
||||
</DL>
|
||||
</P>
|
||||
@ -276,25 +305,6 @@ is a GUI frontend which uses cdrecord for CD burning.)
|
||||
<DT>Example for a test session with a cdrecord based scdbackup installation:</DT>
|
||||
<DD>$ <KBD><B>cdrskin -scanbus</B></KBD></DD>
|
||||
<DD><KBD>...</KBD></DD>
|
||||
<DD><KBD>scsibus1:</KBD></DD>
|
||||
<DD><KBD> 1,0,0 0) 'TEAC' 'CD-ROM CD-532S' '?' Removable CD-ROM</KBD></DD>
|
||||
<DD><KBD>scsibus2:</KBD></DD>
|
||||
<DD><KBD> 2,2,0 1) 'LITE-ON' 'LTR-48125S' '?' Removable CD-ROM</KBD></DD>
|
||||
<DD>$ <KBD><B>export SCDBACKUP_SCSI_ADR="2,2,0"</B></KBD></DD>
|
||||
<DD>$ <KBD><B>export SCDBACKUP_CDRECORD="cdrskin -v -v tao_to_sao_tsize=650m eject_device=/dev/cdrecorder"</B></KBD></DD>
|
||||
<DD>(eject_device= has to be the appropriate address for program eject)</DD>
|
||||
<DD>$ <KBD><B>scdbackup_home</B></KBD></DD>
|
||||
</DL>
|
||||
<DL>
|
||||
<DT>Example for a permanent configuration of cdrskin based scdbackup</DT>
|
||||
<DD>$ <KBD><B>cd scdbackup-0.8.6/inst</B></KBD></DD>
|
||||
<DD>$ <KBD><B>export SCDBACKUP_USE_CDRSKIN=1</B></KBD></DD>
|
||||
<DD>$ <KBD><B>export SCDBACKUP_EJECT_ADR=/dev/cdrecorder</B></KBD></DD>
|
||||
<DD>$ <KBD><B>./CONFIGURE_CD</B></KBD></DD>
|
||||
<DD><KBD>...</KBD></DD>
|
||||
<DD><KBD>cdrskin 0.1.2 : limited cdrecord compatibility wrapper for libburn</KBD></DD>
|
||||
<DD><KBD>...</KBD></DD>
|
||||
<DD><KBD> ------------------- SCSI devices. To be used like 0,0,0</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.
|
||||
@ -303,16 +313,34 @@ In this case, you may execute
|
||||
and try again.
|
||||
<DL>
|
||||
<DT></DT>
|
||||
<DD><KBD> 1,0,0 0) 'TEAC' 'CD-ROM CD-532S' '?' Removable CD-ROM</KBD></DD>
|
||||
<DD><KBD> 2,2,0 1) 'LITE-ON' 'LTR-48125S' '?' Removable CD-ROM</KBD></DD>
|
||||
<DD><KBD>------------------- end of SCSI device list</KBD></DD>
|
||||
<DD><KBD> 2,0,0 0) 'TEAC' 'CD-ROM CD-532S' '?' Removable CD-ROM</KBD></DD>
|
||||
<DD>$ <KBD><B>cdrskin -scanbus dev=ATA</B></KBD></DD>
|
||||
<DD><KBD>...</KBD></DD>
|
||||
<DD><KBD> 1,0,0 1) '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>scdbackup_home</B></KBD></DD>
|
||||
</DL>
|
||||
<DL>
|
||||
<DT>Example for a permanent configuration of cdrskin based scdbackup</DT>
|
||||
<DD>$ <KBD><B>cd scdbackup-0.8.6/inst</B></KBD></DD>
|
||||
<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.4 : limited cdrecord compatibility wrapper for libburn</KBD></DD>
|
||||
<DD><KBD>...</KBD></DD>
|
||||
<DD><KBD> ------------------- SCSI devices. To be used like 0,0,0</KBD></DD>
|
||||
<DD><KBD> 2,0,0 0) 'TEAC' 'CD-ROM CD-532S' '?' Removable CD-ROM</KBD></DD>
|
||||
<DD><KBD> ------------------- end of SCSI device list</KBD></DD>
|
||||
<DD><KBD> ------------------- ATA devices. To be used like ATA:0,0,0
|
||||
<DD><KBD> 1,0,0 1) 'LITE-ON' 'LTR-48125S' '?' Removable CD-ROM</KBD></DD>
|
||||
<DD><KBD>...</KBD></DD>
|
||||
<DD><KBD> * Your cdrecord offers -driveropts=burnfree with your recorder.</KBD></DD>
|
||||
<DD><KBD>...</KBD></DD>
|
||||
<DD><KBD>scdbackup for CD 0.8.6 : First stage of installation done.</KBD></DD>
|
||||
<DD><KBD>...</KBD></DD>
|
||||
<DD><KBD>Now give it a try. Run : scdbackup_home</KBD></DD>
|
||||
<DD>$ <KBD><B>unset SCDBACKUP_USE_CDRSKIN SCDBACKUP_EJECT_ADR</B></KBD></DD>
|
||||
<DD>$ <KBD><B>unset SCDBACKUP_USE_CDRSKIN</B></KBD></DD>
|
||||
</DL>
|
||||
<DL>
|
||||
<DT>To get back to using cdrecord :</DT>
|
||||
|
@ -1 +1 @@
|
||||
#define Cdrskin_timestamP "2006.09.16.194730"
|
||||
#define Cdrskin_timestamP "2006.10.28.132532"
|
||||
|
@ -470,49 +470,767 @@ Prepared cdrskin-build for version leap
|
||||
|
||||
----------------------------- cycled (last cdrskin-0.1.5 ?) - 2006.09.15.101326
|
||||
|
||||
2006.09.15.101326 []
|
||||
2006.09.15.101326 [139]
|
||||
cdrskin/README
|
||||
cdrskin/changelog.txt
|
||||
New upload of scdbackup.sourceforge.net/cdrskin-0.1.5.tar.gz
|
||||
|
||||
2006.09.15.174748 [143]
|
||||
cdrskin/cdrskin.c
|
||||
Revoked change of 1 Sep 2006 revision 78 (full -nopad) (ticket 41)
|
||||
|
||||
16 Sep 2006 [144]
|
||||
libburn/libburn.h
|
||||
Made doxygen happy with parameter of burn_drive_get_adr
|
||||
|
||||
Sep 2006 []
|
||||
2006.09.16.194730 [145]
|
||||
000_CAUTION_RELEASE_CANDIDATE
|
||||
zzz_CAUTION_RELEASE_CANDIDATE
|
||||
README
|
||||
Makefile.am
|
||||
cdrskin/README
|
||||
cdrskin/cdrskin_eng.html
|
||||
cdrskin/add_ts_changes_to_libburn_0_2_1
|
||||
cdrskin/add_ts_changes_to_libburn_0_2_2
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/compile_cdrskin.sh
|
||||
( cd_backup_planer_dir/aux/upload )
|
||||
Perfom version leap
|
||||
Perfomed version leap in respect to SVN
|
||||
|
||||
------------------------------ cycle
|
||||
2006.09.19.124540 [160] [161]
|
||||
cdrskin/cdrskin.c
|
||||
Allowed driveropts=burnproof as alias for burnfree
|
||||
|
||||
2006 []
|
||||
2006.09.19.140716 [162] [163]
|
||||
cdrskin/cdrskin.c
|
||||
Added error message in case of failed eject
|
||||
|
||||
2006.09.20.134219 [175] [176] [177]
|
||||
cdrskin/cdrskin.c
|
||||
Fixed bug with dev=1,1,0 (ticket 75)
|
||||
|
||||
21 Sep 2006 [186]
|
||||
configure.ac
|
||||
Makefile.am
|
||||
Forwarded changes from 0.2.2 to 0.2.3
|
||||
|
||||
Sep 2006 [187] [188] [189] [190]
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/compile_cdrskin.sh
|
||||
cdrskin/cdrskin_eng.html
|
||||
cdrskin/README
|
||||
cdrskin/changelog.txt
|
||||
- cdrskin/add_ts_changes_to_libburn_0_2_1
|
||||
+ cdrskin/add_ts_changes_to_libburn_0_2_3
|
||||
Makefile.am
|
||||
cdrskin/cdrskin_timestamp.h
|
||||
Performed development version leap to cdrskin-0.2.3
|
||||
|
||||
------------------------------------ cycled - cdrskin-0.2.3 - 2006.09.21.082411
|
||||
|
||||
21 Sep 2006 [191]
|
||||
README
|
||||
Clarified build from SVN versus tarball
|
||||
|
||||
2006.09.21.173012 [192]
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/compile_cdrskin.sh
|
||||
Gave up compile options -tarball_0_2 , -cvs_A51208 , -libburn_0_2_1
|
||||
Now standard and therefore no longer needed as macros:
|
||||
Cdrskin_libburn_p_sectoR
|
||||
Cdrskin_libburn_with_fd_sourcE
|
||||
Cdrskin_libburn_largefilE
|
||||
Cdrskin_libburn_padding_does_worK
|
||||
|
||||
2006.09.21.185623 [193]
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/compile_cdrskin.sh
|
||||
Officialized gestures of pre-0.2.3 -experimental, introduced -oldfashioned
|
||||
|
||||
2006.09.21.194006 [194]
|
||||
cdrskin/cdrskin.c
|
||||
Investigating failure to open drive on eject
|
||||
|
||||
2006.09.22.133027 [195]
|
||||
libburn/libburn.h
|
||||
libburn/sg.c
|
||||
libburn/sg.h
|
||||
libburn/drive.c
|
||||
cdrskin/cdrskin.c
|
||||
Implemented resolving of softlinks (ticket 33)
|
||||
|
||||
2006.09.22.170220 [196]
|
||||
libburn/libburn.h
|
||||
libburn/sg.c
|
||||
libburn/sg.h
|
||||
libburn/drive.c
|
||||
cdrskin/cdrskin.c
|
||||
Implemented new API function burn_drive_convert_fs_adr()
|
||||
|
||||
|
||||
2006.09.22.172307 [197]
|
||||
cdrskin/cdrskin.c
|
||||
Fixed SIGSEGV of -eject on non-existent device address
|
||||
|
||||
22 Sep 2006 [198]
|
||||
libburn/sg.c
|
||||
libburn/sg.h
|
||||
libburn/drive.c
|
||||
Implemented finding matching /dev/sgN from /dev/srM or /dev/scdK
|
||||
(ioctl(): SCSI_IOCTL_GET_IDLUN)
|
||||
|
||||
2006.09.22.195414 [199]
|
||||
cdrskin/cdrskin.c
|
||||
Removed bug prone implementation of link resolving (now only via libburn)
|
||||
|
||||
2006.09.22.202631 [200]
|
||||
cdrskin/cdrskin.c
|
||||
Kept new address conversion from hopping on libburn drive numbers
|
||||
|
||||
2006.09.22.203939 [201]
|
||||
cdrskin/cdrskin.c
|
||||
Fixed --no_follow_links and renamed to --no_convert_fs_adr
|
||||
|
||||
2006.09.23.080015 [202]
|
||||
libburn/drive.c
|
||||
Restructured SCSI search, removed a potential bug with hdX
|
||||
|
||||
23 Sep 2006 [203]
|
||||
libburn/libburn.h
|
||||
Made burn_drive_convert_scsi_adr() a new API function
|
||||
|
||||
23 Sep 2006 [204]
|
||||
libburn/drive.c
|
||||
libburn/sg.c
|
||||
Changed outdated comments
|
||||
|
||||
23 Sep 2006 [205]
|
||||
libburn/libburn.h
|
||||
libburn/drive.c
|
||||
Introduced new API function burn_drive_obtain_scsi_adr()
|
||||
|
||||
2006.09.23.100001 [not in libburn-0.2.2 yet]
|
||||
cdrskin-0.2.2/cdrskin/cdrskin.c
|
||||
Backported bug fix of revision 197. Version timestamp : 2006.09.23.100001
|
||||
|
||||
23 Sep 2006 [206] [207]
|
||||
libburn/drive.c
|
||||
libburn/sg.c
|
||||
Enabled unused SCSI part of struct burn_drive. Switched persistent address to burn_drive.devname
|
||||
|
||||
2006.09.23.114858 [208]
|
||||
cdrskin/cdrskin.c
|
||||
Implemented --no_pseudo_scsi_adr
|
||||
|
||||
2006.09.23.132755 [209]
|
||||
cdrskin/cdrskin.c
|
||||
libburn/drive.c
|
||||
Removed a bug with SCSI address of scanned drives without such address
|
||||
|
||||
23 Sep 2006 [210]
|
||||
cdrskin/README
|
||||
Explained the new addressing mode
|
||||
|
||||
2006.09.23.182444 [211]
|
||||
cdrskin/README
|
||||
cdrskin/cdrskin.c
|
||||
Bus,Target,Lun for dev=ATA and dev=ATAPI, real SCSI addressing by default
|
||||
|
||||
2006.09.23.183608 [212]
|
||||
cdrskin/cdrskin.c
|
||||
Made small improvement with debug message
|
||||
|
||||
2006.09.24.171706 [214]
|
||||
Makefile.am
|
||||
libburn/libburn.h
|
||||
libburn/libdax_msgs.h
|
||||
libburn/libdax_msgs.c
|
||||
libburn/init.c
|
||||
cdrskin/compile_cdrskin.sh
|
||||
cdrskin/cdrskin.c
|
||||
Added an error message handling facility (ticket 74)
|
||||
|
||||
2006.09.24.180836 [215]
|
||||
libburn/init.c
|
||||
libburn/sg.c
|
||||
libburn/libdax_msgs.h
|
||||
libburn/libdax_msgs.c
|
||||
cdrskin/cdrskin.c
|
||||
Made use of new message handling facility and removed first bugs
|
||||
|
||||
24 Sep 2006 [216]
|
||||
libburn/libdax_msgs.h
|
||||
Recorded error_code 0x00020001
|
||||
|
||||
24 Sep 2006 [217] [218]
|
||||
Makefile.am
|
||||
libburn/libburn.h
|
||||
libburn/write.c
|
||||
libburn/drive.c
|
||||
cdrskin/compile_cdrskin.sh
|
||||
Obsoleted libburn/message.[ch]
|
||||
|
||||
25 Sep 2006 [219]
|
||||
libburn/read.c
|
||||
libburn/write.c
|
||||
Removed inclusion of libburn/message.h
|
||||
|
||||
2006.09.25.104629 [220]
|
||||
libburn/init.c
|
||||
libburn/drive.c
|
||||
cdrskin/cdrskin.c
|
||||
Converted "libburn_experimental:" messages of address conversion into "DEBUG"
|
||||
|
||||
2006.09.25.141035 [221]
|
||||
libburn/libdax_msgs.h
|
||||
libburn/libdax_msgs.c
|
||||
libburn/drive.c
|
||||
libburn/sg.h
|
||||
libburn/sg.c
|
||||
Implemented sg_close_drive_fd (ticket 74)
|
||||
|
||||
2006.09.25.144506 [222]
|
||||
libburn/libdax_msgs.c
|
||||
Achieved minimum strerror thread safety (strerror_r is burned by Unix and GNU)
|
||||
|
||||
2006.09.26.114552 [223]
|
||||
libburn/libburn.h
|
||||
libburn/init.c
|
||||
libburn/libdax_msgs.c
|
||||
cdrskin/cdrskin.c
|
||||
Made first use of queued messages and fixed several bugs with that
|
||||
|
||||
2006.09.26.142824 [224]
|
||||
libburn/sg.c
|
||||
libburn/libdax_msgs.h
|
||||
cdrskin/cdrskin.c
|
||||
Made changes with usage of queued messages
|
||||
|
||||
24 Sep 2006 [225]
|
||||
Makefile.am
|
||||
libburn/libburn.h
|
||||
libburn/write.c
|
||||
libburn/drive.c
|
||||
- libburn/message.c
|
||||
- libburn/message.h
|
||||
Removed libburn/message.[ch]
|
||||
|
||||
2006.09.26.205504 [227]
|
||||
libburn/drive.c
|
||||
Enhanced softlink resolution
|
||||
|
||||
2006.09.26.210711 [228]
|
||||
libburn/drive.c
|
||||
Fixed bug in enhanced softlink resolution
|
||||
|
||||
2006.09.27.063147 [229]
|
||||
cdrskin/cdrskin.c
|
||||
Fixed bug with relative device addresses and Cdrpreskin__cdrecord_to_dev()
|
||||
|
||||
2006.09.27.074910 [230]
|
||||
cdrskin/cdrskin.c
|
||||
Fixed broken -version and --help (second time for same mistake)
|
||||
|
||||
2006.09.27.080826 [231]
|
||||
cdrskin/README
|
||||
cdrskin/cdrskin.c
|
||||
Allowed comments and empty lines in startup files
|
||||
|
||||
2006.09.27.082057 [232]
|
||||
cdrskin/cdrskin.c
|
||||
Prevented reading of startup files with first arg -version, -help or --help
|
||||
|
||||
2006.09.27.115919 [233]
|
||||
libburn/drive.c
|
||||
libburn/sg.h
|
||||
libburn/sg.c
|
||||
libburn/libdax_msgs.h
|
||||
cdrskin/cdrskin.c
|
||||
Disabled but did not discarded failed attempt to lock against growisofs
|
||||
|
||||
2006.09.27.120656 [234]
|
||||
libburn/drive.h
|
||||
libburn/init.c
|
||||
libburn/transport.h
|
||||
libburn/libburn.h
|
||||
Disabled but did not discarded failed attempt to lock against growisofs
|
||||
|
||||
2006.09.27.134332 [235]
|
||||
libburn/sg.c
|
||||
Kept /dev/hdX from all having SCSI address 0,0,0
|
||||
|
||||
2006.09.27.142312 [236]
|
||||
libburn/drive.c
|
||||
Curbed endless links to 20 hops
|
||||
|
||||
2006.09.27.143843 [237]
|
||||
libburn/sg.c
|
||||
Removed obsolete code and comments
|
||||
|
||||
2006.09.28.074434 [238]
|
||||
cdrskin/cdrskin.c
|
||||
Enabled optional growisofs lock attempt via --drive_scsi_exclusive
|
||||
|
||||
28 Sep 2006 [239]
|
||||
libburn/libburn.h
|
||||
Made official exclusive==2 with burn_preset_device_open()
|
||||
|
||||
------------------------------------ cycled - cdrskin-0.2.3 - 2006.09.28.100934
|
||||
|
||||
2006.09.28.115152 [240]
|
||||
cdrskin/cdrskin.c
|
||||
Restored vanished line at end of -help text and added a new one
|
||||
|
||||
2006.10.01.104140 [243]
|
||||
libburn/drive.c
|
||||
cdrskin/cdrskin.c
|
||||
Enhanced Cdrpreskin__cdrecord_to_dev so it warns of invisible SCSI drive.
|
||||
|
||||
2006.10.02.103418 [244]
|
||||
libburn/libburn.h
|
||||
libburn/drive.h
|
||||
libburn/drive.c
|
||||
libburn/libdax_msgs.h
|
||||
libburn/libdax_msgs.c
|
||||
cdrskin/cdrskin.c
|
||||
Implemented burn_abort() and made use of it
|
||||
|
||||
2006.10.03.162719 [245]
|
||||
Makefile.am
|
||||
libburn/libburn.h
|
||||
libburn/init.c
|
||||
libburn/cleanup.h
|
||||
libburn/cleanup.c
|
||||
cdrskin/cleanup.h
|
||||
cdrskin/cleanup.c
|
||||
test/libburner.c
|
||||
--audio and multi-track
|
||||
cdrskin/compile_cdrskin.sh
|
||||
cdrskin/cdrskin.c
|
||||
Implemented new API function burn_set_signal_handling(), libburner uses it
|
||||
|
||||
5 Oct 2006 [246]
|
||||
libburn/drive.c
|
||||
Uploaded forgotten part of revision 245
|
||||
|
||||
2006.10.05.142628 [247]
|
||||
libburn/libburn.h
|
||||
libburn/transport.h
|
||||
libburn/sg.c
|
||||
libburn/sg.h
|
||||
libburn/drive.c
|
||||
cdrskin/cdrskin.c
|
||||
Made use of SCSI_IOCTL_GET_BUS_NUMBER in hope of cdrecord compatibility
|
||||
|
||||
6 Oct 2006 [248]
|
||||
+ libburn/asserts.txt
|
||||
Listed findings on assert() within libburn
|
||||
|
||||
7 Oct 2006 [249]
|
||||
libburn/async.c
|
||||
libburn/libdax_msgs.h
|
||||
libburn/asserts.txt
|
||||
Got rid by soft means of assert() in async.c
|
||||
|
||||
2006.10.07.121234 [250]
|
||||
libburn/libburn.h
|
||||
libburn/async.c
|
||||
libburn/drive.h
|
||||
libburn/drive.c
|
||||
libburn/init.c
|
||||
libburn/libdax_msgs.h
|
||||
libburn/sg.c
|
||||
libburn/asserts.txt
|
||||
Got rid of assert() in drive.c by soft means
|
||||
|
||||
2006.10.07.132916 [251]
|
||||
libburn/init.c
|
||||
libburn/async.c
|
||||
Got rid of assert() in init.c by soft means
|
||||
|
||||
2006.10.07.142454 [252]
|
||||
libburn/libburn.h
|
||||
libburn/async.c
|
||||
libburn/options.c
|
||||
libburn/sector.c
|
||||
libburn/spc.c
|
||||
libburn/libdax_msgs.h
|
||||
Got rid of assert() in options.c by soft means
|
||||
|
||||
7 Oct 2006 [253]
|
||||
libburn/read.c
|
||||
Got rid of assert() in read.c by soft means
|
||||
|
||||
2006.10.07.170913 [254]
|
||||
libburn/sg.c
|
||||
libburn/asserts.txt
|
||||
Got rid of some assert() in sg.c by soft means
|
||||
|
||||
2006.10.07.175427 [255]
|
||||
libburn/spc.c
|
||||
libburn/async.c
|
||||
libburn/libdax_msgs.h
|
||||
Got rid of assert() in spc.c by soft means
|
||||
|
||||
2006.10.08.095016 [256]
|
||||
libburn/structure.c
|
||||
libburn/sector.c
|
||||
libburn/spc.c
|
||||
libburn/libdax_msgs.h
|
||||
libburn/asserts.txt
|
||||
Got rid of assert() in structure.c by soft means
|
||||
|
||||
8 Oct 2006 [257]
|
||||
libburn/toc.c
|
||||
Got rid of assert() in toc.c by soft means
|
||||
|
||||
8 Oct 2006 [258]
|
||||
libburn/util.c
|
||||
Got rid of assert() in util.c by soft means
|
||||
|
||||
2006.10.09.083438 [259]
|
||||
libburn/write.c
|
||||
libburn/structure.c
|
||||
libburn/libdax_msgs.h
|
||||
libburn/asserts.txt
|
||||
Got rid of assert() in write.c by soft means
|
||||
|
||||
2006.10.09.123518 [260]
|
||||
libburn/mmc.c
|
||||
libburn/read.c
|
||||
libburn/sector.c
|
||||
libburn/mmc.h
|
||||
libburn/transport.h
|
||||
libburn/asserts.txt
|
||||
Got rid of assert() in mmc.c by soft means
|
||||
|
||||
2006.10.10.112545 [261]
|
||||
libburn/sector.h
|
||||
libburn/sector.c
|
||||
libburn/async.c
|
||||
libburn/write.h
|
||||
libburn/write.c
|
||||
libburn/libdax_msgs.h
|
||||
libburn/asserts.txt
|
||||
Got rid of assert() in sector.c by soft means
|
||||
|
||||
2006.10.10.175444 [262]
|
||||
libburn/sg.c
|
||||
libburn/libdax_msgs.h
|
||||
Got rid of assert() in sg.c by soft means
|
||||
|
||||
10 Oct 2006 [263]
|
||||
libburn/asserts.txt
|
||||
Got rid of assert() in libburn
|
||||
|
||||
2006.10.11.191959 [264]
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/README
|
||||
Changed pseudo-cdrecord addresses: /dev/hdX = ATA:(X-'a')/2,(X-'a')%2,0
|
||||
|
||||
13 Oct 2006 [270]
|
||||
Makefile.am
|
||||
libburn/sg.c
|
||||
libburn/cleanup.c
|
||||
libburn/sg-linux.c
|
||||
libburn/read.c
|
||||
libburn/drive.c
|
||||
libburn/sbc.c
|
||||
libburn/transport.h
|
||||
cdrskin/cleanup.c
|
||||
Made libburn and cdrskin build on my Linux again
|
||||
|
||||
2006.10.13.114554 [271]
|
||||
cdrskin/cdrskin.c
|
||||
libburn/write.c
|
||||
libburn/sg-linux.c
|
||||
libburn/libdax_msgs.h
|
||||
Removed bug in burn_disc_write_sync(): BURN_DRIVE_IDLE, then d->sync_cache()
|
||||
|
||||
2006.10.14.105224 [272]
|
||||
libburn/sg.h
|
||||
libburn/sg-freebsd.c
|
||||
libburn/sg-linux.c
|
||||
libburn/drive.c
|
||||
Introduced burn_drive_enumerator_t to allow more complete sg-freebsd implementation
|
||||
|
||||
2006.10.15.133035 [274]
|
||||
cdrskin/cdrskin.c
|
||||
Changed ambigous include statement of libburn.h
|
||||
|
||||
15 Oct 2006 2006 [275]
|
||||
Makefile.am
|
||||
libburn/libdax_msgs.h
|
||||
+ libburn/libdax_audioxtr.h
|
||||
+ libburn/libdax_audioxtr.c
|
||||
Implemented a first attempt of a .wav decapitator (ticket 38)
|
||||
|
||||
15 Oct 2006 2006 [276]
|
||||
+ test/dewav.c
|
||||
Implemented a first attempt of a .wav decapitator (ticket 38)
|
||||
|
||||
15 Oct 2006 2006 [277]
|
||||
test/dewav.c
|
||||
Fixed permissions of eventually created output file
|
||||
|
||||
15 Oct 2006 2006 [278]
|
||||
test/dewav.c
|
||||
cdrskin/compile_cdrskin.sh
|
||||
Hunting a malloc/free memory problem
|
||||
|
||||
15 Oct 2006 2006 [279]
|
||||
libburn/libdax_audioxtr.c
|
||||
Hopefully fixed memory problem which causes sigabrt on free
|
||||
|
||||
15 Oct 2006 2006 [280]
|
||||
libburn/libdax_audioxtr.c
|
||||
Hopefully fixed problem with stdin as audio source
|
||||
|
||||
15 Oct 2006 2006 [281]
|
||||
test/dewav.c
|
||||
Made helptext print to stderr rather than stdout
|
||||
|
||||
2006.10.17.141053 [283]
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/compile_cdrskin.sh
|
||||
libburn/libdax_audioxtr.h
|
||||
libburn/libdax_audioxtr.c
|
||||
test/dewav.c
|
||||
Roughly implemented automatic .wav extraction in cdrskin
|
||||
|
||||
2006.10.17.164140 [284]
|
||||
cdrskin/cdrskin.c
|
||||
libburn/libdax_audioxtr.h
|
||||
libburn/libdax_audioxtr.c
|
||||
test/dewav.c
|
||||
Implemented some cdrecord pickiness for .wav extraction
|
||||
|
||||
18 Oct 2006 [285]
|
||||
test/libburner.c
|
||||
Added --audio and multi-track, removed --verbose, hid --burn_for_real
|
||||
|
||||
2006.10.18.174334 [286]
|
||||
cdrskin/cdrskin.c
|
||||
Removed assumption BURN_DRIVE_IDLE==0
|
||||
|
||||
18 Oct 2006 [287]
|
||||
cdrskin/README
|
||||
Changed audio statements to reflect new situation
|
||||
|
||||
18 Oct 2006 [288]
|
||||
cdrskin/README
|
||||
Removed a typo
|
||||
|
||||
19 Oct 2006 [292]
|
||||
test/libburner.c
|
||||
Freed all tracks after burning and not only last one
|
||||
|
||||
2006.10.19.094543 [293]
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/compile_cdrskin.sh
|
||||
Made cdrskin use libburn/cleanup.[oh] by default (not cdrskin/cleanup.[ch])
|
||||
|
||||
------------------------------------ cycled - cdrskin-0.2.3 - 2006.10.19.105730
|
||||
|
||||
2006.10.19.162254 [294]
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/cdrskin_eng.html
|
||||
cdrskin/changelog.txt
|
||||
Updated documentation about cdrskin-0.2.3
|
||||
|
||||
2006.10.19.164742 [295]
|
||||
cdrskin/cdrskin.c
|
||||
Corrected -help text
|
||||
|
||||
2006.10.20.113421 [297]
|
||||
libburn/libburn.h
|
||||
libburn/mmc.c
|
||||
libburn/sg-linux.c
|
||||
libburn/sg-freebsd.c
|
||||
libburn/drive.c
|
||||
cdrskin/cdrskin.c
|
||||
Made cdrskin produce "ATIP start of lead" (on non-blank media for now)
|
||||
|
||||
20 Oct 2006 [298]
|
||||
doc/comments
|
||||
Updated help text of libburner
|
||||
|
||||
2006.10.20.151602 [299]
|
||||
libburn/libburn.h
|
||||
libburn/drive.c
|
||||
libburn/mmc.c
|
||||
libburn/libdax_msgs.h
|
||||
cdrskin/cdrskin.c
|
||||
Classified media with TOC read error as unsuitable (rather than as blank)
|
||||
|
||||
2006.10.21.103352 [300]
|
||||
libburn/libburn.h
|
||||
libburn/transport.h
|
||||
libburn/drive.c
|
||||
libburn/mmc.c
|
||||
libburn/spc.c
|
||||
libburn/sg-linux.c
|
||||
libburn/sg-freebsd.c
|
||||
libburn/libdax_msgs.h
|
||||
cdrskin/cdrskin.c
|
||||
Implemented some ATIP functionality
|
||||
|
||||
2006.10.21.103653 [301] [302]
|
||||
libburn/libburn.h
|
||||
Clarified relation of burn_disc_read_atip() and burn_drive_get_start_end_lba()
|
||||
|
||||
2006.10.21.185102 [303]
|
||||
libburn/sg.h
|
||||
libburn/mmc.h
|
||||
libburn/mmc.c
|
||||
libburn/sbc.h
|
||||
libburn/sbc.c
|
||||
libburn/spc.h
|
||||
libburn/spc.c
|
||||
libburn/drive.h
|
||||
libburn/drive.c
|
||||
libburn/transport.h
|
||||
libburn/sg-linux.c
|
||||
libburn/sg-freebsd.c
|
||||
Split enumerate_common() into logic-layer, command-layer, transport-layer
|
||||
|
||||
2006.10.22.130341 [304]
|
||||
libburn/libburn.h
|
||||
libburn/mmc.c
|
||||
libburn/drive.c
|
||||
libburn/cleanup.c
|
||||
cdrskin/cleanup.c
|
||||
cdrskin/cdrskin.c
|
||||
Implemented cdrskin -toc
|
||||
|
||||
2006.10.22.131452 [305]
|
||||
cdrskin/cdrskin.c
|
||||
Regulated coexistence of options -toc and -atip
|
||||
|
||||
23 Oct 2006 [306]
|
||||
libburn/mmc.c
|
||||
Made clarification in remark about atip speed conversion
|
||||
|
||||
2006.10.23.074430 [307]
|
||||
cdrskin/cdrskin.c
|
||||
Made use of burn_drive_info.revision as firmware revision text
|
||||
|
||||
2006.10.23.113116 [308]
|
||||
libburn/libburn.h
|
||||
libburn/transport.h
|
||||
libburn/mmc.h
|
||||
libburn/mmc.c
|
||||
libburn/write.c
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/cdrskin_eng.html
|
||||
cdrskin/README
|
||||
Made available drive buffer fill during write
|
||||
|
||||
23 Oct 2006 [309]
|
||||
libburn/sg-freebsd.c
|
||||
Updated tangling of FreeBSD code with mmc.c :(
|
||||
|
||||
|
||||
2006.10.23.134719 [310]
|
||||
cdrskin/cdrskin.c
|
||||
Corrected -toc track counter and notified about "hidden" tracks
|
||||
|
||||
2006.10.24.075039 [311]
|
||||
libburn/libdax_audioxtr.h
|
||||
libburn/libdax_audioxtr.c
|
||||
test/dewav.c
|
||||
cdrskin/cdrskin.c
|
||||
Introduced extraction of .au (but not its usage within cdrskin)
|
||||
|
||||
2006.10.24.102107 [312]
|
||||
libburn/libburn.h
|
||||
libburn/structure.h
|
||||
libburn/structure.c
|
||||
libburn/sector.c
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/README
|
||||
Enabled byte swapping for audio track sources, added anti option -swab
|
||||
|
||||
2006.10.24.130259 [313]
|
||||
test/dewav.c
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/README
|
||||
Enabled automatic extraction of .au
|
||||
|
||||
24 Oct 2006 [314]
|
||||
Makefile.am
|
||||
+ test/fake_au.c
|
||||
Introduced temporary test program to produce SUN .au files
|
||||
|
||||
------------------------------------ cycled - cdrskin-0.2.3 - 2006.10.24.144650
|
||||
|
||||
2006.10.24.165427 [315]
|
||||
libburn/sector.c
|
||||
Closed some loopholes for byte swapping.
|
||||
|
||||
|
||||
2006.10.24.165610 [316]
|
||||
cdrskin/cdrskin.c
|
||||
Enabled audio byte swapping by default (to be disabled via option -swab)
|
||||
|
||||
------------------------------------ cycled - cdrskin-0.2.3 - 2006.10.24.173602
|
||||
|
||||
25 Oct 2006 [317]
|
||||
cdrskin/README
|
||||
cdrskin/cdrskin_eng.html
|
||||
cdrskin/wiki_plain.txt
|
||||
Announced full -audio compatibility with cdrecord
|
||||
|
||||
------------------------------------ cycled - cdrskin-0.2.3 - 2006.10.25.160540
|
||||
|
||||
[]
|
||||
- cdrskin/add_ts_changes_to_libburn_0_2_3
|
||||
+ cdrskin/add_ts_changes_to_libburn_0_2_4
|
||||
cdrskin/README
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/cdrskin_eng.html
|
||||
cdrskin/changelog.txt
|
||||
README
|
||||
Preparing cdrskin version leap to cdrskin-0.2.4
|
||||
(To be committed to branch)
|
||||
|
||||
|
||||
------------------------------------ cycle - cdrskin-0.2.5
|
||||
|
||||
[]
|
||||
- cdrskin/add_ts_changes_to_libburn_0_2_3
|
||||
+ cdrskin/add_ts_changes_to_libburn_0_2_4
|
||||
+ cdrskin/add_ts_changes_to_libburn_0_2_5
|
||||
cdrskin/README
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/cdrskin_eng.html
|
||||
cdrskin/changelog.txt
|
||||
README
|
||||
Prepare cdrskin version leap to cdrskin-0.2.5
|
||||
(To be committed to trunk)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
2006 []
|
||||
Resolve softlinks (ticket 33)
|
||||
-reset: ioctl(fd,CDROMRESET) ioctl(fd,SG_SCSI_RESET,SG_SCSI_RESET_DEVICE)
|
||||
|
||||
2006 []
|
||||
Find matching /dev/sgN from srM or scdM
|
||||
Try wether tao will work if finalized by mmc_close()
|
||||
|
||||
2006 []
|
||||
Implement a .wav decapitator (ticket 38)
|
||||
Open O_EXCL all devices in address resolution chain
|
||||
(Might help with non-standard hdX device siblings)
|
||||
|
||||
2006 []
|
||||
Convert libburn_experimental: into LIBDAX_MSGS_SEV_DEBUG
|
||||
Convert burn_print() into libdax_msgs_submit()
|
||||
|
||||
2006 []
|
||||
Test unlocking of all drives by burn_drive_info_free()
|
||||
Test unlocking of single drive by burn_drive_grab(), burn_drive_release()
|
||||
|
||||
|
||||
|
||||
|
||||
2006 []
|
||||
Clear outdated persistent read buffer after small CD image was read (ticket 57)
|
||||
|
||||
|
||||
2006 []
|
||||
>>> libburn/libburn.h
|
||||
>>> libburn/drive.c
|
||||
>>> libburn/sg.c
|
||||
>>> Promoted burn_drive_is_open() to official API
|
||||
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
A signal handler which cleans up an application and exits.
|
||||
|
||||
Provided under GPL license within cdrskin and under BSD license elsewise.
|
||||
Provided under GPL license within GPL projects, BSD license elsewise.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -23,6 +23,29 @@ typedef void (*sighandler_t)(int);
|
||||
|
||||
#include "cleanup.h"
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
|
||||
/* Signals to be caught */
|
||||
static int signal_list[]= {
|
||||
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT,
|
||||
SIGFPE, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM,
|
||||
SIGUSR1, SIGUSR2, SIGXCPU, SIGTSTP, SIGTTIN,
|
||||
SIGTTOU,
|
||||
SIGBUS, SIGPROF, SIGSYS, SIGTRAP,
|
||||
SIGVTALRM, SIGXCPU, SIGXFSZ, -1
|
||||
};
|
||||
static char *signal_name_list[]= {
|
||||
"SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGABRT",
|
||||
"SIGFPE", "SIGSEGV", "SIGPIPE", "SIGALRM", "SIGTERM",
|
||||
"SIGUSR1", "SIGUSR2", "SIGXCPU", "SIGTSTP", "SIGTTIN",
|
||||
"SIGTTOU",
|
||||
"SIGBUS", "SIGPROF", "SIGSYS", "SIGTRAP",
|
||||
"SIGVTALRM", "SIGXCPU", "SIGXFSZ", "@"
|
||||
};
|
||||
static int signal_list_count= 23;
|
||||
|
||||
#else /* __FreeBSD__ */
|
||||
|
||||
/* Signals to be caught */
|
||||
static int signal_list[]= {
|
||||
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT,
|
||||
@ -42,6 +65,8 @@ static char *signal_name_list[]= {
|
||||
};
|
||||
static int signal_list_count= 24;
|
||||
|
||||
#endif /* ! __FreeBSD__ */
|
||||
|
||||
/* Signals not to be caught */
|
||||
static int non_signal_list[]= {
|
||||
SIGKILL, SIGCHLD, SIGSTOP, SIGURG, -1
|
||||
@ -62,26 +87,27 @@ static int Cleanup_handler_exit(int exit_value, int signum, int flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if(cleanup_msg[0]!=0)
|
||||
fprintf(stderr,"\n%s\n",cleanup_msg);
|
||||
if(cleanup_perform_app_handler_first)
|
||||
if(cleanup_app_handler!=NULL) {
|
||||
ret= (*cleanup_app_handler)(cleanup_app_handle,signum,0);
|
||||
if(ret==2)
|
||||
if(ret==2 || ret==-2)
|
||||
return(2);
|
||||
}
|
||||
if(cleanup_exiting) {
|
||||
if(cleanup_msg[0]!=0)
|
||||
fprintf(stderr,"%s\n",cleanup_msg);
|
||||
fprintf(stderr,"cleanup: ABORT : repeat by pid=%d, signum=%d\n",
|
||||
getpid(),signum);
|
||||
return(0);
|
||||
}
|
||||
cleanup_exiting= 1;
|
||||
if(cleanup_msg[0]!=0)
|
||||
fprintf(stderr,"%s\n",cleanup_msg);
|
||||
alarm(0);
|
||||
if(!cleanup_perform_app_handler_first)
|
||||
if(cleanup_app_handler!=NULL)
|
||||
(*cleanup_app_handler)(cleanup_app_handle,signum,0);
|
||||
if(cleanup_app_handler!=NULL) {
|
||||
ret= (*cleanup_app_handler)(cleanup_app_handle,signum,0);
|
||||
if(ret==2 || ret==-2)
|
||||
return(2);
|
||||
}
|
||||
exit(exit_value);
|
||||
}
|
||||
|
||||
@ -115,8 +141,12 @@ int Cleanup_set_handlers(void *handle, Cleanup_app_handler_T handler, int flag)
|
||||
cleanup_msg[0]= 0;
|
||||
cleanup_app_handle= handle;
|
||||
cleanup_app_handler= handler;
|
||||
|
||||
/* <<< make cleanup_exiting thread safe to get rid of this */
|
||||
if(flag&4)
|
||||
cleanup_perform_app_handler_first= 1;
|
||||
|
||||
|
||||
if(flag&1)
|
||||
sig_handler= SIG_DFL;
|
||||
else if(flag&2)
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
A signal handler which cleans up an application and exits.
|
||||
|
||||
Provided under GPL license within cdrskin and under BSD license elsewise.
|
||||
Provided under GPL license within GPL projects, BSD license elsewise.
|
||||
*/
|
||||
|
||||
#ifndef Cleanup_includeD
|
||||
@ -13,7 +13,7 @@
|
||||
/** Layout of an application provided cleanup function using an application
|
||||
provided handle as first argument and the signal number as second
|
||||
argument. The third argument is a flag bit field with no defined bits yet.
|
||||
If the handler returns 2 then it has delegated exit() to some other
|
||||
If the handler returns 2 or -2 then it has delegated exit() to some other
|
||||
instance and the Cleanup handler shall return rather than exit.
|
||||
*/
|
||||
typedef int (*Cleanup_app_handler_T)(void *, int, int);
|
||||
|
@ -6,37 +6,50 @@
|
||||
|
||||
debug_opts=
|
||||
def_opts=
|
||||
libvers="-DCdrskin_libburn_0_2_2"
|
||||
libvers="-DCdrskin_libburn_0_2_3"
|
||||
cleanup_src_or_obj="libburn/cleanup.o"
|
||||
libdax_msgs_o="libburn/libdax_msgs.o"
|
||||
libdax_audioxtr_o="libburn/libdax_audioxtr.o"
|
||||
do_strip=0
|
||||
static_opts=
|
||||
warn_opts="-Wall"
|
||||
fifo_source="cdrskin/cdrfifo.c"
|
||||
compile_cdrskin=1
|
||||
compile_cdrfifo=0
|
||||
compile_dewav=0
|
||||
|
||||
for i in "$@"
|
||||
do
|
||||
if test "$i" = "-compile_cdrfifo"
|
||||
then
|
||||
compile_cdrfifo=1
|
||||
elif test "$i" = "-tarball_0_2"
|
||||
elif test "$i" = "-compile_dewav"
|
||||
then
|
||||
libvers=
|
||||
elif test "$i" = "-cvs_A51208"
|
||||
then
|
||||
libvers="-DCdrskin_libburn_cvs_A51208_tS"
|
||||
compile_dewav=1
|
||||
elif test "$i" = "-cvs_A60220"
|
||||
then
|
||||
libvers="-DCdrskin_libburn_cvs_A60220_tS"
|
||||
elif test "$i" = "-libburn_0_2_1"
|
||||
then
|
||||
libvers="-DCdrskin_libburn_0_2_1"
|
||||
libdax_audioxtr_o=
|
||||
libdax_msgs_o="libburn/message.o"
|
||||
cleanup_src_or_obj="cdrskin/cleanup.c"
|
||||
elif test "$i" = "-libburn_0_2_2"
|
||||
then
|
||||
libvers="-DCdrskin_libburn_0_2_2"
|
||||
libdax_audioxtr_o=
|
||||
libdax_msgs_o="libburn/message.o"
|
||||
cleanup_src_or_obj="cdrskin/cleanup.c"
|
||||
elif test "$i" = "-libburn_0_2_3"
|
||||
then
|
||||
libvers="-DCdrskin_libburn_0_2_3"
|
||||
libdax_audioxtr_o="libburn/libdax_audioxtr.o"
|
||||
libdax_msgs_o="libburn/libdax_msgs.o"
|
||||
cleanup_src_or_obj="libburn/cleanup.o"
|
||||
elif test "$i" = "-newapi" -o "$i" = "-experimental"
|
||||
then
|
||||
def_opts="$def_opts -DCdrskin_new_api_tesT"
|
||||
elif test "$i" = "-oldfashioned"
|
||||
then
|
||||
def_opts="$def_opts -DCdrskin_oldfashioned_api_usE"
|
||||
elif test "$i" = "-do_not_compile_cdrskin"
|
||||
then
|
||||
compile_cdrskin=0
|
||||
@ -56,16 +69,16 @@ do
|
||||
debug_opts="$debug_opts -O2"
|
||||
elif test "$i" = "-help" -o "$i" = "--help" -o "$i" = "-h"
|
||||
then
|
||||
echo "cdrskin/compile_cdrskin.sh : to be executed within ./cdrskin-0.1.3.0.2.ts"
|
||||
echo "cdrskin/compile_cdrskin.sh : to be executed within top level directory"
|
||||
echo "Options:"
|
||||
echo " -compile_cdrfifo compile program cdrskin/cdrfifo."
|
||||
echo " -tarball_0_2 set macro to match libburn-0.2.ts.tar.gz"
|
||||
echo " -cvs_A51208 set macro to match libburn-CVS of 8 Dec 2005."
|
||||
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_1 set macro to match libburn-SVN of 15 Sep 2006."
|
||||
echo " -libburn_0_2_2 set macro to match libburn-0.2.2"
|
||||
echo " -libburn_0_2_2 set macro to match libburn-0.2.2."
|
||||
echo " -libburn_0_2_3 set macro to match current libburn-SVN."
|
||||
echo " -do_not_compile_cdrskin omit compilation of cdrskin/cdrskin."
|
||||
echo " -experimental use newly introduced libburn features."
|
||||
echo " -oldfashioned use pre-0.2.2 libburn features only."
|
||||
echo " -do_diet produce capability reduced lean version."
|
||||
echo " -do_strip apply program strip to compiled programs."
|
||||
echo " -g compile with cc option -g."
|
||||
@ -85,7 +98,7 @@ echo "Build timestamp : $timestamp"
|
||||
|
||||
if test "$compile_cdrskin"
|
||||
then
|
||||
echo "compiling program cdrskin/cdrskin.c $static_opts $debug_opts $libvers $def_opts"
|
||||
echo "compiling program cdrskin/cdrskin.c $static_opts $debug_opts $libvers $def_opts $cleanup_src_or_obj"
|
||||
cc $warn_opts -I. $static_opts $debug_opts $libvers $def_opts \
|
||||
-DCdrskin_build_timestamP='"'"$timestamp"'"' \
|
||||
\
|
||||
@ -93,7 +106,8 @@ then
|
||||
\
|
||||
cdrskin/cdrskin.c \
|
||||
$fifo_source \
|
||||
cdrskin/cleanup.c \
|
||||
\
|
||||
$cleanup_src_or_obj \
|
||||
\
|
||||
libburn/async.o \
|
||||
libburn/debug.o \
|
||||
@ -104,9 +118,10 @@ then
|
||||
libburn/source.o \
|
||||
libburn/structure.o \
|
||||
\
|
||||
libburn/message.o \
|
||||
libburn/sg.o \
|
||||
libburn/write.o \
|
||||
$libdax_audioxtr_o \
|
||||
$libdax_msgs_o \
|
||||
\
|
||||
libburn/mmc.o \
|
||||
libburn/sbc.o \
|
||||
@ -120,6 +135,17 @@ then
|
||||
libburn/lec.o \
|
||||
\
|
||||
-lpthread
|
||||
|
||||
ret=$?
|
||||
if test "$ret" = 0
|
||||
then
|
||||
dummy=dummy
|
||||
else
|
||||
echo >&2
|
||||
echo "+++ FATAL : Compilation of cdrskin failed" >&2
|
||||
echo >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$compile_cdrfifo" = 1
|
||||
@ -129,8 +155,43 @@ then
|
||||
-DCdrfifo_standalonE \
|
||||
-o cdrskin/cdrfifo \
|
||||
cdrskin/cdrfifo.c
|
||||
|
||||
ret=$?
|
||||
if test "$ret" = 0
|
||||
then
|
||||
dummy=dummy
|
||||
else
|
||||
echo >&2
|
||||
echo "+++ FATAL : Compilation of cdrfifo failed" >&2
|
||||
echo >&2
|
||||
exit 2
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$compile_dewav" = 1
|
||||
then
|
||||
echo "compiling program test/dewav.c -DDewav_without_libburN $static_opts $debug_opts"
|
||||
cc $static_opts $debug_opts \
|
||||
-DDewav_without_libburN \
|
||||
-o test/dewav \
|
||||
test/dewav.c \
|
||||
libburn/libdax_audioxtr.o \
|
||||
libburn/libdax_msgs.o \
|
||||
\
|
||||
-lpthread
|
||||
|
||||
ret=$?
|
||||
if test "$ret" = 0
|
||||
then
|
||||
dummy=dummy
|
||||
else
|
||||
echo >&2
|
||||
echo "+++ FATAL : Compilation of test/dewav failed" >&2
|
||||
echo >&2
|
||||
exit 2
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$do_strip" = 1
|
||||
then
|
||||
echo "stripping result cdrskin/cdrskin"
|
||||
|
@ -2,7 +2,7 @@
|
||||
cdrskin Wiki - plain text copy
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
cdrskin is the cdrecord compatibility middleware of libburn.
|
||||
cdrskin-0.2.3 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
|
||||
@ -16,14 +16,8 @@ can be found in cdrskin/README .
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
cdrskin with CD media fails to match its paragon cdrecord on three major
|
||||
fields: convenient TAO burn mode, multi session, audio features.
|
||||
|
||||
Audio features are the only topic where cdrskin did not yet exploit current
|
||||
libburn to the maximum. This is due to my own lack of audiophile motivation
|
||||
and due to the lack of sincere users who provide me with cdrecord use cases,
|
||||
help me to explore the original cdrecord behavior and serve as dedicated
|
||||
testers for eventual newly introduced cdrskin audio features.
|
||||
cdrskin with CD media fails to match its paragon cdrecord on two major
|
||||
fields: convenient TAO burn mode and multi session.
|
||||
|
||||
cdrskin does not provide DVD burning yet. See advise to use dvd+rw-tools
|
||||
at the end of this text.
|
||||
@ -80,45 +74,6 @@ has to offer both, r- and w-permission.
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
eject_device=<path> is needed to work around yet broken tray ejection of
|
||||
drives. cdrskin makes a bold shell call to program "eject" and regrettably
|
||||
this program does not like our addresses for SCSI devices.
|
||||
/dev/hdX work fine and /dev/sg0 is quite safely guess-translated to
|
||||
/dev/sr0 . /dev/sg1 et.al. need the user's help. <path> must work with eject.
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
dev_translation=<sep><from><sep><to> is 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.
|
||||
cdrskin project - at least for now - refuses to try to provide a similar
|
||||
guesswork but uses own cdrecord style addresses which have a mere
|
||||
semi-automatic text mapping to real libburn addresses. See cdrskin/README,
|
||||
"Pseudo-SCSI Adresses".
|
||||
|
||||
If you need to foist cdrskin under a frontend then you may be lucky and
|
||||
both ideas of an address coincide. Especially if the frontend has the
|
||||
decency to ask its "cdrecord" via option -scanbus for a list of drives.
|
||||
If not, look into the error protocol of the frontend, look at the output
|
||||
of a run of cdrskin --devices and give cdrskin the necessary hint.
|
||||
|
||||
If your frontend insists in using "0,0,0" and --devices reported
|
||||
dev='/dev/sg0' resp. cdrskin -scanbus reported "1,0,0" then this
|
||||
would be the appropriate translation
|
||||
|
||||
dev_translation=+0,0,0+/dev/sg0
|
||||
|
||||
The "+" character is a separator to be choosen by you.
|
||||
Currently i am not aware of the need to choose any other than "+"
|
||||
unless you get playful with custom translations like
|
||||
|
||||
dev_translation=-"cd+dvd"-1,0,0
|
||||
|
||||
See http://scdbackup.sourceforge.net/k3b_on_cdrskin.html
|
||||
for an illustrated example with K3b 0.10 .
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
--fifo_start_empty is a throughput enhancer for unsteady data streams
|
||||
like they are produced by a compressing archiver program when piping to
|
||||
CD on-the-fly. It makes better use of the general property of a FIFO
|
||||
@ -177,6 +132,35 @@ 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.
|
||||
|
||||
Normally, cdrskin understands all addresses which are suitable for cdrecord
|
||||
under Linux. See cdrskin/README, "Pseudo-SCSI Adresses".
|
||||
This option is mainly for (yet unknown) exotic configurations or very
|
||||
stubborn frontend programs.
|
||||
|
||||
If a frontend refuses to work with cdrskin, look into the error protocol
|
||||
of that frontend, look at the output of a run of cdrskin --devices and give
|
||||
cdrskin the necessary hint.
|
||||
Example: Your frontend insists in using "0,0,0" and --devices reported
|
||||
dev='/dev/hdc' resp. cdrskin dev=ATA -scanbus reported "1,0,0" then this
|
||||
would be the appropriate translation:
|
||||
|
||||
dev_translation=+0,0,0+/dev/hdc
|
||||
|
||||
The "+" character is a separator to be choosen by you.
|
||||
Currently i am not aware of the need to choose any other than "+"
|
||||
unless you get playful with custom translations like
|
||||
|
||||
dev_translation=-"cd+dvd"-1,0,0
|
||||
|
||||
See http://scdbackup.sourceforge.net/k3b_on_cdrskin.html
|
||||
for an illustrated example with K3b 0.10 .
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
DVD advise:
|
||||
|
||||
For burning of DVD media the cdrskin project currently advises to use
|
||||
|
31
configure.ac
31
configure.ac
@ -1,4 +1,4 @@
|
||||
AC_INIT([libburn], [0.2.2], [http://libburn.pykix.org])
|
||||
AC_INIT([libburn], [0.2.3], [http://libburn.pykix.org])
|
||||
AC_PREREQ([2.50])
|
||||
dnl AC_CONFIG_HEADER([config.h])
|
||||
|
||||
@ -7,6 +7,8 @@ AC_CANONICAL_TARGET
|
||||
|
||||
AM_INIT_AUTOMAKE([subdir-objects])
|
||||
|
||||
AM_CONFIG_HEADER(config.h)
|
||||
|
||||
dnl Making releases:
|
||||
dnl BURN_MICRO_VERSION += 1;
|
||||
dnl BURN_INTERFACE_AGE += 1;
|
||||
@ -19,7 +21,7 @@ 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=1
|
||||
BURN_MICRO_VERSION=3
|
||||
BURN_INTERFACE_AGE=0
|
||||
BURN_BINARY_AGE=0
|
||||
BURN_VERSION=$BURN_MAJOR_VERSION.$BURN_MINOR_VERSION.$BURN_MICRO_VERSION
|
||||
@ -69,10 +71,18 @@ 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)
|
||||
|
||||
TARGET_SHIZZLE
|
||||
AC_SUBST(ARCH)
|
||||
AC_SUBST(LIBBURN_ARCH_LIBS)
|
||||
|
||||
dnl Add compiler-specific flags
|
||||
|
||||
@ -93,23 +103,6 @@ else
|
||||
CFLAGS="$CFLAGS -DDEBUG"
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([if we build the HTML documentation])
|
||||
AC_ARG_ENABLE(docs,
|
||||
[ --enable-docs Use doxygen to build HTML documentation],
|
||||
[case "${enableval}" in
|
||||
yes) build_docs=true ;;
|
||||
no) build_docs=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-docs) ;;
|
||||
esac],[build_docs=false])
|
||||
|
||||
if test "x$build_docs" = "xtrue"; then
|
||||
AC_MSG_RESULT([yes])
|
||||
touch doc/doc.lock
|
||||
else
|
||||
AC_MSG_RESULT([no (use --enable-docs to enable)])
|
||||
rm -f doc/doc.lock
|
||||
fi
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
doc/doxygen.conf
|
||||
|
21
doc/comments
21
doc/comments
@ -92,23 +92,26 @@ stay upward compatible for a good while.
|
||||
<pre>
|
||||
Usage: test/libburner
|
||||
[--drive <address>|<driveno>|"-"]
|
||||
[--verbose <level>] [--blank_fast|--blank_full]
|
||||
[--burn_for_real|--try_to_simulate] [--stdin_size <bytes>]
|
||||
[<imagefile>|"-"]
|
||||
[--blank_fast|--blank_full] [--audio]
|
||||
[--try_to_simulate] [--stdin_size <bytes>]
|
||||
[<one or more imagefiles>|"-"]
|
||||
Examples
|
||||
A bus scan (needs rw-permissions to see a drive):
|
||||
test/libburner --drive -
|
||||
Burn a file to drive chosen by number:
|
||||
test/libburner --drive 0 --burn_for_real my_image_file
|
||||
test/libburner --drive 0 my_image_file
|
||||
Burn a file to drive chosen by persistent address:
|
||||
test/libburner --drive /dev/hdc --burn_for_real my_image_file
|
||||
test/libburner --drive /dev/hdc my_image_file
|
||||
Blank a used CD-RW (is combinable with burning in one run):
|
||||
test/libburner --drive 0 --blank_fast
|
||||
test/libburner --drive /dev/hdc --blank_fast
|
||||
Burn two audio tracks
|
||||
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, pad up to 700 MB:
|
||||
( cd my_directory ; find . -print | afio -oZ - ) | \
|
||||
test/libburner --drive /dev/hdc --burn_for_real --stdin_size 734003200 -
|
||||
To be read from *not mounted* CD via:
|
||||
afio -tvZ /dev/hdc
|
||||
test/libburner --drive /dev/hdc --stdin_size 734003200 -
|
||||
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.
|
||||
</pre>
|
||||
|
||||
|
@ -7,5 +7,6 @@ Name: libburn
|
||||
Description: Disc reading/writing library
|
||||
Version: @VERSION@
|
||||
Requires:
|
||||
Libs: -L${libdir} -lburn @THREAD_LIBS@
|
||||
Libs: -L${libdir} -lburn
|
||||
Libs.private: @THREAD_LIBS@ @LIBBURN_ARCH_LIBS@
|
||||
Cflags: -I${includedir}/libburn
|
||||
|
792
libburn/asserts.txt
Normal file
792
libburn/asserts.txt
Normal file
@ -0,0 +1,792 @@
|
||||
List of assert() calls in libburn. 6 Oct 2006.
|
||||
|
||||
Format:
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Number) grep'ed line
|
||||
(++ before number means: is fully done, + means is done so far )
|
||||
function():
|
||||
Description of abort condition.
|
||||
|
||||
Possible callers and their relation to the abort condition.
|
||||
|
||||
: Error Evaluation
|
||||
=> Consequences
|
||||
|
||||
Eventual implementation timestamp
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 1) libburn/async.c: assert(a != NULL); /* wasn't found.. this should not be possible */
|
||||
static remove_worker():
|
||||
A thread describing structure (struct w_list) could not be found in
|
||||
order to be released.
|
||||
|
||||
Called by API burn_drive_scan()
|
||||
Called by static erase_worker_func() , thread under API burn_disc_erase()
|
||||
Called by static write_disc_worker_func(), thread under API burn_disc_write()
|
||||
All three want to clean up after they are done.
|
||||
|
||||
: Severe Libburn Error
|
||||
=> issue LIBDAX_MSGS_SEV_WARNING
|
||||
|
||||
ts A61006
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 2) libburn/async.c: assert(!(workers && workers->drive));
|
||||
API burn_drive_scan():
|
||||
Before spawning a thread, the function refuses work because another
|
||||
drive activity is going on.
|
||||
|
||||
: Severe Application Error
|
||||
=> return -1; redefine @return in API , issue LIBDAX_MSGS_SEV_SORRY
|
||||
|
||||
ts A61006
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
+ 3) libburn/async.c: assert(workers == NULL);
|
||||
API burn_drive_scan():
|
||||
After thread is done and remover_worker() succeeded, there is still a
|
||||
worker registered. Shall probably detect roguely appeared burn or
|
||||
erase runs. (I consider to install a mutex shielded function for that.)
|
||||
|
||||
: Severe Libburn Error
|
||||
=> Same as 1)
|
||||
|
||||
ts A61006
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 4) libburn/async.c: assert(drive);
|
||||
libburn/async.c: assert(!SCAN_GOING());
|
||||
libburn/async.c: assert(!find_worker(drive));
|
||||
API burn_disc_erase():
|
||||
Wants to see a drive (assumes NULL == 0), wants to see no scan and
|
||||
wants to see no other worker on that drive. I.e. this would tolerate
|
||||
a parallel activity on another drive.
|
||||
|
||||
: Severe Application Error
|
||||
=> (no return value), issue LIBDAX_MSGS_SEV_SORRY
|
||||
|
||||
ts A61006
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 5) libburn/async.c: assert(!SCAN_GOING());
|
||||
libburn/async.c: assert(!find_worker(opts->drive));
|
||||
API burn_disc_write():
|
||||
Same as 4)
|
||||
|
||||
: Severe Application Error
|
||||
=> Same as 4)
|
||||
|
||||
ts A61006
|
||||
|
||||
---------------------------------------------------------------------
|
||||
|
||||
++ 6) libburn/drive.c: assert(d->busy == BURN_DRIVE_IDLE);
|
||||
API burn_drive_release():
|
||||
A drive is not idle on release.
|
||||
|
||||
: Severe Application Error
|
||||
=> Same as 4)
|
||||
|
||||
ts A61007
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 7) libburn/drive.c: assert(d->released);
|
||||
burn_wait_all()
|
||||
A drive is found grabbed.
|
||||
|
||||
Called by burn_drive_scan_sync(), thread under API burn_drive_scan()
|
||||
Called by API burn_finish
|
||||
|
||||
: Severe Application Error
|
||||
=> rename and redefine burn_wait_all() : now burn_drives_are_clear()
|
||||
=> change all use of burn_wait_all()
|
||||
=> Move tests up to burn_drive_scan()
|
||||
=> There: return -1; issue LIBDAX_MSGS_SEV_SORRY
|
||||
|
||||
ts A61007
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 8) libburn/drive.c: assert(!d->released);
|
||||
API burn_disc_get_status()
|
||||
Attempt to read status of non-grabbed drive.
|
||||
|
||||
: Severe Application Error
|
||||
=> extend enum burn_disc_status by BURN_DISC_UNGRABBED
|
||||
=> return BURN_DISC_UNGRABBED, issue LIBDAX_MSGS_SEV_SORRY
|
||||
|
||||
ts A61007
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 9) libburn/drive.c: assert( /* (write_type >= BURN_WRITE_PACKET) && */
|
||||
burn_drive_get_block_types():
|
||||
Will not work on BURN_WRITE below BURN_WRITE_RAW.
|
||||
|
||||
Called by -nobody- ?
|
||||
|
||||
: Severe Application Error
|
||||
=> inactivate unused function
|
||||
|
||||
ts A61007
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 10) libburn/drive.c: assert(d->idata);
|
||||
libburn/drive.c: assert(d->mdata);
|
||||
static drive_getcaps():
|
||||
sg.c:enumerate_common() did not succeed in creating a proper struct burn_drive
|
||||
Called by burn_drive_scan_sync()
|
||||
|
||||
: Severe System Error
|
||||
=> This could possibly really stay an abort() because the reason is
|
||||
a plain failure of the system's memory management.
|
||||
=> Detect this failure already in enumerate_common(),
|
||||
issue LIBDAX_MSGS_SEV_FATAL, return
|
||||
|
||||
ts A61007
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 11) libburn/drive.c: assert(burn_running);
|
||||
burn_drive_scan_sync():
|
||||
The library was not initialized.
|
||||
|
||||
Called as thread by API burn_drive_scan()
|
||||
|
||||
: Severe Application Error
|
||||
=> Move this test up to burn_drive_scan()
|
||||
=> There: return -1; redefine @return in API , issue LIBDAX_MSGS_SEV_FATAL
|
||||
|
||||
ts A61007
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 12) libburn/drive.c: assert(d->released == 1);
|
||||
burn_drive_scan_sync():
|
||||
Inactivated
|
||||
|
||||
: (Severe Application Error)
|
||||
=> throw out inactivated code
|
||||
|
||||
ts A61007
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 13) libburn/drive.c: assert(strlen(d->devname) < BURN_DRIVE_ADR_LEN);
|
||||
burn_drive_raw_get_adr():
|
||||
An enumerated device address is longer than the API's maximum length
|
||||
|
||||
Called by API burn_drive_get_adr()
|
||||
Called by API burn_drive_obtain_scsi_adr()
|
||||
|
||||
: Severe Libburn Error
|
||||
=> return -1; in all three functions, enhance burn_drive_get_adr @return docs
|
||||
=> issue LIBDAX_MSGS_SEV_SORRY
|
||||
|
||||
ts A61007
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 14) libburn/drive.c: assert(drive_info->drive!=NULL);
|
||||
API burn_drive_get_adr():
|
||||
Drive info has no drive attached.
|
||||
|
||||
: Severe Libburn Error (unlikely, will eventually SIGSEGV on NULL)
|
||||
=> delete assert
|
||||
|
||||
ts A61007
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 15) libburn/init.c: assert(burn_running);
|
||||
API burn_finish():
|
||||
The library is not initialized
|
||||
|
||||
: Severe Application Error
|
||||
=> return (assume no msg system)
|
||||
|
||||
ts A61007
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 16) libburn/init.c: assert(burn_running);
|
||||
API burn_preset_device_open():
|
||||
The library is not initialized
|
||||
|
||||
: Severe Application Error
|
||||
=> return (assume no msg system)
|
||||
|
||||
ts A61007
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 17) libburn/mmc.c: assert(o->drive == d);
|
||||
mmc_close_disc():
|
||||
alias: struct burn_drive.close_disc()
|
||||
Parameters struct burn_drive and struct burn_write_opts do not match
|
||||
|
||||
Called by -nobody- ?
|
||||
|
||||
( => Disable unused function ? )
|
||||
=> removed redundant parameter struct burn_drive
|
||||
|
||||
ts A61009
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 18) libburn/mmc.c: assert(o->drive == d);
|
||||
mmc_close_session():
|
||||
Same as 17)
|
||||
alias: struct burn_drive.close_session()
|
||||
|
||||
Called by -nobody- ?
|
||||
|
||||
( => Disable unused function ? )
|
||||
=> removed redundant parameter struct burn_drive
|
||||
|
||||
ts A61009
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 19) libburn/mmc.c: assert(buf->bytes >= buf->sectors); /* can be == at 0... */
|
||||
mmc_write_12():
|
||||
- Unclear what .bytes and .sectors mean in struct buffer -
|
||||
|
||||
Called by -nobody- ?
|
||||
|
||||
=> problems with filling the write buffer have to be handled by callers
|
||||
=> delete assert
|
||||
|
||||
ts A61009
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 20) libburn/mmc.c: assert(buf->bytes >= buf->sectors); /* can be == at 0... */
|
||||
mmc_write():
|
||||
- Unclear what .bytes and .sectors mean in struct buffer -
|
||||
|
||||
libburn/mmc.c: c.page->sectors = errorblock - start + 1;
|
||||
mmc_read_sectors() by toc_find_modes() by mmc_read_toc() alias drive.read_toc()
|
||||
by burn_drive_grab()
|
||||
This seems to be unrelated to mmc_write().
|
||||
|
||||
libburn/sector.c: out->sectors++;
|
||||
get_sector()
|
||||
Seems to hand out sector start pointer in opts->drive->buffer
|
||||
and to count reservation transactions as well as reserved bytes.
|
||||
Ensures out->bytes >= out->sectors
|
||||
|
||||
|
||||
libburn/mmc.c: c.page->bytes = s->count * 8;
|
||||
mmc_send_cue_sheet()
|
||||
Does not use mmc_write() but directly (sg_)issue_command()
|
||||
|
||||
libburn/sector.c: out->bytes += seclen;
|
||||
get_sector()
|
||||
See above
|
||||
Ensures out->bytes >= out->sectors
|
||||
|
||||
libburn/spc.c: c.page->bytes = 8 + 2 + d->mdata->retry_page_length;
|
||||
spc_select_error_params()
|
||||
Does not use mmc_write() but directly (sg_)issue_command()
|
||||
|
||||
libburn/spc.c: c.page->bytes = 8 + 2 + d->mdata->write_page_length;
|
||||
spc_select_error_params()
|
||||
Does not use mmc_write() but directly (sg_)issue_command()
|
||||
|
||||
libburn/spc.c: c.page->bytes = 8 + 2 + 0x32;
|
||||
spc_probe_write_modes()
|
||||
Does not use mmc_write() but directly (sg_)issue_command()
|
||||
|
||||
alias struct burn_drive.write()
|
||||
Called by static get_sector, by many
|
||||
Called by burn_write_flush
|
||||
Called by burn_write_track
|
||||
|
||||
=> problems with filling the write buffer have to be handled by callers
|
||||
=> delete assert
|
||||
|
||||
ts A61009
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 21) libburn/mmc.c: assert(((dlen - 2) % 11) == 0);
|
||||
mmc_read_toc():
|
||||
- Is defunct -
|
||||
|
||||
=> :)
|
||||
|
||||
ts A61009
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 22) libburn/mmc.c: assert(len >= 0);
|
||||
mmc_read_sectors():
|
||||
Catches a bad parameter
|
||||
|
||||
alias: struct burn_drive.read_sectors()
|
||||
Called by API burn_disc_read() , - is defunct -, one could catch the problem
|
||||
Called by toc_find_modes(), problem cannot occur: mem.sectors = 1;
|
||||
|
||||
: Severe Libburn Error
|
||||
(=> in burn_disc_read() check page.sectors before d->read_sectors() )
|
||||
=> :)
|
||||
|
||||
ts A61009
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 23) libburn/mmc.c: assert(d->busy);
|
||||
mmc_read_sectors():
|
||||
Catches use of a drive that is not marked as busy
|
||||
|
||||
alias: struct burn_drive.read_sectors()
|
||||
Called by API burn_disc_read() , - is defunct -, busy = BURN_DRIVE_READING;
|
||||
Called by toc_find_modes(), does the same assert. To be solved there.
|
||||
|
||||
: Severe Libburn Error
|
||||
=> :)
|
||||
|
||||
ts A61009
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 24) libburn/options.c: assert(0);
|
||||
API burn_write_opts_set_write_type():
|
||||
Detects unsuitable enum burn_write_types write_type and int block_type.
|
||||
API promises return 0 on failure
|
||||
|
||||
: Severe Application Error
|
||||
=> issue LIBDAX_MSGS_SEV_SORRY
|
||||
=> should also detect problem of 26) : wrong write_type,block_type combination
|
||||
by calling sector_get_outmode() and checking for -1
|
||||
=> should also detect problem of 41) : unknown block_type
|
||||
by spc_block_type() and checking for -1
|
||||
=> delete assert(0)
|
||||
|
||||
ts A61007
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 25) libburn/read.c: assert((o->version & 0xfffff000) == (OPTIONS_VERSION & 0xfffff000));
|
||||
libburn/read.c: assert(!d->busy);
|
||||
libburn/read.c: assert(d->toc->valid);
|
||||
libburn/read.c: assert(o->datafd != -1);
|
||||
API burn_disc_read():
|
||||
- ? -
|
||||
|
||||
burn_disc_read() is defunct
|
||||
OPTIONS_VERSION does not occur outside this line
|
||||
|
||||
( => one would return )
|
||||
( 22) => catch page.sectors<0 before d->read_sectors() )
|
||||
( 37) => catch ! d->mdata->valid )
|
||||
=> :)
|
||||
|
||||
ts A61007
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 26) libburn/sector.c: assert(0); /* return BURN_MODE_UNIMPLEMENTED :) */
|
||||
static get_outmode():
|
||||
burn_write_opts is wrongly programmed with .write_type and .block_type
|
||||
|
||||
: Severe Application Error
|
||||
=> This gets handled by burn_write_opts_set_write_type()
|
||||
ts A61007 by new semi-public sector_get_outmode()
|
||||
=> delete assert()
|
||||
|
||||
ts A61007
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 27) libburn/sector.c: assert(outlen >= inlen);
|
||||
libburn/sector.c: assert(outmode & BURN_MODE_RAW);
|
||||
libburn/sector.c: assert(offset != -1);
|
||||
static convert_data():
|
||||
Several unacceptable settings within struct burn_write_opts
|
||||
|
||||
Called by sector_toc() sector_pregap() sector_postgap() sector_lout()
|
||||
sector_data()
|
||||
|
||||
: Severe Application Error
|
||||
=> change return type of convert_data()
|
||||
=> all callers interpret return value and eventually return failure
|
||||
|
||||
ts A61007
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 28) libburn/sector.c: assert(0);
|
||||
static char_to_isrc():
|
||||
Called by subcode_user() with data set by API burn_track_set_isrc()
|
||||
Some character conversion fails on wrong input
|
||||
|
||||
: Severe Application Error
|
||||
=> burn_track_set_isrc() has to make sure that only good data are set
|
||||
=> char_to_isrc() returns 0 as default
|
||||
=> delete assert()
|
||||
|
||||
ts A61008
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 29) libburn/sector.c: assert(qmode == 1 || qmode == 2 || qmode == 3);
|
||||
subcode_user():
|
||||
- can not happen -
|
||||
|
||||
: Unknown reason of assert()
|
||||
=> remove assert()
|
||||
|
||||
ts A61010
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 30) libburn/sector.c: assert(modebyte == 1);
|
||||
sector_headers():
|
||||
Does only accept modes BURN_AUDIO, BURN_MODE1 or write_type BURN_WRITE_SAO
|
||||
|
||||
Called by sector_toc() sector_pregap() sector_postgap() sector_lout()
|
||||
sector_data()
|
||||
|
||||
: Severe Libburn Error
|
||||
=> new functions sector_headers_is_ok(), burn_disc_write_is_ok()
|
||||
help to catch problem in API burn_disc_write()
|
||||
=> issue LIBDAX_MSGS_SEV_FATAL
|
||||
|
||||
ts A61009
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 31) libburn/sector.c: assert(0);
|
||||
process_q()
|
||||
- defunct -
|
||||
|
||||
=> :)
|
||||
|
||||
ts A61009
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 32) libburn/sg.c: assert("drive busy" == "non fatal");
|
||||
sg_handle_busy_device():
|
||||
Intentional abort preset by the app
|
||||
|
||||
=> change to abort()
|
||||
|
||||
ts A61007
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 33) libburn/sg.c: assert(fd != -1337);
|
||||
sg_grab():
|
||||
The drive device file could not be opened
|
||||
|
||||
:Severe External Problem
|
||||
=> obsolete by normal drive open failure handling
|
||||
|
||||
ts A61007
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 34) libburn/sg.c: assert(!c->page);
|
||||
sg_issue_command():
|
||||
An SCSI command of direction NO_TRANSFER may not have a .page != NULL.
|
||||
|
||||
Since it is about exposing a libburn detail towards the sg driver, i believe
|
||||
it is sufficient to just not use it.
|
||||
|
||||
: Libburn Error
|
||||
=> enhance internal logics of sg_issue_command()
|
||||
|
||||
ts A61007
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 35) libburn/sg.c: assert(c->page->bytes > 0);
|
||||
sg_issue_command():
|
||||
An SCSI command of direction TO_DRIVE wants to transfer 0 bytes.
|
||||
|
||||
: Severe Libburn Error
|
||||
=> set command.error = 1 and return 0
|
||||
|
||||
ts A61010
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 36) libburn/sg.c: assert(err != -1);
|
||||
sg_issue_command():
|
||||
The transfer of the command via ioctl() failed
|
||||
|
||||
: Severe Transport Level Problem
|
||||
=> close drive fd, set idle and released
|
||||
=> set command.error = 1 and return -1
|
||||
|
||||
ts A61010
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 37) libburn/spc.c: assert(d->mdata->valid);
|
||||
spc_select_error_params():
|
||||
Drive was not properly programmed
|
||||
|
||||
alias struct burn_drive.send_parameters()
|
||||
Called by burn_disc_read, - defunct -
|
||||
|
||||
: Severe Application Error
|
||||
=> moved up as mangled assert to burn_disc_read()
|
||||
|
||||
ts A61007
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 38) libburn/spc.c: assert(d->mdata->cdr_write || d->mdata->cdrw_write ||
|
||||
spc_sense_write_params():
|
||||
Drive does not offer write of any known media type
|
||||
|
||||
alias struct burn_drive.read_disc_info()
|
||||
Called by API burn_drive_grab (assert test made there in soft)
|
||||
|
||||
: Severe Command Level Problem
|
||||
=> remove assert()
|
||||
|
||||
ts A61007
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 39) libburn/spc.c: assert(o->drive == d);
|
||||
spc_select_write_params():
|
||||
Drive does not match struct burn_write_opts
|
||||
|
||||
alias struct burn_drive.send_write_parameters()
|
||||
Called by mmc_close_disc() (-defunct- ?), mmc_close_session() (-defunct- ?),
|
||||
burn_write_track() (d = o->drive;),
|
||||
burn_disc_write_sync() d = (o->drive;)
|
||||
|
||||
: Severe Libburn Error
|
||||
=> remove assert()
|
||||
|
||||
ts A61007
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 40) libburn/spc.c: assert(d->mdata->valid);
|
||||
spc_select_write_params():
|
||||
Drive was not properly programmed
|
||||
|
||||
Called by (see 39)
|
||||
burn_write_track() by burn_write_session() by burn_disc_write_sync()
|
||||
burn_disc_write_sync() indirectly by API burn_disc_write()
|
||||
|
||||
: Severe Libburn Error
|
||||
=> caught in burn_disc_write() now
|
||||
|
||||
ts A61007
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 41) libburn/spc.c: assert(0);
|
||||
spc_block_type():
|
||||
Unknown value with enum burn_block_types
|
||||
|
||||
Called by spc_select_write_params, uses burn_write_opts.block_type,
|
||||
set by API burn_write_opts_set_write_type()
|
||||
|
||||
: Severe Application Error
|
||||
=> catch in API burn_write_opts_set_write_type
|
||||
by calling spc_block_type()
|
||||
=> delete assert
|
||||
|
||||
ts A61007
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 42) libburn/structure.c: assert(!(pos > BURN_POS_END));\
|
||||
macro RESIZE
|
||||
An illegal list index is given by the app.
|
||||
|
||||
( TO->NEW##s obviusly means to append "s" to cpp result of TO->NEW )
|
||||
Used by API burn_session_add_track() and API burn_disc_add_session()
|
||||
|
||||
: Severe Application Error
|
||||
=> replace assert by if-and-return-0
|
||||
|
||||
ts A61008
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 43) libburn/structure.c: assert(s->track != NULL);
|
||||
API burn_session_remove_track()
|
||||
An application supplied pointer is NULL
|
||||
|
||||
: Severe Application Error
|
||||
=> replace by if-and-return-0
|
||||
|
||||
ts A61008
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 44) libburn/structure.c: assert((country[i] >= '0' || country[i] < '9') &&
|
||||
libburn/structure.c: assert((owner[i] >= '0' || owner[i] < '9') &&
|
||||
libburn/structure.c: assert(year <= 99);
|
||||
libburn/structure.c: assert(serial <= 99999);
|
||||
API burn_track_set_isrc():
|
||||
Illegal texts supplied by application.
|
||||
The logical expression is always true !
|
||||
|
||||
: Severe Application Error
|
||||
=> issue LIBDAX_MSGS_SEV_SORRY and return
|
||||
=> delete assert
|
||||
=> delete assert 28) in char_to_isrc()
|
||||
|
||||
ts A61008
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 45) libburn/toc.c: assert(0); /* unhandled! find out ccd's
|
||||
static write_clonecd2():
|
||||
|
||||
- defunct -, - unused -
|
||||
|
||||
=> mangle assert
|
||||
|
||||
ts A61008
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 46) libburn/toc.c: assert(d->busy);
|
||||
toc_find_modes():
|
||||
The drive to work on is not marked busy
|
||||
|
||||
Called by mmc_read_toc() alias read_toc() by ... burn_drive_grab()
|
||||
|
||||
: Severe Libburn Error
|
||||
=> to be prevented on the higher levels
|
||||
=> delete assert
|
||||
|
||||
ts A61008
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 47) libburn/util.c: assert(s);
|
||||
burn_strdup()
|
||||
Abort on NULL string which would elsewise cause a SIGSEGV
|
||||
|
||||
Used once in enumerate_common() with a string that worked with open(2) before
|
||||
|
||||
: Severe Libburn Error
|
||||
=> delete assert
|
||||
|
||||
ts A61008
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 48) libburn/util.c: assert(s);
|
||||
burn_strndup(): - unused -
|
||||
Same as 47
|
||||
|
||||
: Severe Libburn Error
|
||||
=> return NULL
|
||||
=> delete assert
|
||||
|
||||
ts A61008
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 49) libburn/util.c: assert(n > 0);
|
||||
burn_strndup(): - unused -
|
||||
Prevent problems by negative copy length
|
||||
|
||||
: Severe Libburn Error
|
||||
=> return NULL
|
||||
=> delete assert
|
||||
|
||||
ts A61008
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 50) libburn/write.c: assert(0);
|
||||
static type_to_ctrl():
|
||||
Unsuitable mode to be converted into "ctrl"
|
||||
Called by static type_to_form() finally burn_create_toc_entries()
|
||||
|
||||
: Severe Application Error
|
||||
=> to be caught in burn_track_define_data by calling for test type_to_form()
|
||||
=> return -1;
|
||||
|
||||
ts A61008
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 51) libburn/write.c: assert(0);
|
||||
libburn/write.c: assert(0); /* XXX someone's gonna want this sometime */
|
||||
static type_to_form():
|
||||
Does not like BURN_MODE0 or BURN_MODE2 but tolerates unknown modes
|
||||
|
||||
Called by static burn_create_toc_entries() by burn_disc_write_sync()
|
||||
|
||||
: Undocumented Libburn Restriction
|
||||
=> set *form = -1 , *ctladr = 0xff , return
|
||||
=> make function non-static
|
||||
=> call for test in API burn_track_define_data()
|
||||
|
||||
ts A61009
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 52) libburn/write.c: assert(ptr);
|
||||
static add_cue():
|
||||
realloc() failed
|
||||
|
||||
Called by burn_create_toc_entries() by burn_disc_write_sync()
|
||||
(burn_create_toc_entries is ignorant towards own potential memory problems)
|
||||
(This could possibly really stay an abort() because the reason is
|
||||
a plain failure of the system's memory management.)
|
||||
|
||||
: Severe System Error
|
||||
=> change return type of add_cue to int
|
||||
=> react on return -1 in burn_create_toc_entries, return NULL on failure
|
||||
=> abort burn_disc_write_sync() on NULL return
|
||||
|
||||
ts A61009
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 53) libburn/write.c: assert(d->toc_entry == NULL);
|
||||
burn_create_toc_entries():
|
||||
Multiple usage of struct burn_drive.toc_entry
|
||||
|
||||
Called by burn_disc_write_sync()
|
||||
This will probably trigger an abort with disc->sessions > 1
|
||||
(disc->sessions is incremented in macro RESIZE() as "NEW##s")
|
||||
|
||||
: Design Problem
|
||||
( => ? disallow multiple sessions ? )
|
||||
=> replace assert by soft means and wait what happens
|
||||
|
||||
ts A61009
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
++ 54) libburn/write.c: assert(0);
|
||||
burn_sector_length():
|
||||
Only BURN_AUDIO, BURN_MODE_RAW, BURN_MODE1 are allowed
|
||||
|
||||
Called by get_sector(), convert_data(), ...
|
||||
|
||||
=> call burn_sector_length() for test in API burn_track_define_data()
|
||||
=> replace assert by -1
|
||||
|
||||
ts A61009
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
107
libburn/async.c
107
libburn/async.c
@ -6,11 +6,17 @@
|
||||
#include "write.h"
|
||||
#include "options.h"
|
||||
#include "async.h"
|
||||
#include "init.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
#include <a ssert.h>
|
||||
*/
|
||||
#include "libdax_msgs.h"
|
||||
extern struct libdax_msgs *libdax_messenger;
|
||||
|
||||
#define SCAN_GOING() (workers && !workers->drive)
|
||||
|
||||
typedef void *(*WorkerFunc) (void *);
|
||||
@ -100,7 +106,13 @@ static void remove_worker(pthread_t th)
|
||||
free(a);
|
||||
break;
|
||||
}
|
||||
assert(a != NULL); /* wasn't found.. this should not be possible */
|
||||
|
||||
/* ts A61006 */
|
||||
/* a ssert(a != NULL);/ * wasn't found.. this should not be possible */
|
||||
if (a == NULL)
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020101,
|
||||
LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"remove_worker() cannot find given worker item", 0, 0);
|
||||
}
|
||||
|
||||
static void *scan_worker_func(struct w_list *w)
|
||||
@ -115,11 +127,41 @@ int burn_drive_scan(struct burn_drive_info *drives[], unsigned int *n_drives)
|
||||
struct scan_opts o;
|
||||
int ret = 0;
|
||||
|
||||
/* ts A61006 : moved up from burn_drive_scan_sync , former Assert */
|
||||
if (!burn_running) {
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020109,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Library not running (on attempt to scan)", 0, 0);
|
||||
*drives = NULL;
|
||||
*n_drives = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* cant be anything working! */
|
||||
assert(!(workers && workers->drive));
|
||||
|
||||
/* ts A61006 */
|
||||
/* a ssert(!(workers && workers->drive)); */
|
||||
if (workers != NULL && workers->drive != NULL) {
|
||||
drive_is_active:;
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020102,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"A drive operation is still going on (want to scan)",
|
||||
0, 0);
|
||||
*drives = NULL;
|
||||
*n_drives = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!workers) {
|
||||
/* start it */
|
||||
|
||||
/* ts A61007 : test moved up from burn_drive_scan_sync()
|
||||
was burn_wait_all() */
|
||||
if (!burn_drives_are_clear())
|
||||
goto drive_is_active;
|
||||
*drives = NULL;
|
||||
*n_drives = 0;
|
||||
|
||||
o.drives = drives;
|
||||
o.n_drives = n_drives;
|
||||
o.done = 0;
|
||||
@ -128,7 +170,17 @@ int burn_drive_scan(struct burn_drive_info *drives[], unsigned int *n_drives)
|
||||
/* its done */
|
||||
ret = workers->u.scan.done;
|
||||
remove_worker(workers->thread);
|
||||
assert(workers == NULL);
|
||||
|
||||
/* ts A61006 */
|
||||
/* a ssert(workers == NULL); */
|
||||
if (workers != NULL) {
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020101,
|
||||
LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"After scan a drive operation is still going on",
|
||||
0, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* still going */
|
||||
}
|
||||
@ -146,9 +198,25 @@ void burn_disc_erase(struct burn_drive *drive, int fast)
|
||||
{
|
||||
struct erase_opts o;
|
||||
|
||||
assert(drive);
|
||||
assert(!SCAN_GOING());
|
||||
assert(!find_worker(drive));
|
||||
/* ts A61006 */
|
||||
/* a ssert(drive); */
|
||||
/* a ssert(!SCAN_GOING()); */
|
||||
/* a ssert(!find_worker(drive)); */
|
||||
if((drive == NULL)) {
|
||||
libdax_msgs_submit(libdax_messenger, drive->global_index,
|
||||
0x00020104,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"NULL pointer caught in burn_disc_erase", 0, 0);
|
||||
return;
|
||||
}
|
||||
if ((SCAN_GOING()) || find_worker(drive)) {
|
||||
libdax_msgs_submit(libdax_messenger, drive->global_index,
|
||||
0x00020102,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"A drive operation is still going on (want to erase)",
|
||||
0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
o.drive = drive;
|
||||
o.fast = fast;
|
||||
@ -171,8 +239,29 @@ void burn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc)
|
||||
{
|
||||
struct write_opts o;
|
||||
|
||||
assert(!SCAN_GOING());
|
||||
assert(!find_worker(opts->drive));
|
||||
/* ts A61006 */
|
||||
/* a ssert(!SCAN_GOING()); */
|
||||
/* a ssert(!find_worker(opts->drive)); */
|
||||
if ((SCAN_GOING()) || find_worker(opts->drive)) {
|
||||
libdax_msgs_submit(libdax_messenger, opts->drive->global_index,
|
||||
0x00020102,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"A drive operation is still going on (want to write)",
|
||||
0, 0);
|
||||
return;
|
||||
}
|
||||
/* ts A61007 : obsolete Assert in spc_select_write_params() */
|
||||
if (!opts->drive->mdata->valid) {
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
opts->drive->global_index, 0x00020113,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"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 */
|
||||
return;
|
||||
|
||||
o.drive = opts->drive;
|
||||
o.opts = opts;
|
||||
o.disc = disc;
|
||||
|
214
libburn/cleanup.c
Normal file
214
libburn/cleanup.c
Normal file
@ -0,0 +1,214 @@
|
||||
/*
|
||||
cleanup.c , Copyright 2006 Thomas Schmitt <scdbackup@gmx.net>
|
||||
|
||||
A signal handler which cleans up an application and exits.
|
||||
|
||||
Provided under GPL license within GPL projects, BSD license elsewise.
|
||||
*/
|
||||
|
||||
/*
|
||||
cc -g -o cleanup -DCleanup_standalonE cleanup.c
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <signal.h>
|
||||
typedef void (*sighandler_t)(int);
|
||||
|
||||
|
||||
#include "cleanup.h"
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
|
||||
/* Signals to be caught */
|
||||
static int signal_list[]= {
|
||||
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT,
|
||||
SIGFPE, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM,
|
||||
SIGUSR1, SIGUSR2, SIGXCPU, SIGTSTP, SIGTTIN,
|
||||
SIGTTOU,
|
||||
SIGBUS, SIGPROF, SIGSYS, SIGTRAP,
|
||||
SIGVTALRM, SIGXCPU, SIGXFSZ, -1
|
||||
};
|
||||
static char *signal_name_list[]= {
|
||||
"SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGABRT",
|
||||
"SIGFPE", "SIGSEGV", "SIGPIPE", "SIGALRM", "SIGTERM",
|
||||
"SIGUSR1", "SIGUSR2", "SIGXCPU", "SIGTSTP", "SIGTTIN",
|
||||
"SIGTTOU",
|
||||
"SIGBUS", "SIGPROF", "SIGSYS", "SIGTRAP",
|
||||
"SIGVTALRM", "SIGXCPU", "SIGXFSZ", "@"
|
||||
};
|
||||
static int signal_list_count= 23;
|
||||
|
||||
#else /* __FreeBSD__ */
|
||||
|
||||
/* Signals to be caught */
|
||||
static int signal_list[]= {
|
||||
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT,
|
||||
SIGFPE, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM,
|
||||
SIGUSR1, SIGUSR2, SIGXCPU, SIGTSTP, SIGTTIN,
|
||||
SIGTTOU,
|
||||
SIGBUS, SIGPOLL, SIGPROF, SIGSYS, SIGTRAP,
|
||||
SIGVTALRM, SIGXCPU, SIGXFSZ, -1
|
||||
};
|
||||
static char *signal_name_list[]= {
|
||||
"SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGABRT",
|
||||
"SIGFPE", "SIGSEGV", "SIGPIPE", "SIGALRM", "SIGTERM",
|
||||
"SIGUSR1", "SIGUSR2", "SIGXCPU", "SIGTSTP", "SIGTTIN",
|
||||
"SIGTTOU",
|
||||
"SIGBUS", "SIGPOLL", "SIGPROF", "SIGSYS", "SIGTRAP",
|
||||
"SIGVTALRM", "SIGXCPU", "SIGXFSZ", "@"
|
||||
};
|
||||
static int signal_list_count= 24;
|
||||
|
||||
#endif /* ! __FreeBSD__ */
|
||||
|
||||
/* Signals not to be caught */
|
||||
static int non_signal_list[]= {
|
||||
SIGKILL, SIGCHLD, SIGSTOP, SIGURG, -1
|
||||
};
|
||||
static int non_signal_list_count= 4;
|
||||
|
||||
|
||||
/* run time dynamic part */
|
||||
static char cleanup_msg[4096]= {""};
|
||||
static int cleanup_exiting= 0;
|
||||
|
||||
static void *cleanup_app_handle= NULL;
|
||||
static Cleanup_app_handler_T cleanup_app_handler= NULL;
|
||||
static int cleanup_perform_app_handler_first= 0;
|
||||
|
||||
|
||||
static int Cleanup_handler_exit(int exit_value, int signum, int flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if(cleanup_msg[0]!=0)
|
||||
fprintf(stderr,"\n%s\n",cleanup_msg);
|
||||
if(cleanup_perform_app_handler_first)
|
||||
if(cleanup_app_handler!=NULL) {
|
||||
ret= (*cleanup_app_handler)(cleanup_app_handle,signum,0);
|
||||
if(ret==2 || ret==-2)
|
||||
return(2);
|
||||
}
|
||||
if(cleanup_exiting) {
|
||||
fprintf(stderr,"cleanup: ABORT : repeat by pid=%d, signum=%d\n",
|
||||
getpid(),signum);
|
||||
return(0);
|
||||
}
|
||||
cleanup_exiting= 1;
|
||||
alarm(0);
|
||||
if(!cleanup_perform_app_handler_first)
|
||||
if(cleanup_app_handler!=NULL) {
|
||||
ret= (*cleanup_app_handler)(cleanup_app_handle,signum,0);
|
||||
if(ret==2 || ret==-2)
|
||||
return(2);
|
||||
}
|
||||
exit(exit_value);
|
||||
}
|
||||
|
||||
|
||||
static void Cleanup_handler_generic(int signum)
|
||||
{
|
||||
int i;
|
||||
|
||||
sprintf(cleanup_msg,"UNIX-SIGNAL caught: %d errno= %d",signum,errno);
|
||||
for(i= 0; i<signal_list_count; i++)
|
||||
if(signum==signal_list[i]) {
|
||||
sprintf(cleanup_msg,"UNIX-SIGNAL: %s errno= %d",
|
||||
signal_name_list[i],errno);
|
||||
break;
|
||||
}
|
||||
Cleanup_handler_exit(1,signum,0);
|
||||
}
|
||||
|
||||
|
||||
int Cleanup_set_handlers(void *handle, Cleanup_app_handler_T handler, int flag)
|
||||
/*
|
||||
bit0= set to default handlers
|
||||
bit1= set to ignore
|
||||
bit2= set cleanup_perform_app_handler_first
|
||||
bit3= set SIGABRT to handler (makes sense with bits 0 or 1)
|
||||
*/
|
||||
{
|
||||
int i,j,max_sig= -1,min_sig= 0x7fffffff;
|
||||
sighandler_t sig_handler;
|
||||
|
||||
cleanup_msg[0]= 0;
|
||||
cleanup_app_handle= handle;
|
||||
cleanup_app_handler= handler;
|
||||
|
||||
/* <<< make cleanup_exiting thread safe to get rid of this */
|
||||
if(flag&4)
|
||||
cleanup_perform_app_handler_first= 1;
|
||||
|
||||
|
||||
if(flag&1)
|
||||
sig_handler= SIG_DFL;
|
||||
else if(flag&2)
|
||||
sig_handler= SIG_IGN;
|
||||
else
|
||||
sig_handler= Cleanup_handler_generic;
|
||||
/* set all signal numbers between the lowest and highest in the list
|
||||
except those in the non-signal list */
|
||||
for(i= 0; i<signal_list_count; i++) {
|
||||
if(signal_list[i]>max_sig)
|
||||
max_sig= signal_list[i];
|
||||
if(signal_list[i]<min_sig)
|
||||
min_sig= signal_list[i];
|
||||
}
|
||||
for(i= min_sig; i<=max_sig; i++) {
|
||||
for(j= 0; j<non_signal_list_count; j++)
|
||||
if(i==non_signal_list[j])
|
||||
break;
|
||||
if(j>=non_signal_list_count) {
|
||||
if(i==SIGABRT && (flag&8))
|
||||
signal(i,Cleanup_handler_generic);
|
||||
else
|
||||
signal(i,sig_handler);
|
||||
}
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
#ifdef Cleanup_standalonE
|
||||
|
||||
struct Demo_apP {
|
||||
char *msg;
|
||||
};
|
||||
|
||||
|
||||
int Demo_app_handler(struct Demo_apP *demoapp, int signum, int flag)
|
||||
{
|
||||
printf("Handling exit of demo application on signal %d. msg=\"%s\"\n",
|
||||
signum,demoapp->msg);
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
main()
|
||||
{
|
||||
struct Demo_apP demoapp;
|
||||
|
||||
demoapp.msg= "Good Bye";
|
||||
Cleanup_set_handlers(&demoapp,(Cleanup_app_handler_T) Demo_app_handler,0);
|
||||
|
||||
if(1) { /* change to 0 in order to wait for external signals */
|
||||
char *cpt= NULL,c;
|
||||
printf("Intentionally provoking SIGSEGV ...\n");
|
||||
c= *cpt;
|
||||
} else {
|
||||
printf("killme: %d\n",getpid());
|
||||
sleep(3600);
|
||||
}
|
||||
|
||||
Cleanup_set_handlers(NULL,NULL,1);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#endif /* Cleanup_standalonE */
|
34
libburn/cleanup.h
Normal file
34
libburn/cleanup.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
cleanup.c , Copyright 2006 Thomas Schmitt <scdbackup@gmx.net>
|
||||
|
||||
A signal handler which cleans up an application and exits.
|
||||
|
||||
Provided under GPL license within GPL projects, BSD license elsewise.
|
||||
*/
|
||||
|
||||
#ifndef Cleanup_includeD
|
||||
#define Cleanup_includeD 1
|
||||
|
||||
|
||||
/** Layout of an application provided cleanup function using an application
|
||||
provided handle as first argument and the signal number as second
|
||||
argument. The third argument is a flag bit field with no defined bits yet.
|
||||
If the handler returns 2 or -2 then it has delegated exit() to some other
|
||||
instance and the Cleanup handler shall return rather than exit.
|
||||
*/
|
||||
typedef int (*Cleanup_app_handler_T)(void *, int, int);
|
||||
|
||||
|
||||
/** Establish exiting signal handlers on (hopefully) all signals that are
|
||||
not ignored by default or non-catchable.
|
||||
@param handle Opaque object which knows how to cleanup application
|
||||
@param handler Function which uses handle to perform application cleanup
|
||||
@param flag Control Bitfield
|
||||
bit0= reset to default signal handling
|
||||
*/
|
||||
int Cleanup_set_handlers(void *handle, Cleanup_app_handler_T handler,
|
||||
int flag);
|
||||
|
||||
|
||||
#endif /* ! Cleanup_includeD */
|
||||
|
655
libburn/drive.c
655
libburn/drive.c
@ -1,9 +1,17 @@
|
||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
|
||||
#include <malloc.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/* #include <m alloc.h> ts A61013 : not in Linux man 3 malloc */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* ts A61007 */
|
||||
/* #include <a ssert.h> */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
@ -11,7 +19,6 @@
|
||||
#include "libburn.h"
|
||||
#include "drive.h"
|
||||
#include "transport.h"
|
||||
#include "message.h"
|
||||
#include "debug.h"
|
||||
#include "init.h"
|
||||
#include "toc.h"
|
||||
@ -20,10 +27,22 @@
|
||||
#include "structure.h"
|
||||
#include "back_hacks.h"
|
||||
|
||||
#include "libdax_msgs.h"
|
||||
extern struct libdax_msgs *libdax_messenger;
|
||||
|
||||
static struct burn_drive drive_array[255];
|
||||
static int drivetop = -1;
|
||||
|
||||
int burn_drive_is_open(struct burn_drive *d);
|
||||
/* ts A61021 : the unspecific part of sg.c:enumerate_common()
|
||||
*/
|
||||
int burn_setup_drive(struct burn_drive *d, char *fname)
|
||||
{
|
||||
d->devname = burn_strdup(fname);
|
||||
memset(&d->params, 0, sizeof(struct params));
|
||||
d->released = 1;
|
||||
d->status = BURN_DISC_UNREADY;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ts A60904 : ticket 62, contribution by elmom */
|
||||
/* splitting former burn_drive_free() (which freed all, into two calls) */
|
||||
@ -33,10 +52,11 @@ void burn_drive_free(struct burn_drive *d)
|
||||
return;
|
||||
/* ts A60822 : close open fds before forgetting them */
|
||||
if (burn_drive_is_open(d))
|
||||
close(d->fd);
|
||||
sg_close_drive(d);
|
||||
free((void *) d->idata);
|
||||
free((void *) d->mdata);
|
||||
free((void *) d->toc_entry);
|
||||
if(d->toc_entry != NULL)
|
||||
free((void *) d->toc_entry);
|
||||
free(d->devname);
|
||||
d->global_index = -1;
|
||||
}
|
||||
@ -55,12 +75,8 @@ void burn_drive_free_all(void)
|
||||
/* ts A60822 */
|
||||
int burn_drive_is_open(struct burn_drive *d)
|
||||
{
|
||||
/* a bit more detailed case distinction than needed */
|
||||
if (d->fd == -1337)
|
||||
return 0;
|
||||
if (d->fd < 0)
|
||||
return 0;
|
||||
return 1;
|
||||
/* ts A61021 : moved decision to sg.c */
|
||||
return d->drive_is_open(d);
|
||||
}
|
||||
|
||||
|
||||
@ -144,7 +160,10 @@ int burn_drive_grab(struct burn_drive *d, int le)
|
||||
d->load(d);
|
||||
|
||||
d->lock(d);
|
||||
d->status = BURN_DISC_BLANK;
|
||||
|
||||
/* ts A61020 : this was BURN_DISC_BLANK as pure guess */
|
||||
d->status = BURN_DISC_UNREADY;
|
||||
|
||||
if (d->mdata->cdr_write || d->mdata->cdrw_write ||
|
||||
d->mdata->dvdr_write || d->mdata->dvdram_write) {
|
||||
|
||||
@ -168,6 +187,8 @@ int burn_drive_grab(struct burn_drive *d, int le)
|
||||
old_erasable = new_erasable;
|
||||
|
||||
d->read_disc_info(d);
|
||||
if(d->status == BURN_DISC_UNSUITABLE)
|
||||
break;
|
||||
|
||||
new_speed = burn_drive_get_write_speed(d);
|
||||
new_erasable = burn_disc_erasable(d);
|
||||
@ -244,13 +265,77 @@ struct burn_drive *burn_drive_register(struct burn_drive *d)
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* unregister most recently registered drive */
|
||||
int burn_drive_unregister(struct burn_drive *d)
|
||||
{
|
||||
if(d->global_index != drivetop)
|
||||
return 0;
|
||||
burn_drive_free(d);
|
||||
drivetop--;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ts A61021 : after-setup activities from sg.c:enumerate_common()
|
||||
*/
|
||||
struct burn_drive *burn_drive_finish_enum(struct burn_drive *d)
|
||||
{
|
||||
struct burn_drive *t;
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
int mmc_function_spy(char * text);
|
||||
|
||||
t = burn_drive_register(d);
|
||||
|
||||
/* ts A60821 */
|
||||
mmc_function_spy("enumerate_common : -------- doing grab");
|
||||
|
||||
/* try to get the drive info */
|
||||
if (t->grab(t)) {
|
||||
burn_print(2, "getting drive info\n");
|
||||
t->getcaps(t);
|
||||
t->unlock(t);
|
||||
t->released = 1;
|
||||
} else {
|
||||
burn_print(2, "unable to grab new located drive\n");
|
||||
burn_drive_unregister(t);
|
||||
t = NULL;
|
||||
}
|
||||
|
||||
/* ts A60821 */
|
||||
mmc_function_spy("enumerate_common : ----- would release ");
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
void burn_drive_release(struct burn_drive *d, int le)
|
||||
{
|
||||
if (d->released)
|
||||
burn_print(1, "second release on drive!\n");
|
||||
if (d->released) {
|
||||
/* ts A61007 */
|
||||
/* burn_print(1, "second release on drive!\n"); */
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
d->global_index, 0x00020105,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Drive is already released", 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ts A61007 */
|
||||
/* ts A60906: one should not assume BURN_DRIVE_IDLE == 0 */
|
||||
assert(d->busy == BURN_DRIVE_IDLE);
|
||||
/* a ssert(d->busy == BURN_DRIVE_IDLE); */
|
||||
if (d->busy != BURN_DRIVE_IDLE) {
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
d->global_index, 0x00020106,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Drive is busy on attempt to close", 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ts A61020 : mark media info as invalid */
|
||||
d->start_lba= -2000000000;
|
||||
d->end_lba= -2000000000;
|
||||
|
||||
d->unlock(d);
|
||||
if (le)
|
||||
@ -260,7 +345,7 @@ void burn_drive_release(struct burn_drive *d, int le)
|
||||
|
||||
d->status = BURN_DISC_UNREADY;
|
||||
d->released = 1;
|
||||
if (d->toc_entry)
|
||||
if (d->toc_entry != NULL)
|
||||
free(d->toc_entry);
|
||||
d->toc_entry = NULL;
|
||||
d->toc_entries = 0;
|
||||
@ -270,6 +355,26 @@ void burn_drive_release(struct burn_drive *d, int le)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ts A61007 : former void burn_wait_all() */
|
||||
int burn_drives_are_clear(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = burn_drive_count() - 1; i >= 0; --i) {
|
||||
/* ts A60904 : ticket 62, contribution by elmom */
|
||||
if (drive_array[i].global_index == -1)
|
||||
continue;
|
||||
if (drive_array[i].released)
|
||||
continue;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
void burn_wait_all(void)
|
||||
{
|
||||
unsigned int i;
|
||||
@ -285,16 +390,20 @@ void burn_wait_all(void)
|
||||
if (d->global_index==-1)
|
||||
continue;
|
||||
|
||||
assert(d->released);
|
||||
a ssert(d->released);
|
||||
}
|
||||
if (!finished)
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void burn_disc_erase_sync(struct burn_drive *d, int fast)
|
||||
{
|
||||
/* ts A60924 : libburn/message.c gets obsoleted
|
||||
burn_message_clear_queue();
|
||||
*/
|
||||
|
||||
burn_print(1, "erasing drive %s %s\n", d->idata->vendor,
|
||||
d->idata->product);
|
||||
@ -320,8 +429,8 @@ void burn_disc_erase_sync(struct burn_drive *d, int fast)
|
||||
/* read the initial 0 stage */
|
||||
while (!d->test_unit_ready(d) && d->get_erase_progress(d) == 0)
|
||||
sleep(1);
|
||||
while (!d->test_unit_ready(d) &&
|
||||
(d->progress.sector = d->get_erase_progress(d)) > 0)
|
||||
while ((d->progress.sector = d->get_erase_progress(d)) > 0 ||
|
||||
!d->test_unit_ready(d))
|
||||
sleep(1);
|
||||
d->progress.sector = 0x10000;
|
||||
d->busy = BURN_DRIVE_IDLE;
|
||||
@ -329,7 +438,17 @@ void burn_disc_erase_sync(struct burn_drive *d, int fast)
|
||||
|
||||
enum burn_disc_status burn_disc_get_status(struct burn_drive *d)
|
||||
{
|
||||
assert(!d->released);
|
||||
/* ts A61007 */
|
||||
/* a ssert(!d->released); */
|
||||
if (d->released) {
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
d->global_index, 0x00020108,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Drive is not grabbed on disc status inquiry",
|
||||
0, 0);
|
||||
return BURN_DISC_UNGRABBED;
|
||||
}
|
||||
|
||||
return d->status;
|
||||
}
|
||||
|
||||
@ -354,14 +473,17 @@ void burn_drive_cancel(struct burn_drive *d)
|
||||
pthread_mutex_unlock(&d->access_lock);
|
||||
}
|
||||
|
||||
/* ts A61007 : defunct because unused */
|
||||
#if 0
|
||||
int burn_drive_get_block_types(struct burn_drive *d,
|
||||
enum burn_write_types write_type)
|
||||
{
|
||||
burn_print(12, "write type: %d\n", write_type);
|
||||
assert( /* (write_type >= BURN_WRITE_PACKET) && */
|
||||
a ssert( /* (write_type >= BURN_WRITE_PACKET) && */
|
||||
(write_type <= BURN_WRITE_RAW));
|
||||
return d->block_types[write_type];
|
||||
}
|
||||
#endif
|
||||
|
||||
static void strip_spaces(char *str)
|
||||
{
|
||||
@ -386,14 +508,18 @@ static void strip_spaces(char *str)
|
||||
|
||||
static int drive_getcaps(struct burn_drive *d, struct burn_drive_info *out)
|
||||
{
|
||||
struct scsi_inquiry_data *id;
|
||||
struct burn_scsi_inquiry_data *id;
|
||||
|
||||
/* ts A61007 : now prevented in enumerate_common() */
|
||||
#if 0
|
||||
a ssert(d->idata);
|
||||
a ssert(d->mdata);
|
||||
#endif
|
||||
|
||||
assert(d->idata);
|
||||
assert(d->mdata);
|
||||
if (!d->idata->valid || !d->mdata->valid)
|
||||
return 0;
|
||||
|
||||
id = (struct scsi_inquiry_data *)d->idata;
|
||||
id = (struct burn_scsi_inquiry_data *)d->idata;
|
||||
|
||||
memcpy(out->vendor, id->vendor, sizeof(id->vendor));
|
||||
strip_spaces(out->vendor);
|
||||
@ -435,27 +561,21 @@ int burn_drive_scan_sync(struct burn_drive_info *drives[],
|
||||
static int scanning = 0, scanned = 0, found = 0;
|
||||
static unsigned num_scanned = 0, count = 0;
|
||||
unsigned int i;
|
||||
#ifdef Libburn_ticket_62_enable_redundant_asserT
|
||||
struct burn_drive *d;
|
||||
#endif
|
||||
|
||||
assert(burn_running);
|
||||
/* ts A61007 : moved up to burn_drive_scan() */
|
||||
/* a ssert(burn_running); */
|
||||
|
||||
if (!scanning) {
|
||||
scanning = 1;
|
||||
|
||||
/* ts A61007 : test moved up to burn_drive_scan()
|
||||
burn_wait_all() is obsoleted */
|
||||
#if 0
|
||||
/* make sure the drives aren't in use */
|
||||
burn_wait_all(); /* make sure the queue cleans up
|
||||
before checking for the released
|
||||
state */
|
||||
|
||||
/* ts A60904 : ticket 62, contribution by elmom */
|
||||
/* this is redundant with what is done in burn_wait_all() */
|
||||
#ifdef Libburn_ticket_62_enable_redundant_asserT
|
||||
d = drive_array;
|
||||
count = burn_drive_count();
|
||||
for (i = 0; i < count; ++i, ++d)
|
||||
assert(d->released == 1);
|
||||
#endif /* Libburn_ticket_62_enable_redundant_asserT */
|
||||
#endif /* 0 */
|
||||
|
||||
/* refresh the lib's drives */
|
||||
sg_enumerate();
|
||||
@ -501,19 +621,17 @@ void burn_drive_info_free(struct burn_drive_info drive_infos[])
|
||||
burn_drive_info is not the manager of burn_drive but only its
|
||||
spokesperson. To my knowlege drive_infos from burn_drive_scan()
|
||||
are not memorized globally. */
|
||||
if(drive_infos != NULL) /* and this NULL test is deadly necessary */
|
||||
if(drive_infos != NULL)
|
||||
free((void *) drive_infos);
|
||||
|
||||
burn_drive_free_all();
|
||||
}
|
||||
|
||||
/* Experimental API call */
|
||||
int burn_drive_info_forget(struct burn_drive_info *info, int force)
|
||||
/* ts A61001 : internal call */
|
||||
int burn_drive_forget(struct burn_drive *d, int force)
|
||||
{
|
||||
int occup;
|
||||
struct burn_drive *d;
|
||||
|
||||
d = info->drive;
|
||||
occup = burn_drive_is_occupied(d);
|
||||
/*
|
||||
fprintf(stderr, "libburn: experimental: occup == %d\n",occup);
|
||||
@ -536,8 +654,18 @@ int burn_drive_info_forget(struct burn_drive_info *info, int force)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* API call */
|
||||
int burn_drive_info_forget(struct burn_drive_info *info, int force)
|
||||
{
|
||||
return burn_drive_forget(info->drive, force);
|
||||
}
|
||||
|
||||
struct burn_disc *burn_drive_get_disc(struct burn_drive *d)
|
||||
{
|
||||
/* ts A61022: SIGSEGV on calling this function with blank media */
|
||||
if(d->disc == NULL)
|
||||
return NULL;
|
||||
|
||||
d->disc->refcnt++;
|
||||
return d->disc;
|
||||
}
|
||||
@ -569,6 +697,12 @@ int burn_drive_get_write_speed(struct burn_drive *d)
|
||||
return d->mdata->max_write_speed;
|
||||
}
|
||||
|
||||
/* ts A61021 : New API function */
|
||||
int burn_drive_get_min_write_speed(struct burn_drive *d)
|
||||
{
|
||||
return d->mdata->min_write_speed;
|
||||
}
|
||||
|
||||
|
||||
/* ts A51221 */
|
||||
static char *enumeration_whitelist[BURN_DRIVE_WHITELIST_LEN];
|
||||
@ -627,39 +761,434 @@ int burn_drive_scan_and_grab(struct burn_drive_info *drive_infos[], char* adr,
|
||||
fprintf(stderr,"libburn: experimental: burn_drive_scan_and_grab(%s)\n",
|
||||
adr);
|
||||
*/
|
||||
while (!burn_drive_scan(drive_infos, &n_drives))
|
||||
while (1) {
|
||||
ret = burn_drive_scan(drive_infos, &n_drives);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
if (ret > 0)
|
||||
break;
|
||||
usleep(1002);
|
||||
}
|
||||
if (n_drives <= 0)
|
||||
return 0;
|
||||
/*
|
||||
fprintf(stderr, "libburn: experimental: n_drives == %d\n",n_drives);
|
||||
*/
|
||||
|
||||
/* ts A60908 : seems we get rid of this :) */
|
||||
#ifdef Libburn_grab_release_and_grab_agaiN
|
||||
if (load) {
|
||||
/* RIP-14.5 + LITE-ON 48125S produce a false status
|
||||
if tray was unloaded */
|
||||
/* Therefore the first grab is just for loading */
|
||||
ret= burn_drive_grab(drive_infos[0]->drive, 1);
|
||||
if (ret != 1)
|
||||
return -1;
|
||||
burn_drive_release(drive_infos[0]->drive,0);
|
||||
}
|
||||
#endif /* Libburn_grab_release_and_grab_agaiN */
|
||||
|
||||
ret = burn_drive_grab(drive_infos[0]->drive, load);
|
||||
if (ret != 1)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ts A60823 */
|
||||
/** Inquire the persistent address of the given drive. */
|
||||
int burn_drive_get_adr(struct burn_drive_info *drive_info, char adr[])
|
||||
/* ts A60925 */
|
||||
/** Simple debug message frontend to libdax_msgs_submit().
|
||||
If arg is not NULL, then fmt MUST contain exactly one %s and no
|
||||
other sprintf() %-formatters.
|
||||
*/
|
||||
int burn_drive_adr_debug_msg(char *fmt, char *arg)
|
||||
{
|
||||
assert(strlen(drive_info->location) < BURN_DRIVE_ADR_LEN);
|
||||
strcpy(adr,drive_info->location);
|
||||
int ret;
|
||||
char msg[4096], *msgpt;
|
||||
|
||||
msgpt= msg;
|
||||
if(arg != NULL)
|
||||
sprintf(msg, fmt, arg);
|
||||
else
|
||||
msgpt= fmt;
|
||||
if(libdax_messenger == NULL)
|
||||
return 0;
|
||||
ret = libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
|
||||
msgpt, 0, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ts A60923 */
|
||||
/** Inquire the persistent address of the given drive. */
|
||||
int burn_drive_raw_get_adr(struct burn_drive *d, char adr[])
|
||||
{
|
||||
if (strlen(d->devname) >= BURN_DRIVE_ADR_LEN) {
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020110,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Persistent drive address too long", 0, 0);
|
||||
return -1;
|
||||
}
|
||||
strcpy(adr,d->devname);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ts A60823 - A60923 */
|
||||
/** Inquire the persistent address of the given drive. */
|
||||
int burn_drive_get_adr(struct burn_drive_info *drive_info, char adr[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = burn_drive_raw_get_adr(drive_info->drive, adr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* ts A60922 ticket 33 */
|
||||
/** Evaluate wether the given address would be enumerated by libburn */
|
||||
int burn_drive_is_enumerable_adr(char *adr)
|
||||
{
|
||||
return sg_is_enumerable_adr(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;
|
||||
char link_target[4096], msg[4096+100], link_adr[4096], *adrpt;
|
||||
|
||||
burn_drive_adr_debug_msg("burn_drive_resolve_link( %s )", path);
|
||||
if (*recursion_count >= BURN_DRIVE_MAX_LINK_DEPTH) {
|
||||
burn_drive_adr_debug_msg(
|
||||
"burn_drive_resolve_link aborts because link too deep",
|
||||
NULL);
|
||||
return 0;
|
||||
}
|
||||
(*recursion_count)++;
|
||||
ret = readlink(path, link_target, sizeof(link_target));
|
||||
if (ret == -1) {
|
||||
burn_drive_adr_debug_msg("readlink( %s ) returns -1", path);
|
||||
return 0;
|
||||
}
|
||||
if (ret >= sizeof(link_target) - 1) {
|
||||
sprintf(msg,"readlink( %s ) returns %d (too much)", path, ret);
|
||||
burn_drive_adr_debug_msg(msg, NULL);
|
||||
return -1;
|
||||
}
|
||||
link_target[ret] = 0;
|
||||
adrpt= link_target;
|
||||
if (link_target[0] != '/') {
|
||||
strcpy(link_adr, path);
|
||||
if ((adrpt = strrchr(link_adr, '/')) != NULL) {
|
||||
strcpy(adrpt + 1, link_target);
|
||||
adrpt = link_adr;
|
||||
} else
|
||||
adrpt = link_target;
|
||||
}
|
||||
ret = burn_drive_convert_fs_adr_sub(adrpt, adr, recursion_count);
|
||||
sprintf(msg,"burn_drive_convert_fs_adr( %s ) returns %d",
|
||||
link_target, ret);
|
||||
burn_drive_adr_debug_msg(msg, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ts A60922 - A61014 ticket 33 */
|
||||
/* Try to find an enumerated address with the given stat.st_rdev number */
|
||||
int burn_drive_find_devno(dev_t devno, char adr[])
|
||||
{
|
||||
char fname[4096], msg[4096+100];
|
||||
int ret = 0, first = 1;
|
||||
struct stat stbuf;
|
||||
burn_drive_enumerator_t enm;
|
||||
|
||||
while (1) {
|
||||
ret = sg_give_next_adr(&enm, fname, sizeof(fname), first);
|
||||
if(ret <= 0)
|
||||
break;
|
||||
first = 0;
|
||||
ret = stat(fname, &stbuf);
|
||||
if(ret == -1)
|
||||
continue;
|
||||
if(devno != stbuf.st_rdev)
|
||||
continue;
|
||||
if(strlen(fname) >= BURN_DRIVE_ADR_LEN)
|
||||
return -1;
|
||||
|
||||
sprintf(msg, "burn_drive_find_devno( 0x%lX ) found %s",
|
||||
(long) devno, fname);
|
||||
burn_drive_adr_debug_msg(msg, NULL);
|
||||
strcpy(adr, fname);
|
||||
{ ret = 1; goto ex;}
|
||||
}
|
||||
ret = 0;
|
||||
ex:;
|
||||
if (first == 0)
|
||||
sg_give_next_adr(&enm, fname, sizeof(fname), -1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ts A60923 */
|
||||
/** Try to obtain host,channel,target,lun from path.
|
||||
@return 1 = success , 0 = failure , -1 = severe error
|
||||
*/
|
||||
int burn_drive_obtain_scsi_adr(char *path,
|
||||
int *bus_no, int *host_no, int *channel_no,
|
||||
int *target_no, int *lun_no)
|
||||
{
|
||||
int ret, i;
|
||||
char adr[BURN_DRIVE_ADR_LEN];
|
||||
|
||||
/* open drives cannot be inquired by sg_obtain_scsi_adr() */
|
||||
for (i = 0; i < drivetop + 1; i++) {
|
||||
if (drive_array[i].global_index < 0)
|
||||
continue;
|
||||
ret = burn_drive_raw_get_adr(&(drive_array[i]),adr);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
if (ret == 0)
|
||||
continue;
|
||||
if (strcmp(adr, path) == 0) {
|
||||
*host_no = drive_array[i].host;
|
||||
*channel_no = drive_array[i].channel;
|
||||
*target_no = drive_array[i].id;
|
||||
*lun_no = drive_array[i].lun;
|
||||
*bus_no = drive_array[i].bus_no;
|
||||
if (*host_no < 0 || *channel_no < 0 ||
|
||||
*target_no < 0 || *lun_no < 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
ret = sg_obtain_scsi_adr(path, bus_no, host_no, channel_no,
|
||||
target_no, lun_no);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ts A60923 */
|
||||
int burn_drive_convert_scsi_adr(int bus_no, int host_no, int channel_no,
|
||||
int target_no, int lun_no, char adr[])
|
||||
{
|
||||
char fname[4096],msg[4096+100];
|
||||
int ret = 0, first = 1, i_bus_no = -1;
|
||||
int i_host_no = -1, i_channel_no = -1, i_target_no = -1, i_lun_no = -1;
|
||||
burn_drive_enumerator_t enm;
|
||||
|
||||
sprintf(msg,"burn_drive_convert_scsi_adr( %d,%d,%d,%d,%d )",
|
||||
bus_no, host_no, channel_no, target_no, lun_no);
|
||||
burn_drive_adr_debug_msg(msg, NULL);
|
||||
|
||||
while (1) {
|
||||
ret= sg_give_next_adr(&enm, fname, sizeof(fname), first);
|
||||
if(ret <= 0)
|
||||
break;
|
||||
first = 0;
|
||||
ret = burn_drive_obtain_scsi_adr(fname, &i_bus_no, &i_host_no,
|
||||
&i_channel_no, &i_target_no, &i_lun_no);
|
||||
if(ret <= 0)
|
||||
continue;
|
||||
if(bus_no >=0 && i_bus_no != bus_no)
|
||||
continue;
|
||||
if(host_no >=0 && i_host_no != host_no)
|
||||
continue;
|
||||
if(channel_no >= 0 && i_channel_no != channel_no)
|
||||
continue;
|
||||
if(target_no >= 0 && i_target_no != target_no)
|
||||
continue;
|
||||
if(lun_no >= 0 && i_lun_no != lun_no)
|
||||
continue;
|
||||
if(strlen(fname) >= BURN_DRIVE_ADR_LEN)
|
||||
{ ret = -1; goto ex;}
|
||||
burn_drive_adr_debug_msg(
|
||||
"burn_drive_convert_scsi_adr() found %s", fname);
|
||||
strcpy(adr, fname);
|
||||
{ ret = 1; goto ex;}
|
||||
}
|
||||
ret = 0;
|
||||
ex:;
|
||||
if (first == 0)
|
||||
sg_give_next_adr(&enm, fname, sizeof(fname), -1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ts A60922 ticket 33 */
|
||||
/* Try to find an enumerated address with the same host,channel,target,lun
|
||||
as path */
|
||||
int burn_drive_find_scsi_equiv(char *path, char adr[])
|
||||
{
|
||||
int ret = 0;
|
||||
int bus_no, host_no, channel_no, target_no, lun_no;
|
||||
char msg[4096];
|
||||
|
||||
ret = burn_drive_obtain_scsi_adr(path, &bus_no, &host_no, &channel_no,
|
||||
&target_no, &lun_no);
|
||||
if(ret <= 0) {
|
||||
sprintf(msg,"burn_drive_obtain_scsi_adr( %s ) returns %d\n",
|
||||
path, ret);
|
||||
burn_drive_adr_debug_msg(msg, NULL);
|
||||
return 0;
|
||||
}
|
||||
sprintf(msg, "burn_drive_find_scsi_equiv( %s ) : (%d),%d,%d,%d,%d",
|
||||
path, bus_no, host_no, channel_no, target_no, lun_no);
|
||||
burn_drive_adr_debug_msg(msg, NULL);
|
||||
|
||||
ret= burn_drive_convert_scsi_adr(-1, host_no, channel_no, target_no,
|
||||
lun_no, adr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* ts A60922 ticket 33 */
|
||||
/** Try to convert a given existing filesystem address into a persistent drive
|
||||
address. */
|
||||
int burn_drive_convert_fs_adr_sub(char *path, char adr[], int *rec_count)
|
||||
{
|
||||
int ret;
|
||||
struct stat stbuf;
|
||||
|
||||
burn_drive_adr_debug_msg("burn_drive_convert_fs_adr( %s )", path);
|
||||
if(burn_drive_is_enumerable_adr(path)) {
|
||||
if(strlen(path) >= BURN_DRIVE_ADR_LEN)
|
||||
return -1;
|
||||
burn_drive_adr_debug_msg(
|
||||
"burn_drive_is_enumerable_adr( %s ) is true", path);
|
||||
strcpy(adr, path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(lstat(path, &stbuf) == -1) {
|
||||
burn_drive_adr_debug_msg("lstat( %s ) returns -1", path);
|
||||
return 0;
|
||||
}
|
||||
if((stbuf.st_mode & S_IFMT) == S_IFLNK) {
|
||||
ret = burn_drive_resolve_link(path, adr, rec_count);
|
||||
if(ret > 0)
|
||||
return 1;
|
||||
burn_drive_adr_debug_msg("link fallback via stat( %s )", path);
|
||||
if(stat(path, &stbuf) == -1) {
|
||||
burn_drive_adr_debug_msg("stat( %s ) returns -1",path);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if((stbuf.st_mode&S_IFMT) == S_IFBLK ||
|
||||
(stbuf.st_mode&S_IFMT) == S_IFCHR) {
|
||||
ret = burn_drive_find_devno(stbuf.st_rdev, adr);
|
||||
if(ret > 0)
|
||||
return 1;
|
||||
ret = burn_drive_find_scsi_equiv(path, adr);
|
||||
if(ret > 0)
|
||||
return 1;
|
||||
}
|
||||
burn_drive_adr_debug_msg("Nothing found for %s", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Try to convert a given existing filesystem address into a persistent drive
|
||||
address. */
|
||||
int burn_drive_convert_fs_adr(char *path, char adr[])
|
||||
{
|
||||
int ret, rec_count = 0;
|
||||
|
||||
ret = burn_drive_convert_fs_adr_sub(path, adr, &rec_count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/** A pacifier function suitable for burn_abort.
|
||||
@param handle If not NULL, a pointer to a text suitable for printf("%s")
|
||||
*/
|
||||
int burn_abort_pacifier(void *handle, int patience, int elapsed)
|
||||
{
|
||||
char *prefix= "libburn : ";
|
||||
|
||||
if(handle!=NULL)
|
||||
prefix= handle;
|
||||
fprintf(stderr,
|
||||
"\r%sABORT : Waiting for drive to finish ( %d s, %d max)",
|
||||
(char *) prefix, elapsed, patience);
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/** Abort any running drive operation and finis libburn.
|
||||
@param patience Maximum number of seconds to wait for drives to finish
|
||||
@param pacifier_func Function to produce appeasing messages. See
|
||||
burn_abort_pacifier() for an example.
|
||||
@return 1 ok, all went well
|
||||
0 had to leave a drive in unclean state
|
||||
<0 severe error, do no use libburn again
|
||||
*/
|
||||
int burn_abort(int patience,
|
||||
int (*pacifier_func)(void *handle, int patience, int elapsed),
|
||||
void *handle)
|
||||
{
|
||||
int ret, i, occup, still_not_done= 1, pacifier_off= 0, first_round= 1;
|
||||
unsigned long wait_grain= 100000;
|
||||
time_t start_time, current_time, pacifier_time, end_time;
|
||||
|
||||
current_time = start_time = pacifier_time = time(0);
|
||||
end_time = start_time + patience;
|
||||
while(current_time-end_time < patience) {
|
||||
still_not_done = 0;
|
||||
|
||||
for(i = 0; i < drivetop + 1; i++) {
|
||||
occup = burn_drive_is_occupied(&(drive_array[i]));
|
||||
if(occup == -2)
|
||||
continue;
|
||||
if(occup <= 10) {
|
||||
burn_drive_forget(&(drive_array[i]), 1);
|
||||
} else if(occup <= 100) {
|
||||
if(first_round)
|
||||
burn_drive_cancel(&(drive_array[i]));
|
||||
still_not_done++;
|
||||
} else if(occup <= 1000) {
|
||||
still_not_done++;
|
||||
}
|
||||
}
|
||||
first_round = 0;
|
||||
|
||||
if(still_not_done == 0)
|
||||
break;
|
||||
usleep(wait_grain);
|
||||
current_time = time(0);
|
||||
if(current_time>pacifier_time) {
|
||||
if(pacifier_func != NULL && !pacifier_off) {
|
||||
ret = (*pacifier_func)(handle, patience,
|
||||
current_time-start_time);
|
||||
pacifier_off = (ret <= 0);
|
||||
}
|
||||
pacifier_time = current_time;
|
||||
}
|
||||
}
|
||||
burn_finish();
|
||||
return(still_not_done == 0);
|
||||
}
|
||||
|
||||
|
||||
/* ts A61020 API function */
|
||||
int burn_drive_get_start_end_lba(struct burn_drive *d,
|
||||
int *start_lba, int *end_lba, int flag)
|
||||
{
|
||||
if (d->start_lba == -2000000000 || d->end_lba == -2000000000)
|
||||
return 0;
|
||||
*start_lba = d->start_lba;
|
||||
*end_lba= d->end_lba;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ts A61020 API function */
|
||||
int burn_disc_pretend_blank(struct burn_drive *d)
|
||||
{
|
||||
if (d->status != BURN_DISC_UNREADY &&
|
||||
d->status != BURN_DISC_UNSUITABLE)
|
||||
return 0;
|
||||
d->status = BURN_DISC_BLANK;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ts A61021: new API function */
|
||||
int burn_disc_read_atip(struct burn_drive *d)
|
||||
{
|
||||
if (burn_drive_is_released(d)) {
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
d->global_index, 0x0002010e,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Attempt to read ATIP from ungrabbed drive",
|
||||
0, 0);
|
||||
return -1;
|
||||
}
|
||||
d->read_atip(d);
|
||||
/* >>> some control of success would be nice :) */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -35,9 +35,14 @@ struct mempage;
|
||||
SESSION_LEADOUT_ENTRY((d), (d)->toc->sessions-1))
|
||||
|
||||
struct burn_drive *burn_drive_register(struct burn_drive *);
|
||||
int burn_drive_unregister(struct burn_drive *d);
|
||||
|
||||
unsigned int burn_drive_count(void);
|
||||
void burn_wait_all(void);
|
||||
|
||||
/* ts A61007 */
|
||||
/* void burn_wait_all(void); */
|
||||
int burn_drives_are_clear(void);
|
||||
|
||||
int burn_sector_length_write(struct burn_drive *d);
|
||||
int burn_track_control(struct burn_drive *d, int);
|
||||
void burn_write_empty_sector(int fd);
|
||||
@ -51,7 +56,18 @@ void burn_disc_erase_sync(struct burn_drive *d, int fast);
|
||||
int burn_drive_get_block_types(struct burn_drive *d,
|
||||
enum burn_write_types write_type);
|
||||
|
||||
/* ts A60822 */
|
||||
int burn_drive_is_open(struct burn_drive *d);
|
||||
int burn_drive_is_occupied(struct burn_drive *d);
|
||||
int burn_drive_forget(struct burn_drive *d, int force);
|
||||
int burn_drive_convert_fs_adr_sub(char *path, char adr[], int *rec_count);
|
||||
|
||||
/* ts A61021 : the unspecific part of sg.c:enumerate_common()
|
||||
*/
|
||||
int burn_setup_drive(struct burn_drive *d, char *fname);
|
||||
|
||||
/* ts A61021 : after-setup activities from sg.c:enumerate_common()
|
||||
*/
|
||||
struct burn_drive *burn_drive_finish_enum(struct burn_drive *d);
|
||||
|
||||
|
||||
#endif /* __DRIVE */
|
||||
|
208
libburn/init.c
208
libburn/init.c
@ -1,9 +1,14 @@
|
||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* ts A61007 */
|
||||
/* #include <a ssert.h> */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "init.h"
|
||||
#include "sg.h"
|
||||
#include "error.h"
|
||||
@ -14,6 +19,11 @@
|
||||
#define BURN_BACK_HACKS_INIT 1
|
||||
#include "back_hacks.h"
|
||||
|
||||
/* ts A60924 : a new message handling facility */
|
||||
#include "libdax_msgs.h"
|
||||
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 */
|
||||
@ -31,50 +41,206 @@ int burn_sg_open_o_nonblock = 1;
|
||||
int burn_sg_open_abort_busy = 0;
|
||||
|
||||
|
||||
/* ts A61002 */
|
||||
|
||||
#include "cleanup.h"
|
||||
|
||||
/* Parameters for builtin abort handler */
|
||||
static char abort_message_prefix[81] = {"libburn : "};
|
||||
static pid_t abort_control_pid= 0;
|
||||
|
||||
|
||||
/* ts A60925 : ticket 74 */
|
||||
/** Create the messenger object for libburn. */
|
||||
int burn_msgs_initialize(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if(libdax_messenger == NULL) {
|
||||
ret = libdax_msgs_new(&libdax_messenger,0);
|
||||
if (ret <= 0)
|
||||
return 0;
|
||||
}
|
||||
libdax_msgs_set_severities(libdax_messenger, LIBDAX_MSGS_SEV_NEVER,
|
||||
LIBDAX_MSGS_SEV_FATAL, "libburn: ", 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ts A60924 : ticket 74 : Added use of global libdax_messenger */
|
||||
int burn_initialize(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (burn_running)
|
||||
return 1;
|
||||
|
||||
ret = burn_msgs_initialize();
|
||||
if (ret <= 0)
|
||||
return 0;
|
||||
burn_running = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void burn_finish(void)
|
||||
{
|
||||
assert(burn_running);
|
||||
/* ts A61007 : assume no messageing system */
|
||||
/* a ssert(burn_running); */
|
||||
if (!burn_running)
|
||||
return;
|
||||
|
||||
burn_wait_all();
|
||||
/* ts A61007 */
|
||||
/* burn_wait_all(); */
|
||||
if (!burn_drives_are_clear()) {
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020107,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Drive is busy on attempt to shut down library", 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ts A60904 : ticket 62, contribution by elmom : name addon "_all" */
|
||||
burn_drive_free_all();
|
||||
|
||||
/* ts A60924 : ticket 74 */
|
||||
libdax_msgs_destroy(&libdax_messenger,0);
|
||||
|
||||
burn_running = 0;
|
||||
}
|
||||
|
||||
|
||||
/* ts A60813 */
|
||||
/** Set parameters for behavior on opening device files. To be called early
|
||||
after burn_initialize() and before any bus scan. But not mandatory at all.
|
||||
@param exclusive 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.
|
||||
@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.
|
||||
@param abort_on_busy Unconditionally abort process when a non blocking
|
||||
exclusive opening attempt indicates a busy drive.
|
||||
Use this only after thorough tests with your app.
|
||||
Parameter value 1 enables a feature, 0 disables.
|
||||
Default is (1,0,0). Have a good reason before you change it.
|
||||
*/
|
||||
/** API function. See libburn.h */
|
||||
void burn_preset_device_open(int exclusive, int blocking, int abort_on_busy)
|
||||
{
|
||||
assert(burn_running);
|
||||
/* ts A61007 */
|
||||
/* a ssert(burn_running); */
|
||||
if (!burn_running)
|
||||
return;
|
||||
|
||||
burn_sg_open_o_excl= !!exclusive;
|
||||
burn_sg_open_o_excl= exclusive;
|
||||
burn_sg_open_o_nonblock= !blocking;
|
||||
burn_sg_open_abort_busy= !!abort_on_busy;
|
||||
}
|
||||
|
||||
|
||||
/* ts A60924 : ticket 74 */
|
||||
/** Control queueing and stderr printing of messages from libburn.
|
||||
Severity may be one of "NEVER", "FATAL", "SORRY", "WARNING", "HINT",
|
||||
"NOTE", "UPDATE", "DEBUG", "ALL".
|
||||
@param queue_severity Gives the minimum limit for messages to be queued.
|
||||
Default: "NEVER". If you queue messages then you
|
||||
must consume them by burn_msgs_obtain().
|
||||
@param print_severity Does the same for messages to be printed directly
|
||||
to stderr.
|
||||
@param print_id A text prefix to be printed before the message.
|
||||
@return >0 for success, <=0 for error
|
||||
|
||||
*/
|
||||
int burn_msgs_set_severities(char *queue_severity,
|
||||
char *print_severity, char *print_id)
|
||||
{
|
||||
int ret, queue_sevno, print_sevno;
|
||||
|
||||
ret = libdax_msgs__text_to_sev(queue_severity, &queue_sevno, 0);
|
||||
if (ret <= 0)
|
||||
return 0;
|
||||
ret = libdax_msgs__text_to_sev(print_severity, &print_sevno, 0);
|
||||
if (ret <= 0)
|
||||
return 0;
|
||||
ret = libdax_msgs_set_severities(libdax_messenger, queue_sevno,
|
||||
print_sevno, print_id, 0);
|
||||
if (ret <= 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ts A60924 : ticket 74 */
|
||||
#define BURM_MSGS_MESSAGE_LEN 4096
|
||||
|
||||
/** Obtain the oldest pending libburn message from the queue which has at
|
||||
least the given minimum_severity. This message and any older message of
|
||||
lower severity will get discarded from the queue and is then lost forever.
|
||||
Severity may be one of "NEVER", "FATAL", "SORRY", "WARNING", "HINT",
|
||||
"NOTE", "UPDATE", "DEBUG", "ALL". To call with minimum_severity "NEVER"
|
||||
will discard the whole queue.
|
||||
@param error_code Will become a unique error code as liste in
|
||||
libburn/libdax_msgs.h
|
||||
@param msg_text Must provide at least BURM_MSGS_MESSAGE_LEN bytes.
|
||||
@param os_errno Will become the eventual errno related to the message
|
||||
@param severity Will become the severity related to the message and
|
||||
should provide at least 80 bytes.
|
||||
@return 1 if a matching item was found, 0 if not, <0 for severe errors
|
||||
*/
|
||||
int burn_msgs_obtain(char *minimum_severity,
|
||||
int *error_code, char msg_text[], int *os_errno,
|
||||
char severity[])
|
||||
{
|
||||
int ret, minimum_sevno, sevno, priority;
|
||||
char *textpt, *sev_name;
|
||||
struct libdax_msgs_item *item = NULL;
|
||||
|
||||
ret = libdax_msgs__text_to_sev(minimum_severity, &minimum_sevno, 0);
|
||||
if (ret <= 0)
|
||||
return 0;
|
||||
ret = libdax_msgs_obtain(libdax_messenger, &item, minimum_sevno,
|
||||
LIBDAX_MSGS_PRIO_ZERO, 0);
|
||||
if (ret <= 0)
|
||||
goto ex;
|
||||
ret = libdax_msgs_item_get_msg(item, error_code, &textpt, os_errno, 0);
|
||||
if (ret <= 0)
|
||||
goto ex;
|
||||
strncpy(msg_text, textpt, BURM_MSGS_MESSAGE_LEN-1);
|
||||
if(strlen(textpt) >= BURM_MSGS_MESSAGE_LEN)
|
||||
msg_text[BURM_MSGS_MESSAGE_LEN-1] = 0;
|
||||
|
||||
severity[0]= 0;
|
||||
ret = libdax_msgs_item_get_rank(item, &sevno, &priority, 0);
|
||||
if(ret <= 0)
|
||||
goto ex;
|
||||
ret = libdax_msgs__sev_to_text(sevno, &sev_name, 0);
|
||||
if(ret <= 0)
|
||||
goto ex;
|
||||
strcpy(severity,sev_name);
|
||||
|
||||
ret = 1;
|
||||
ex:
|
||||
libdax_msgs_destroy_item(libdax_messenger, &item, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int burn_builtin_abort_handler(void *handle, int signum, int flag)
|
||||
{
|
||||
if(getpid() != abort_control_pid)
|
||||
return -2;
|
||||
Cleanup_set_handlers(NULL, NULL, 2);
|
||||
fprintf(stderr,"%sABORT : Trying to shut down drive and library\n",
|
||||
abort_message_prefix);
|
||||
fprintf(stderr,
|
||||
"%sABORT : Wait the normal burning time before any kill -9\n",
|
||||
abort_message_prefix);
|
||||
close(0); /* somehow stdin as input blocks abort until EOF */
|
||||
burn_abort(4440, burn_abort_pacifier, abort_message_prefix);
|
||||
fprintf(stderr,
|
||||
"\n%sABORT : Program done. Even if you do not see a shell prompt.\n\n",
|
||||
abort_message_prefix);
|
||||
return(1);
|
||||
}
|
||||
|
||||
void burn_set_signal_handling(void *handle, burn_abort_handler_t handler,
|
||||
int mode)
|
||||
{
|
||||
if(handler == NULL && mode == 0) {
|
||||
handler = burn_builtin_abort_handler;
|
||||
/*
|
||||
fprintf(stderr, "libburn_experimental: activated burn_builtin_abort_handler() with handle '%s'\n",(handle==NULL ? "libburn : " : (char *) handle));
|
||||
*/
|
||||
|
||||
}
|
||||
strcpy(abort_message_prefix, "libburn : ");
|
||||
if(handle != NULL)
|
||||
strncpy(abort_message_prefix, (char *) handle,
|
||||
sizeof(abort_message_prefix)-1);
|
||||
abort_message_prefix[sizeof(abort_message_prefix)-1] = 0;
|
||||
abort_control_pid= getpid();
|
||||
Cleanup_set_handlers(handle, (Cleanup_app_handler_T) handler, mode|4);
|
||||
}
|
||||
|
||||
|
@ -172,39 +172,17 @@ enum burn_disc_status
|
||||
/** There is an incomplete disc in the drive */
|
||||
BURN_DISC_APPENDABLE,
|
||||
/** There is a disc with data on it in the drive */
|
||||
BURN_DISC_FULL
|
||||
BURN_DISC_FULL,
|
||||
|
||||
/* ts A61007 */
|
||||
/** The drive was not grabbed when the status was inquired */
|
||||
BURN_DISC_UNGRABBED,
|
||||
|
||||
/* ts A61020 */
|
||||
/** The media seems not to be suitable for burning */
|
||||
BURN_DISC_UNSUITABLE
|
||||
};
|
||||
|
||||
/** Possible types of messages form the library. */
|
||||
enum burn_message_type
|
||||
{
|
||||
/** Diagnostic/Process information. For the curious user. */
|
||||
BURN_MESSAGE_INFO,
|
||||
/** A warning regarding a possible problem. The user should probably
|
||||
be notified, but its not fatal. */
|
||||
BURN_MESSAGE_WARNING,
|
||||
/** An error message. This usually means the current process will be
|
||||
aborted, and the user should definately see these. */
|
||||
BURN_MESSAGE_ERROR
|
||||
};
|
||||
|
||||
/** Possible information messages */
|
||||
enum burn_message_info
|
||||
{
|
||||
BURN_INFO_FOO
|
||||
};
|
||||
|
||||
/** Possible warning messages */
|
||||
enum burn_message_warning
|
||||
{
|
||||
BURN_WARNING_FOO
|
||||
};
|
||||
|
||||
/** Possible error messages */
|
||||
enum burn_message_error
|
||||
{
|
||||
BURN_ERROR_CANCELLED
|
||||
};
|
||||
|
||||
/** Possible data source return values */
|
||||
enum burn_source_status
|
||||
@ -317,7 +295,7 @@ struct burn_drive_info
|
||||
/** This is currently the string which is used as persistent
|
||||
drive address. But be warned: there is NO GUARANTEE that this
|
||||
will stay so. Always use function burn_drive_get_adr() to
|
||||
inquire a persisten address. ^^^^^^ ALWAYS ^^^^^^ */
|
||||
inquire a persistent address. ^^^^^^ ALWAYS ^^^^^^ */
|
||||
|
||||
/** Can the drive read DVD-RAM discs */
|
||||
unsigned int read_dvdram:1;
|
||||
@ -378,29 +356,6 @@ struct burn_drive_info
|
||||
struct burn_drive *drive;
|
||||
};
|
||||
|
||||
/** Messages from the library */
|
||||
struct burn_message
|
||||
{
|
||||
/** The drive associated with the message. NULL if the error is not
|
||||
related to a specific drive. */
|
||||
struct burn_drive *drive;
|
||||
|
||||
/** The type of message this is. See message_type for details. */
|
||||
enum burn_message_type type;
|
||||
|
||||
/** The actual message */
|
||||
union detail {
|
||||
struct {
|
||||
enum burn_message_info message;
|
||||
} info;
|
||||
struct {
|
||||
enum burn_message_warning message;
|
||||
} warning;
|
||||
struct {
|
||||
enum burn_message_error message;
|
||||
} error;
|
||||
} detail;
|
||||
};
|
||||
|
||||
/** Operation progress report. All values are 0 based indices.
|
||||
* */
|
||||
@ -423,6 +378,12 @@ struct burn_progress {
|
||||
int sectors;
|
||||
/** The current sector being processed */
|
||||
int sector;
|
||||
|
||||
/* ts A61023 */
|
||||
/** The capacity of the drive buffer */
|
||||
unsigned buffer_capacity;
|
||||
/** The free space in the drive buffer (might be slightly outdated) */
|
||||
unsigned buffer_available;
|
||||
};
|
||||
|
||||
/** Initialize the library.
|
||||
@ -444,7 +405,36 @@ int burn_initialize(void);
|
||||
*/
|
||||
void burn_finish(void);
|
||||
|
||||
/** Set the verbosity level of the library. The default value is 0, which means
|
||||
|
||||
/* ts A61002 */
|
||||
/** Abort any running drive operation and finally call burn_finish().
|
||||
You MUST calm down the busy drive if an aborting event occurs during a
|
||||
burn run. For that you may call this function either from your own signal
|
||||
handling code or indirectly by activating the builtin signal handling:
|
||||
burn_set_signal_handling("my_app_name : ", NULL, 0);
|
||||
Else you may eventually call burn_drive_cancel() on the active drive and
|
||||
wait for it to assume state BURN_DRIVE_IDLE.
|
||||
@param patience Maximum number of seconds to wait for drives to finish
|
||||
@param pacifier_func If not NULL: a function to produce appeasing messages.
|
||||
See burn_abort_pacifier() for an example.
|
||||
@return 1 ok, all went well
|
||||
0 had to leave a drive in unclean state
|
||||
<0 severe error, do no use libburn again
|
||||
*/
|
||||
int burn_abort(int patience,
|
||||
int (*pacifier_func)(void *handle, int patience, int elapsed),
|
||||
void *handle);
|
||||
|
||||
/** A pacifier function suitable for burn_abort.
|
||||
@param handle If not NULL, a pointer to a text suitable for printf("%s")
|
||||
@param patience Maximum number of seconds to wait
|
||||
@param elapsed Elapsed number of seconds
|
||||
*/
|
||||
int burn_abort_pacifier(void *handle, int patience, int elapsed);
|
||||
|
||||
|
||||
/** ts A61006 : This is for development only. Not suitable for applications.
|
||||
Set the verbosity level of the library. The default value is 0, which means
|
||||
that nothing is output on stderr. The more you increase this, the more
|
||||
debug output should be displayed on stderr for you.
|
||||
@param level The verbosity level desired. 0 for nothing, higher positive
|
||||
@ -457,10 +447,13 @@ 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 Try to open only devices which are not marked as busy
|
||||
@param 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.
|
||||
@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.
|
||||
@ -470,15 +463,6 @@ void burn_set_verbosity(int level);
|
||||
*/
|
||||
void burn_preset_device_open(int exclusive, int blocking, int abort_on_busy);
|
||||
|
||||
/** Returns a newly allocated burn_message structure. This message should be
|
||||
freed with burn_message_free() when you are finished with it.
|
||||
@return A message or NULL when there are no more messages to retrieve.
|
||||
*/
|
||||
struct burn_message* burn_get_message(void);
|
||||
|
||||
/** Frees a burn_message structure */
|
||||
void burn_message_free(struct burn_message *msg);
|
||||
|
||||
|
||||
/* ts A60823 */
|
||||
/** Aquire a drive with known persistent address.This is the sysadmin friendly
|
||||
@ -528,7 +512,7 @@ void burn_drive_clear_whitelist(void);
|
||||
|
||||
|
||||
/** Scan for drives. This function MUST be called until it returns nonzero.
|
||||
No drives can be in use when this is called or it will assert.
|
||||
No drives may be in use when this is called.
|
||||
All drive pointers are invalidated by using this function. Do NOT store
|
||||
drive pointers across calls to this function or death AND pain will ensue.
|
||||
After this call all drives depicted by the returned array are subject
|
||||
@ -541,7 +525,9 @@ void burn_drive_clear_whitelist(void);
|
||||
before burn_finish(), and also before calling this function
|
||||
burn_drive_scan() again.
|
||||
@param n_drives Returns the number of drive items in drive_infos.
|
||||
@return Zero while scanning is not complete; non-zero when it is finished.
|
||||
@return 0 while scanning is not complete
|
||||
>0 when it is finished sucessfully,
|
||||
<0 when finished but failed.
|
||||
*/
|
||||
int burn_drive_scan(struct burn_drive_info *drive_infos[],
|
||||
unsigned int *n_drives);
|
||||
@ -576,9 +562,51 @@ void burn_drive_info_free(struct burn_drive_info drive_infos[]);
|
||||
@param drive_info The drive to inquire. Usually some &(drive_infos[driveno])
|
||||
@param adr An application provided array of at least BURN_DRIVE_ADR_LEN
|
||||
characters size. The persistent address gets copied to it.
|
||||
@return >0 success , <=0 error (due to libburn internal problem)
|
||||
*/
|
||||
int burn_drive_get_adr(struct burn_drive_info *drive_info, char adr[]);
|
||||
|
||||
/* ts A60922 ticket 33 */
|
||||
/** Evaluate wether the given address would be a possible persistent drive
|
||||
address of libburn.
|
||||
@return 1 means yes, 0 means no
|
||||
*/
|
||||
int burn_drive_is_enumerable_adr(char *adr);
|
||||
|
||||
/* ts A60922 ticket 33 */
|
||||
/** Try to convert a given existing filesystem address into a persistent drive
|
||||
address. This succeeds with symbolic links or if a hint about the drive's
|
||||
system address can be read from the filesystem object and a matching drive
|
||||
is found.
|
||||
@param path The address of an existing file system object
|
||||
@param adr An application provided array of at least BURN_DRIVE_ADR_LEN
|
||||
characters size. The persistent address gets copied to it.
|
||||
@return 1 = success , 0 = failure , -1 = severe error
|
||||
*/
|
||||
int burn_drive_convert_fs_adr(char *path, char adr[]);
|
||||
|
||||
/* ts A60923 */
|
||||
/** Try to convert a given SCSI address of bus,host,channel,target,lun into
|
||||
a persistent drive address. If a SCSI address component parameter is < 0
|
||||
then it is not decisive and the first enumerated address which matches
|
||||
the >= 0 parameters is taken as result.
|
||||
Note: bus and (host,channel) are supposed to be redundant.
|
||||
@param adr An application provided array of at least BURN_DRIVE_ADR_LEN
|
||||
characters size. The persistent address gets copied to it.
|
||||
@return 1 = success , 0 = failure , -1 = severe error
|
||||
*/
|
||||
int burn_drive_convert_scsi_adr(int bus_no, int host_no, int channel_no,
|
||||
int target_no, int lun_no, char adr[]);
|
||||
|
||||
/* ts A60923 - A61005 */
|
||||
/** Try to obtain bus,host,channel,target,lun from path. If there is an SCSI
|
||||
address at all, then this call should succeed with a persistent
|
||||
drive address obtained via burn_drive_get_adr(). It is also supposed to
|
||||
succeed with any device file of a (possibly emulated) SCSI device.
|
||||
@return 1 = success , 0 = failure , -1 = severe error
|
||||
*/
|
||||
int burn_drive_obtain_scsi_adr(char *path, int *bus_no, int *host_no,
|
||||
int *channel_no, int *target_no, int *lun_no);
|
||||
|
||||
/** Grab a drive. This must be done before the drive can be used (for reading,
|
||||
writing, etc).
|
||||
@ -605,9 +633,46 @@ void burn_drive_release(struct burn_drive *drive, int eject);
|
||||
for details.
|
||||
@param drive The drive to query for a disc.
|
||||
@return The status of the drive, or what kind of disc is in it.
|
||||
Note: BURN_DISC_UNGRABBED indicates wrong API usage
|
||||
*/
|
||||
enum burn_disc_status burn_disc_get_status(struct burn_drive *drive);
|
||||
|
||||
|
||||
/* ts A61020 */
|
||||
/** WARNING: This revives an old bug-like behavior that might be dangerous.
|
||||
Sets the drive status to BURN_DISC_BLANK if it is BURN_DISC_UNREADY
|
||||
or BURN_DISC_UNSUITABLE. Thus marking media as writable which actually
|
||||
failed to declare themselves either blank or (partially) filled.
|
||||
@return 1 drive status has been set , 0 = unsuitable drive status
|
||||
*/
|
||||
int burn_disc_pretend_blank(struct burn_drive *drive);
|
||||
|
||||
|
||||
/* ts A61021 */
|
||||
/** Reads ATIP information from inserted media. To be obtained via
|
||||
burn_drive_get_write_speed(), burn_drive_get_min_write_speed(),
|
||||
burn_drive_get_start_end_lba(). The drive must be grabbed for this call.
|
||||
@param drive The drive to query.
|
||||
@return 1=sucess, 0=no valid ATIP info read, -1 severe error
|
||||
*/
|
||||
int burn_disc_read_atip(struct burn_drive *drive);
|
||||
|
||||
|
||||
/* ts A61020 */
|
||||
/** Returns start and end lba of the media which is currently inserted
|
||||
in the given drive. The drive has to be grabbed to have hope for reply.
|
||||
Shortcomming (not a feature): unless burn_disc_read_atip() was called
|
||||
only blank media will return valid info.
|
||||
@param drive The drive to query.
|
||||
@param start_lba Returns the start lba value
|
||||
@param end_lba Returns the end lba value
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@return 1 if lba values are valid , 0 if invalid
|
||||
*/
|
||||
int burn_drive_get_start_end_lba(struct burn_drive *drive,
|
||||
int *start_lba, int *end_lba, int flag);
|
||||
|
||||
|
||||
/** Tells whether a disc can be erased or not
|
||||
@return Non-zero means erasable
|
||||
*/
|
||||
@ -624,7 +689,7 @@ enum burn_drive_status burn_drive_get_status(struct burn_drive *drive,
|
||||
/** Creates a write_opts struct for burning to the specified drive
|
||||
must be freed with burn_write_opts_free
|
||||
@param drive The drive to write with
|
||||
@return The write_opts
|
||||
@return The write_opts, NULL on error
|
||||
*/
|
||||
struct burn_write_opts *burn_write_opts_new(struct burn_drive *drive);
|
||||
|
||||
@ -633,7 +698,7 @@ struct burn_write_opts *burn_write_opts_new(struct burn_drive *drive);
|
||||
*/
|
||||
void burn_write_opts_free(struct burn_write_opts *opts);
|
||||
|
||||
/** Creates a write_opts struct for reading from the specified drive
|
||||
/** Creates a read_opts struct for reading from the specified drive
|
||||
must be freed with burn_write_opts_free
|
||||
@param drive The drive to read from
|
||||
@return The read_opts
|
||||
@ -784,6 +849,16 @@ int burn_session_remove_track(struct burn_session *s, struct burn_track *t);
|
||||
void burn_track_define_data(struct burn_track *t, int offset, int tail,
|
||||
int pad, int mode);
|
||||
|
||||
|
||||
/* ts A61024 */
|
||||
/** Define wether a track shall swap bytes of its input stream.
|
||||
@param t The track to change
|
||||
@param swap_source_bytes 0=do not swap, 1=swap byte pairs
|
||||
@return 1=success , 0=unacceptable value
|
||||
*/
|
||||
int burn_track_set_byte_swap(struct burn_track *t, int swap_source_bytes);
|
||||
|
||||
|
||||
/** Set the ISRC details for a track
|
||||
@param t The track to change
|
||||
@param country the 2 char country code. Each character must be
|
||||
@ -809,7 +884,7 @@ void burn_session_hide_first_track(struct burn_session *s, int onoff);
|
||||
|
||||
/** Get the drive's disc struct - free when done
|
||||
@param d drive to query
|
||||
@return the disc struct
|
||||
@return the disc struct or NULL on failure
|
||||
*/
|
||||
struct burn_disc *burn_drive_get_disc(struct burn_drive *d);
|
||||
|
||||
@ -971,6 +1046,16 @@ void burn_read_opts_set_hardware_error_retries(struct burn_read_opts *opts,
|
||||
*/
|
||||
int burn_drive_get_write_speed(struct burn_drive *d);
|
||||
|
||||
|
||||
/* ts A61021 */
|
||||
/** Gets the minimum write speed for a drive. This might differ from
|
||||
burn_drive_get_write_speed() only after burn_disc_read_atip()
|
||||
@param d Drive to query
|
||||
@return Minimum write speed in K/s
|
||||
*/
|
||||
int burn_drive_get_min_write_speed(struct burn_drive *d);
|
||||
|
||||
|
||||
/** Gets the maximum read speed for a drive
|
||||
@param d Drive to query
|
||||
@return Maximum read speed in K/s
|
||||
@ -1031,6 +1116,68 @@ int burn_session_get_hidefirst(struct burn_session *session);
|
||||
*/
|
||||
void burn_version(int *major, int *minor, int *micro);
|
||||
|
||||
|
||||
/* ts A60924 : ticket 74 */
|
||||
/** Control queueing and stderr printing of messages from libburn.
|
||||
Severity may be one of "NEVER", "FATAL", "SORRY", "WARNING", "HINT",
|
||||
"NOTE", "UPDATE", "DEBUG", "ALL".
|
||||
@param queue_severity Gives the minimum limit for messages to be queued.
|
||||
Default: "NEVER". If you queue messages then you
|
||||
must consume them by burn_msgs_obtain().
|
||||
@param print_severity Does the same for messages to be printed directly
|
||||
to stderr. Default: "FATAL".
|
||||
@param print_id A text prefix to be printed before the message.
|
||||
@return >0 for success, <=0 for error
|
||||
|
||||
*/
|
||||
int burn_msgs_set_severities(char *queue_severity,
|
||||
char *print_severity, char *print_id);
|
||||
|
||||
/* ts A60924 : ticket 74 */
|
||||
#define BURN_MSGS_MESSAGE_LEN 4096
|
||||
|
||||
/** Obtain the oldest pending libburn message from the queue which has at
|
||||
least the given minimum_severity. This message and any older message of
|
||||
lower severity will get discarded from the queue and is then lost forever.
|
||||
Severity may be one of "NEVER", "FATAL", "SORRY", "WARNING", "HINT",
|
||||
"NOTE", "UPDATE", "DEBUG", "ALL". To call with minimum_severity "NEVER"
|
||||
will discard the whole queue.
|
||||
@param error_code Will become a unique error code as liste in
|
||||
libburn/libdax_msgs.h
|
||||
@param msg_text Must provide at least BURN_MSGS_MESSAGE_LEN bytes.
|
||||
@param os_errno Will become the eventual errno related to the message
|
||||
@param severity Will become the severity related to the message and
|
||||
should provide at least 80 bytes.
|
||||
@return 1 if a matching item was found, 0 if not, <0 for severe errors
|
||||
*/
|
||||
int burn_msgs_obtain(char *minimum_severity,
|
||||
int *error_code, char msg_text[], int *os_errno,
|
||||
char severity[]);
|
||||
|
||||
|
||||
/* ts A61002 */
|
||||
/* The prototype of a handler function suitable for burn_set_abort_handling().
|
||||
Such a function has to return -2 if it does not want the process to
|
||||
exit with value 1.
|
||||
*/
|
||||
typedef int (*burn_abort_handler_t)(void *handle, int signum, int flag);
|
||||
|
||||
/** Control builtin signal handling. See also burn_abort().
|
||||
@param handle Opaque handle eventually pointing to an application
|
||||
provided memory object
|
||||
@param handler A function to be called on signals. It will get handle as
|
||||
argument. It should finally call burn_abort(). See there.
|
||||
@param mode : 0 call handler(handle, signum, 0) on nearly all signals
|
||||
1 enable system default reaction on all signals
|
||||
2 try to ignore nearly all signals
|
||||
10 like mode 2 but handle SIGABRT like with mode 0
|
||||
Arguments (text, NULL, 0) activate the builtin abort handler. It will
|
||||
eventually call burn_abort() and then perform exit(1). If text is not NULL
|
||||
then it is used as prefix for pacifier messages of burn_abort_pacifier().
|
||||
*/
|
||||
void burn_set_signal_handling(void *handle, burn_abort_handler_t handler,
|
||||
int mode);
|
||||
|
||||
#ifndef DOXYGEN
|
||||
|
||||
BURN_END_DECLS
|
||||
|
326
libburn/libdax_audioxtr.c
Normal file
326
libburn/libdax_audioxtr.c
Normal file
@ -0,0 +1,326 @@
|
||||
|
||||
/* libdax_audioxtr
|
||||
Audio track data extraction facility of libdax and libburn.
|
||||
Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net>, provided under GPL
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
#include "libdax_msgs.h"
|
||||
extern struct libdax_msgs *libdax_messenger;
|
||||
|
||||
|
||||
/* Only this single source module is entitled to do this */
|
||||
#define LIBDAX_AUDIOXTR_H_INTERNAL 1
|
||||
|
||||
/* All clients of the extraction facility must do this */
|
||||
#include "libdax_audioxtr.h"
|
||||
|
||||
|
||||
int libdax_audioxtr_new(struct libdax_audioxtr **xtr, char *path, int flag)
|
||||
{
|
||||
int ret= -1;
|
||||
struct libdax_audioxtr *o;
|
||||
|
||||
o= *xtr= (struct libdax_audioxtr *) malloc(sizeof(struct libdax_audioxtr));
|
||||
if(o==NULL)
|
||||
return(-1);
|
||||
strncpy(o->path,path,LIBDAX_AUDIOXTR_STRLEN-1);
|
||||
o->path[LIBDAX_AUDIOXTR_STRLEN]= 0;
|
||||
o->fd= -1;
|
||||
strcpy(o->fmt,"unidentified");
|
||||
o->fmt_info[0]= 0;
|
||||
o->data_size= 0;
|
||||
o->extract_count= 0;
|
||||
|
||||
o->num_channels= 0;
|
||||
o->sample_rate= 0;
|
||||
o->bits_per_sample= 0;
|
||||
o->msb_first= 0;
|
||||
|
||||
o->wav_subchunk2_size= 0;
|
||||
|
||||
o->au_data_location= 0;
|
||||
o->au_data_size= 0xffffffff;
|
||||
|
||||
ret= libdax_audioxtr_open(o,0);
|
||||
if(ret<=0)
|
||||
{ret= -2*(ret<0); goto failure;}
|
||||
|
||||
return(1);
|
||||
failure:
|
||||
libdax_audioxtr_destroy(xtr,0);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
int libdax_audioxtr_destroy(struct libdax_audioxtr **xtr, int flag)
|
||||
{
|
||||
struct libdax_audioxtr *o;
|
||||
|
||||
o= *xtr;
|
||||
if(o==NULL)
|
||||
return(0);
|
||||
if(o->fd>=0 && strcmp(o->path,"-")!=0)
|
||||
close(o->fd);
|
||||
free((char *) o);
|
||||
*xtr= NULL;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
static int libdax_audioxtr_open(struct libdax_audioxtr *o, int flag)
|
||||
{
|
||||
int ret;
|
||||
char msg[LIBDAX_AUDIOXTR_STRLEN+80];
|
||||
|
||||
if(strcmp(o->path,"-")==0)
|
||||
o->fd= 0;
|
||||
else
|
||||
o->fd= open(o->path, O_RDONLY);
|
||||
if(o->fd<0) {
|
||||
sprintf(msg,"Cannot open audio source file : %s",o->path);
|
||||
libdax_msgs_submit(libdax_messenger,-1,0x00020200,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, errno, 0);
|
||||
return(-1);
|
||||
}
|
||||
ret= libdax_audioxtr_identify(o,0);
|
||||
if(ret<=0) {
|
||||
sprintf(msg,"Audio source file has unsuitable format : %s",o->path);
|
||||
libdax_msgs_submit(libdax_messenger,-1,0x00020201,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0, 0);
|
||||
return(0);
|
||||
}
|
||||
ret= libdax_audioxtr_init_reading(o,0);
|
||||
if(ret<=0) {
|
||||
sprintf(msg,"Failed to prepare reading of audio data : %s",o->path);
|
||||
libdax_msgs_submit(libdax_messenger,-1,0x00020202,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0, 0);
|
||||
return(0);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
static int libdax_audioxtr_identify_wav(struct libdax_audioxtr *o, int flag)
|
||||
{
|
||||
int ret;
|
||||
char buf[45];
|
||||
|
||||
/* check wether this is a MS WAVE file .wav */
|
||||
/* info used: http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ */
|
||||
|
||||
if(o->fd!=0) {
|
||||
ret= lseek(o->fd,0,SEEK_SET);
|
||||
if(ret==-1)
|
||||
return(0);
|
||||
}
|
||||
ret= read(o->fd, buf, 44);
|
||||
if(ret<44)
|
||||
return(0);
|
||||
buf[44]= 0; /* as stopper for any string operations */
|
||||
|
||||
if(strncmp(buf,"RIFF",4)!=0) /* ChunkID */
|
||||
return(0);
|
||||
if(strncmp(buf+8,"WAVE",4)!=0) /* Format */
|
||||
return(0);
|
||||
if(strncmp(buf+12,"fmt ",4)!=0) /* Subchunk1ID */
|
||||
return(0);
|
||||
if(buf[16]!=16 || buf[17]!=0 || buf[18]!=0 || buf[19]!=0) /* Subchunk1Size */
|
||||
return(0);
|
||||
if(buf[20]!=1 || buf[21]!=0) /* AudioFormat must be 1 (Linear quantization) */
|
||||
return(0);
|
||||
|
||||
strcpy(o->fmt,".wav");
|
||||
o->msb_first= 0;
|
||||
o->num_channels= libdax_audioxtr_to_int(o,(unsigned char *) buf+22,2,0);
|
||||
o->sample_rate= libdax_audioxtr_to_int(o,(unsigned char *) buf+24,4,0);
|
||||
o->bits_per_sample= libdax_audioxtr_to_int(o,(unsigned char *)buf+34,2,0);
|
||||
sprintf(o->fmt_info,
|
||||
".wav , num_channels=%d , sample_rate=%d , bits_per_sample=%d",
|
||||
o->num_channels,o->sample_rate,o->bits_per_sample);
|
||||
o->wav_subchunk2_size= libdax_audioxtr_to_int(o,(unsigned char *)buf+40,4,0);
|
||||
o->data_size= o->wav_subchunk2_size;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
static int libdax_audioxtr_identify_au(struct libdax_audioxtr *o, int flag)
|
||||
{
|
||||
int ret,encoding;
|
||||
char buf[24];
|
||||
|
||||
/* Check wether this is a Sun Audio, .au file */
|
||||
/* info used: http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ */
|
||||
|
||||
if(o->fd!=0) {
|
||||
ret= lseek(o->fd,0,SEEK_SET);
|
||||
if(ret==-1)
|
||||
return(0);
|
||||
}
|
||||
ret= read(o->fd, buf, 24);
|
||||
if(ret<24)
|
||||
return(0);
|
||||
|
||||
if(strncmp(buf,".snd",4)!=0)
|
||||
return(0);
|
||||
strcpy(o->fmt,".au");
|
||||
o->msb_first= 1;
|
||||
o->au_data_location= libdax_audioxtr_to_int(o,(unsigned char *)buf+4,4,1);
|
||||
o->au_data_size= libdax_audioxtr_to_int(o,(unsigned char *)buf+8,4,1);
|
||||
encoding= libdax_audioxtr_to_int(o,(unsigned char *)buf+12,4,1);
|
||||
if(encoding==2)
|
||||
o->bits_per_sample= 8;
|
||||
else if(encoding==3)
|
||||
o->bits_per_sample= 16;
|
||||
else if(encoding==4)
|
||||
o->bits_per_sample= 24;
|
||||
else if(encoding==5)
|
||||
o->bits_per_sample= 32;
|
||||
else
|
||||
o->bits_per_sample= -encoding;
|
||||
o->sample_rate= libdax_audioxtr_to_int(o,(unsigned char *)buf+16,4,1);
|
||||
o->num_channels= libdax_audioxtr_to_int(o,(unsigned char *)buf+20,4,1);
|
||||
if(o->au_data_size!=0xffffffff)
|
||||
o->data_size= o->au_data_size;
|
||||
else
|
||||
o->data_size= 0;
|
||||
sprintf(o->fmt_info,
|
||||
".au , num_channels=%d , sample_rate=%d , bits_per_sample=%d",
|
||||
o->num_channels,o->sample_rate,o->bits_per_sample);
|
||||
|
||||
/* <<< for testing only */;
|
||||
return(1);
|
||||
|
||||
return(o->bits_per_sample>0); /* Audio format must be linear PCM */
|
||||
}
|
||||
|
||||
|
||||
static int libdax_audioxtr_identify(struct libdax_audioxtr *o, int flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret= libdax_audioxtr_identify_wav(o, 0);
|
||||
if(ret!=0)
|
||||
return(ret);
|
||||
if(o->fd==0) /* cannot rewind stdin */
|
||||
return(0);
|
||||
ret= libdax_audioxtr_identify_au(o, 0);
|
||||
if(ret!=0)
|
||||
return(ret);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/* @param flag bit0=msb_first */
|
||||
static unsigned libdax_audioxtr_to_int(struct libdax_audioxtr *o,
|
||||
unsigned char *bytes, int len, int flag)
|
||||
{
|
||||
unsigned int ret= 0;
|
||||
int i;
|
||||
|
||||
if(flag&1)
|
||||
for(i= 0; i<len; i++)
|
||||
ret= ret*256+bytes[i];
|
||||
else
|
||||
for(i= len-1; i>=0; i--)
|
||||
ret= ret*256+bytes[i];
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
static int libdax_audioxtr_init_reading(struct libdax_audioxtr *o, int flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
||||
/* currently this only works for MS WAVE files .wav and Sun .au*/;
|
||||
if(o->fd==0) /* stdin: hope no read came after libdax_audioxtr_identify() */
|
||||
return(1);
|
||||
|
||||
o->extract_count= 0;
|
||||
if(strcmp(o->fmt,".wav")==0)
|
||||
ret= lseek(o->fd,44,SEEK_SET);
|
||||
else if(strcmp(o->fmt,".au")==0)
|
||||
ret= lseek(o->fd,o->au_data_location,SEEK_SET);
|
||||
else
|
||||
ret= -1;
|
||||
if(ret==-1)
|
||||
return(0);
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int libdax_audioxtr_get_id(struct libdax_audioxtr *o,
|
||||
char **fmt, char **fmt_info,
|
||||
int *num_channels, int *sample_rate, int *bits_per_sample,
|
||||
int *msb_first, int flag)
|
||||
{
|
||||
*fmt= o->fmt;
|
||||
*fmt_info= o->fmt_info;
|
||||
*num_channels= o->num_channels;
|
||||
*sample_rate= o->sample_rate;
|
||||
*bits_per_sample= o->bits_per_sample;
|
||||
*msb_first= o->msb_first;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int libdax_audioxtr_get_size(struct libdax_audioxtr *o, off_t *size, int flag)
|
||||
{
|
||||
*size= o->data_size;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int libdax_audioxtr_read(struct libdax_audioxtr *o,
|
||||
char buffer[], int buffer_size, int flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if(buffer_size<=0 || o->fd<0)
|
||||
return(-2);
|
||||
if(o->data_size>0 && !(flag&1))
|
||||
if(buffer_size > o->data_size - o->extract_count)
|
||||
buffer_size= o->data_size - o->extract_count;
|
||||
if(buffer_size<=0)
|
||||
return(0);
|
||||
ret= read(o->fd,buffer,buffer_size);
|
||||
if(ret>0)
|
||||
o->extract_count+= ret;
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
int libdax_audioxtr_detach_fd(struct libdax_audioxtr *o, int *fd, int flag)
|
||||
{
|
||||
if(o->fd<0)
|
||||
return(-1);
|
||||
if(strcmp(o->fmt,".wav")!=0 && strcmp(o->fmt,".au")!=0)
|
||||
return(0);
|
||||
if(flag&1) {
|
||||
*fd= o->fd;
|
||||
} else {
|
||||
*fd= dup(o->fd);
|
||||
if(*fd>=0 && strcmp(o->path,"-")!=0)
|
||||
close(o->fd);
|
||||
}
|
||||
if(*fd>=0) {
|
||||
o->fd= -1;
|
||||
return(1);
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
|
229
libburn/libdax_audioxtr.h
Normal file
229
libburn/libdax_audioxtr.h
Normal file
@ -0,0 +1,229 @@
|
||||
|
||||
/* libdax_audioxtr
|
||||
Audio track data extraction facility of libdax and libburn.
|
||||
Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net>, provided under GPL
|
||||
*/
|
||||
|
||||
#ifndef LIBDAX_AUDIOXTR_H_INCLUDED
|
||||
#define LIBDAX_AUDIOXTR_H_INCLUDED 1
|
||||
|
||||
/* Public Macros */
|
||||
|
||||
/* Maximum size for address paths and fmt_info strings */
|
||||
#define LIBDAX_AUDIOXTR_STRLEN 4096
|
||||
|
||||
|
||||
/* Public Opaque Handles */
|
||||
|
||||
/** Extractor object encapsulating intermediate states of extraction.
|
||||
The clients of libdax_audioxtr shall only allocate pointers to this
|
||||
struct and get a storage object via libdax_audioxtr_new().
|
||||
Appropriate initial value for the pointer is NULL.
|
||||
*/
|
||||
struct libdax_audioxtr;
|
||||
|
||||
|
||||
/* Public Functions */
|
||||
|
||||
/* Calls initiated from inside libdax/libburn */
|
||||
|
||||
|
||||
/* Calls from applications (to be forwarded by libdax/libburn) */
|
||||
|
||||
|
||||
/** Open an audio file, check wether suitable, create extractor object.
|
||||
@param xtr Opaque handle to extractor. Gets attached extractor object.
|
||||
@param path Address of the audio file to extract. "-" is stdin (but might
|
||||
be not suitable for all futurely supported formats).
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@return >0 success
|
||||
0 unsuitable format
|
||||
-1 severe error
|
||||
-2 path not found
|
||||
*/
|
||||
int libdax_audioxtr_new(struct libdax_audioxtr **xtr, char *path, int flag);
|
||||
|
||||
|
||||
/** Obtain identification parameters of opened audio source.
|
||||
@param xtr Opaque handle to extractor
|
||||
@param fmt Gets pointed to the audio file format id text: ".wav" , ".au"
|
||||
@param fmt_info Gets pointed to a format info text telling parameters
|
||||
@param num_channels e.g. 1=mono, 2=stereo, etc
|
||||
@param sample_rate e.g. 11025, 44100
|
||||
@param bits_per_sample e.g. 8= 8 bits per sample, 16= 16 bits ...
|
||||
@param msb_first Byte order of samples: 0=Intel 1=Motorola
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@return >0 success, <=0 failure
|
||||
*/
|
||||
int libdax_audioxtr_get_id(struct libdax_audioxtr *xtr,
|
||||
char **fmt, char **fmt_info,
|
||||
int *num_channels, int *sample_rate,
|
||||
int *bits_per_sample, int *msb_first, int flag);
|
||||
|
||||
|
||||
/** Obtain a prediction about the extracted size based on internal information
|
||||
of the formatted file.
|
||||
@param xtr Opaque handle to extractor
|
||||
@param size Gets filled with the predicted size
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@return 1 prediction was possible , 0 no prediction could be made
|
||||
*/
|
||||
int libdax_audioxtr_get_size(struct libdax_audioxtr *o, off_t *size, int flag);
|
||||
|
||||
|
||||
/** Obtain next buffer full of extracted data in desired format (only raw audio
|
||||
for now).
|
||||
@param xtr Opaque handle to extractor
|
||||
@param buffer Gets filled with extracted data
|
||||
@param buffer_size Maximum number of bytes to be filled into buffer
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= do not stop at predicted end of data
|
||||
@return >0 number of valid buffer bytes,
|
||||
0 End of file
|
||||
-1 operating system reports error
|
||||
-2 usage error by application
|
||||
*/
|
||||
int libdax_audioxtr_read(struct libdax_audioxtr *xtr,
|
||||
char buffer[], int buffer_size, int flag);
|
||||
|
||||
|
||||
/** Try to obtain a file descriptor which will deliver extracted data
|
||||
to normal calls of read(2). This may fail because the format is
|
||||
unsuitable for that, but ".wav" is ok. If this call succeeds the xtr
|
||||
object will have forgotten its file descriptor and libdax_audioxtr_read()
|
||||
will return a usage error. One may use *fd after libdax_audioxtr_destroy()
|
||||
and will have to close it via close(2) when done with it.
|
||||
@param xtr Opaque handle to extractor
|
||||
@param fd Eventually returns the file descriptor number
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= do not dup(2) and close(2) but hand out original fd
|
||||
@return 1 success, 0 cannot hand out fd , -1 severe error
|
||||
*/
|
||||
int libdax_audioxtr_detach_fd(struct libdax_audioxtr *o, int *fd, int flag);
|
||||
|
||||
|
||||
/** Clean up after extraction and destroy extractor object.
|
||||
@param xtr Opaque handle to extractor, *xtr is allowed to be NULL,
|
||||
*xtr is set to NULL by this function
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@return 1 = destroyed object, 0 = was already destroyed
|
||||
*/
|
||||
int libdax_audioxtr_destroy(struct libdax_audioxtr **xtr, int flag);
|
||||
|
||||
|
||||
|
||||
#ifdef LIDBAX_AUDIOXTR________________
|
||||
|
||||
|
||||
-- place documentation text here ---
|
||||
|
||||
|
||||
#endif /* LIDBAX_AUDIOXTR_________________ */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*Never* set this macro outside libdax_audioxtr.c !
|
||||
The entrails of this facility are not to be seen by
|
||||
the other library components or the applications.
|
||||
*/
|
||||
#ifdef LIBDAX_AUDIOXTR_H_INTERNAL
|
||||
|
||||
/* Internal Structures */
|
||||
|
||||
/** Extractor object encapsulating intermediate states of extraction */
|
||||
struct libdax_audioxtr {
|
||||
|
||||
/* Source of the encoded audio data */
|
||||
char path[LIBDAX_AUDIOXTR_STRLEN];
|
||||
|
||||
/* File descriptor to path. Anything else than 0 must be lseek-able */
|
||||
int fd;
|
||||
|
||||
/* Format identifier. E.g. ".wav" */
|
||||
char fmt[80];
|
||||
|
||||
/* Format parameter info text */
|
||||
char fmt_info[LIBDAX_AUDIOXTR_STRLEN];
|
||||
|
||||
/* 1= mono, 2= stereo, etc. */
|
||||
int num_channels;
|
||||
|
||||
/* 8000, 44100, etc. */
|
||||
int sample_rate;
|
||||
|
||||
/* 8 bits = 8, 16 bits = 16, etc. */
|
||||
int bits_per_sample;
|
||||
|
||||
/* Byte order of samples: 0=Intel 1=Motorola */
|
||||
int msb_first;
|
||||
|
||||
/* Number of bytes to extract (0= unknown/unlimited) */
|
||||
off_t data_size;
|
||||
|
||||
/* Number of extracted data bytes */
|
||||
off_t extract_count;
|
||||
|
||||
|
||||
/* Format dependent parameters */
|
||||
|
||||
/* MS WAVE Format */
|
||||
/* info used: http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ */
|
||||
|
||||
/* == NumSamples * NumChannels * BitsPerSample/8
|
||||
This is the number of bytes in the data. */
|
||||
unsigned wav_subchunk2_size;
|
||||
|
||||
|
||||
/* Sun Audio, .au */
|
||||
/* info used: http://www.opengroup.org/public/pubs/external/auformat.html */
|
||||
|
||||
/* Number of bytes in non-payload header part */
|
||||
unsigned au_data_location;
|
||||
|
||||
/* Number of payload bytes or 0xffffffff */
|
||||
unsigned au_data_size;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/* Internal Functions */
|
||||
|
||||
/** Open the audio source pointed to by .path and evaluate suitability.
|
||||
@return -1 failure to open, 0 unsuitable format, 1 success
|
||||
*/
|
||||
static int libdax_audioxtr_open(struct libdax_audioxtr *o, int flag);
|
||||
|
||||
|
||||
/** Identify format and evaluate suitability.
|
||||
@return 0 unsuitable format, 1 format is suitable
|
||||
*/
|
||||
static int libdax_audioxtr_identify(struct libdax_audioxtr *o, int flag);
|
||||
|
||||
/** Specialized identifier for .wav */
|
||||
static int libdax_audioxtr_identify_wav(struct libdax_audioxtr *o, int flag);
|
||||
/** Specialized identifier for .au */
|
||||
static int libdax_audioxtr_identify_au(struct libdax_audioxtr *o, int flag);
|
||||
|
||||
|
||||
/** Convert a byte string into a number (currently only little endian)
|
||||
@param flag Bitfield for control purposes
|
||||
bit0=msb_first
|
||||
@return The resulting number
|
||||
*/
|
||||
static unsigned libdax_audioxtr_to_int(struct libdax_audioxtr *o,
|
||||
unsigned char *bytes, int len, int flag);
|
||||
|
||||
|
||||
/** Prepare for reading of first buffer.
|
||||
@return 0 error, 1 success
|
||||
*/
|
||||
static int libdax_audioxtr_init_reading(struct libdax_audioxtr *o, int flag);
|
||||
|
||||
|
||||
|
||||
#endif /* LIBDAX_AUDIOXTR_H_INTERNAL */
|
||||
|
||||
|
||||
#endif /* ! LIBDAX_AUDIOXTR_H_INCLUDED */
|
||||
|
404
libburn/libdax_msgs.c
Normal file
404
libburn/libdax_msgs.c
Normal file
@ -0,0 +1,404 @@
|
||||
|
||||
/* libdax_msgs
|
||||
Message handling facility of libdax.
|
||||
Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net>, provided under GPL
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
/* Only this single source module is entitled to do this */
|
||||
#define LIBDAX_MSGS_H_INTERNAL 1
|
||||
|
||||
/* All participants in the messaging system must do this */
|
||||
#include "libdax_msgs.h"
|
||||
|
||||
|
||||
/* ----------------------------- libdax_msgs_item ------------------------- */
|
||||
|
||||
|
||||
static int libdax_msgs_item_new(struct libdax_msgs_item **item,
|
||||
struct libdax_msgs_item *link, int flag)
|
||||
{
|
||||
int ret;
|
||||
struct libdax_msgs_item *o;
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
|
||||
(*item)= o=
|
||||
(struct libdax_msgs_item *) malloc(sizeof(struct libdax_msgs_item));
|
||||
if(o==NULL)
|
||||
return(-1);
|
||||
o->timestamp= 0.0;
|
||||
ret= gettimeofday(&tv,&tz);
|
||||
if(ret==0)
|
||||
o->timestamp= tv.tv_sec+0.000001*tv.tv_usec;
|
||||
o->process_id= getpid();
|
||||
o->driveno= -1;
|
||||
o->severity= LIBDAX_MSGS_SEV_ALL;
|
||||
o->priority= LIBDAX_MSGS_PRIO_ZERO;
|
||||
o->error_code= 0;
|
||||
o->msg_text= NULL;
|
||||
o->os_errno= 0;
|
||||
o->prev= link;
|
||||
o->next= NULL;
|
||||
if(link!=NULL) {
|
||||
if(link->next!=NULL) {
|
||||
link->next->prev= o;
|
||||
o->next= link->next;
|
||||
}
|
||||
link->next= o;
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/** Detaches item from its queue and eventually readjusts start, end pointers
|
||||
of the queue */
|
||||
int libdax_msgs_item_unlink(struct libdax_msgs_item *o,
|
||||
struct libdax_msgs_item **chain_start,
|
||||
struct libdax_msgs_item **chain_end, int flag)
|
||||
{
|
||||
if(o->prev!=NULL)
|
||||
o->prev->next= o->next;
|
||||
if(o->next!=NULL)
|
||||
o->next->prev= o->prev;
|
||||
if(chain_start!=NULL)
|
||||
if(*chain_start == o)
|
||||
*chain_start= o->next;
|
||||
if(chain_end!=NULL)
|
||||
if(*chain_end == o)
|
||||
*chain_end= o->prev;
|
||||
o->next= o->prev= NULL;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int libdax_msgs_item_destroy(struct libdax_msgs_item **item,
|
||||
int flag)
|
||||
{
|
||||
struct libdax_msgs_item *o;
|
||||
|
||||
o= *item;
|
||||
if(o==NULL)
|
||||
return(0);
|
||||
libdax_msgs_item_unlink(o,NULL,NULL,0);
|
||||
if(o->msg_text!=NULL)
|
||||
free((char *) o->msg_text);
|
||||
free((char *) o);
|
||||
*item= NULL;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int libdax_msgs_item_get_msg(struct libdax_msgs_item *item,
|
||||
int *error_code, char **msg_text, int *os_errno,
|
||||
int flag)
|
||||
{
|
||||
*error_code= item->error_code;
|
||||
*msg_text= item->msg_text;
|
||||
*os_errno= item->os_errno;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int libdax_msgs_item_get_origin(struct libdax_msgs_item *item,
|
||||
double *timestamp, pid_t *process_id, int *driveno,
|
||||
int flag)
|
||||
{
|
||||
*timestamp= item->timestamp;
|
||||
*process_id= item->process_id;
|
||||
*driveno= item->driveno;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int libdax_msgs_item_get_rank(struct libdax_msgs_item *item,
|
||||
int *severity, int *priority, int flag)
|
||||
{
|
||||
*severity= item->severity;
|
||||
*priority= item->priority;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------- libdax_msgs ---------------------------- */
|
||||
|
||||
|
||||
int libdax_msgs_new(struct libdax_msgs **m, int flag)
|
||||
{
|
||||
struct libdax_msgs *o;
|
||||
|
||||
(*m)= o= (struct libdax_msgs *) malloc(sizeof(struct libdax_msgs));
|
||||
if(o==NULL)
|
||||
return(-1);
|
||||
o->oldest= NULL;
|
||||
o->youngest= NULL;
|
||||
o->count= 0;
|
||||
o->queue_severity= LIBDAX_MSGS_SEV_ALL;
|
||||
o->print_severity= LIBDAX_MSGS_SEV_NEVER;
|
||||
strcpy(o->print_id,"libdax: ");
|
||||
|
||||
#ifndef LIBDAX_MSGS_SINGLE_THREADED
|
||||
pthread_mutex_init(&(o->lock_mutex),NULL);
|
||||
#endif
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int libdax_msgs_destroy(struct libdax_msgs **m, int flag)
|
||||
{
|
||||
struct libdax_msgs *o;
|
||||
struct libdax_msgs_item *item, *next_item;
|
||||
|
||||
o= *m;
|
||||
if(o==NULL)
|
||||
return(0);
|
||||
|
||||
#ifndef LIBDAX_MSGS_SINGLE_THREADED
|
||||
if(pthread_mutex_destroy(&(o->lock_mutex))!=0) {
|
||||
pthread_mutex_unlock(&(o->lock_mutex));
|
||||
pthread_mutex_destroy(&(o->lock_mutex));
|
||||
}
|
||||
#endif
|
||||
|
||||
for(item= o->oldest; item!=NULL; item= next_item) {
|
||||
next_item= item->next;
|
||||
libdax_msgs_item_destroy(&item,0);
|
||||
}
|
||||
free((char *) o);
|
||||
*m= NULL;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int libdax_msgs_set_severities(struct libdax_msgs *m, int queue_severity,
|
||||
int print_severity, char *print_id, int flag)
|
||||
{
|
||||
m->queue_severity= queue_severity;
|
||||
m->print_severity= print_severity;
|
||||
strncpy(m->print_id,print_id,80);
|
||||
m->print_id[80]= 0;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
static int libdax_msgs_lock(struct libdax_msgs *m, int flag)
|
||||
{
|
||||
|
||||
#ifndef LIBDAX_MSGS_SINGLE_THREADED
|
||||
int ret;
|
||||
|
||||
ret= pthread_mutex_lock(&(m->lock_mutex));
|
||||
if(ret!=0)
|
||||
return(0);
|
||||
#endif
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
static int libdax_msgs_unlock(struct libdax_msgs *m, int flag)
|
||||
{
|
||||
|
||||
#ifndef LIBDAX_MSGS_SINGLE_THREADED
|
||||
int ret;
|
||||
|
||||
ret= pthread_mutex_unlock(&(m->lock_mutex));
|
||||
if(ret!=0)
|
||||
return(0);
|
||||
#endif
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int libdax_msgs__text_to_sev(char *severity_name, int *severity,
|
||||
int flag)
|
||||
{
|
||||
if(strncmp(severity_name,"NEVER",5)==0)
|
||||
*severity= LIBDAX_MSGS_SEV_NEVER;
|
||||
else if(strncmp(severity_name,"ABORT",5)==0)
|
||||
*severity= LIBDAX_MSGS_SEV_ABORT;
|
||||
else if(strncmp(severity_name,"FATAL",5)==0)
|
||||
*severity= LIBDAX_MSGS_SEV_FATAL;
|
||||
else if(strncmp(severity_name,"SORRY",5)==0)
|
||||
*severity= LIBDAX_MSGS_SEV_SORRY;
|
||||
else if(strncmp(severity_name,"WARNING",7)==0)
|
||||
*severity= LIBDAX_MSGS_SEV_WARNING;
|
||||
else if(strncmp(severity_name,"HINT",4)==0)
|
||||
*severity= LIBDAX_MSGS_SEV_HINT;
|
||||
else if(strncmp(severity_name,"NOTE",4)==0)
|
||||
*severity= LIBDAX_MSGS_SEV_NOTE;
|
||||
else if(strncmp(severity_name,"UPDATE",6)==0)
|
||||
*severity= LIBDAX_MSGS_SEV_UPDATE;
|
||||
else if(strncmp(severity_name,"DEBUG",5)==0)
|
||||
*severity= LIBDAX_MSGS_SEV_DEBUG;
|
||||
else if(strncmp(severity_name,"ALL",3)==0)
|
||||
*severity= LIBDAX_MSGS_SEV_ALL;
|
||||
else {
|
||||
*severity= LIBDAX_MSGS_SEV_NEVER;
|
||||
return(0);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int libdax_msgs__sev_to_text(int severity, char **severity_name,
|
||||
int flag)
|
||||
{
|
||||
if(flag&1) {
|
||||
*severity_name=
|
||||
"NEVER\nABORT\nFATAL\nSORRY\nWARNING\nHINT\nNOTE\nUPDATE\nDEBUG\nALL";
|
||||
return(1);
|
||||
}
|
||||
*severity_name= "";
|
||||
if(severity>=LIBDAX_MSGS_SEV_NEVER)
|
||||
*severity_name= "NEVER";
|
||||
else if(severity>=LIBDAX_MSGS_SEV_ABORT)
|
||||
*severity_name= "ABORT";
|
||||
else if(severity>=LIBDAX_MSGS_SEV_FATAL)
|
||||
*severity_name= "FATAL";
|
||||
else if(severity>=LIBDAX_MSGS_SEV_SORRY)
|
||||
*severity_name= "SORRY";
|
||||
else if(severity>=LIBDAX_MSGS_SEV_WARNING)
|
||||
*severity_name= "WARNING";
|
||||
else if(severity>=LIBDAX_MSGS_SEV_HINT)
|
||||
*severity_name= "HINT";
|
||||
else if(severity>=LIBDAX_MSGS_SEV_NOTE)
|
||||
*severity_name= "NOTE";
|
||||
else if(severity>=LIBDAX_MSGS_SEV_UPDATE)
|
||||
*severity_name= "UPDATE";
|
||||
else if(severity>=LIBDAX_MSGS_SEV_DEBUG)
|
||||
*severity_name= "DEBUG";
|
||||
else if(severity>=LIBDAX_MSGS_SEV_ALL)
|
||||
*severity_name= "ALL";
|
||||
else {
|
||||
*severity_name= "";
|
||||
return(0);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int libdax_msgs_submit(struct libdax_msgs *m, int driveno, int error_code,
|
||||
int severity, int priority, char *msg_text,
|
||||
int os_errno, int flag)
|
||||
{
|
||||
int ret;
|
||||
char *textpt,*sev_name,sev_text[81];
|
||||
struct libdax_msgs_item *item= NULL;
|
||||
|
||||
if(severity >= m->print_severity) {
|
||||
if(msg_text==NULL)
|
||||
textpt= "";
|
||||
else
|
||||
textpt= msg_text;
|
||||
sev_text[0]= 0;
|
||||
ret= libdax_msgs__sev_to_text(severity,&sev_name,0);
|
||||
if(ret>0)
|
||||
sprintf(sev_text,"%s : ",sev_name);
|
||||
|
||||
fprintf(stderr,"%s%s%s\n",m->print_id,sev_text,textpt);
|
||||
if(os_errno!=0) {
|
||||
ret= libdax_msgs_lock(m,0);
|
||||
if(ret<=0)
|
||||
return(-1);
|
||||
fprintf(stderr,"%s( Most recent system error: %d '%s' )\n",
|
||||
m->print_id,os_errno,strerror(os_errno));
|
||||
libdax_msgs_unlock(m,0);
|
||||
}
|
||||
|
||||
}
|
||||
if(severity < m->queue_severity)
|
||||
return(0);
|
||||
|
||||
ret= libdax_msgs_lock(m,0);
|
||||
if(ret<=0)
|
||||
return(-1);
|
||||
ret= libdax_msgs_item_new(&item,m->youngest,0);
|
||||
if(ret<=0)
|
||||
goto failed;
|
||||
item->driveno= driveno;
|
||||
item->error_code= error_code;
|
||||
item->severity= severity;
|
||||
item->priority= priority;
|
||||
if(msg_text!=NULL) {
|
||||
item->msg_text= malloc(strlen(msg_text)+1);
|
||||
if(item->msg_text==NULL)
|
||||
goto failed;
|
||||
strcpy(item->msg_text,msg_text);
|
||||
}
|
||||
item->os_errno= os_errno;
|
||||
if(m->oldest==NULL)
|
||||
m->oldest= item;
|
||||
m->youngest= item;
|
||||
m->count++;
|
||||
libdax_msgs_unlock(m,0);
|
||||
|
||||
/*
|
||||
fprintf(stderr,"libdax_experimental: message submitted to queue (now %d)\n",
|
||||
m->count);
|
||||
*/
|
||||
|
||||
return(1);
|
||||
failed:;
|
||||
libdax_msgs_item_destroy(&item,0);
|
||||
libdax_msgs_unlock(m,0);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
||||
int libdax_msgs_obtain(struct libdax_msgs *m, struct libdax_msgs_item **item,
|
||||
int severity, int priority, int flag)
|
||||
{
|
||||
int ret;
|
||||
struct libdax_msgs_item *im, *next_im= NULL;
|
||||
|
||||
*item= NULL;
|
||||
ret= libdax_msgs_lock(m,0);
|
||||
if(ret<=0)
|
||||
return(-1);
|
||||
for(im= m->oldest; im!=NULL; im= next_im) {
|
||||
for(; im!=NULL; im= next_im) {
|
||||
next_im= im->next;
|
||||
if(im->severity>=severity)
|
||||
break;
|
||||
libdax_msgs_item_unlink(im,&(m->oldest),&(m->youngest),0);
|
||||
libdax_msgs_item_destroy(&im,0); /* severity too low: delete */
|
||||
}
|
||||
if(im==NULL)
|
||||
break;
|
||||
if(im->priority>=priority)
|
||||
break;
|
||||
}
|
||||
if(im==NULL)
|
||||
{ret= 0; goto ex;}
|
||||
libdax_msgs_item_unlink(im,&(m->oldest),&(m->youngest),0);
|
||||
*item= im;
|
||||
ret= 1;
|
||||
ex:;
|
||||
libdax_msgs_unlock(m,0);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
int libdax_msgs_destroy_item(struct libdax_msgs *m,
|
||||
struct libdax_msgs_item **item, int flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret= libdax_msgs_lock(m,0);
|
||||
if(ret<=0)
|
||||
return(-1);
|
||||
ret= libdax_msgs_item_destroy(item,0);
|
||||
libdax_msgs_unlock(m,0);
|
||||
return(ret);
|
||||
}
|
||||
|
376
libburn/libdax_msgs.h
Normal file
376
libburn/libdax_msgs.h
Normal file
@ -0,0 +1,376 @@
|
||||
|
||||
/* libdax_msgs
|
||||
Message handling facility of libdax.
|
||||
Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net>, provided under GPL
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
*Never* set this macro outside libdax_msgs.c !
|
||||
The entrails of the message handling facility are not to be seen by
|
||||
the other library components or the applications.
|
||||
*/
|
||||
#ifdef LIBDAX_MSGS_H_INTERNAL
|
||||
|
||||
|
||||
#ifndef LIBDAX_MSGS_SINGLE_THREADED
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
|
||||
struct libdax_msgs_item {
|
||||
|
||||
double timestamp;
|
||||
pid_t process_id;
|
||||
int driveno;
|
||||
|
||||
int severity;
|
||||
int priority;
|
||||
|
||||
/* Apply for your developer's error code range at
|
||||
libburn-hackers@pykix.org
|
||||
Report introduced codes in the list below. */
|
||||
int error_code;
|
||||
|
||||
char *msg_text;
|
||||
int os_errno;
|
||||
|
||||
struct libdax_msgs_item *prev,*next;
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct libdax_msgs {
|
||||
|
||||
struct libdax_msgs_item *oldest;
|
||||
struct libdax_msgs_item *youngest;
|
||||
int count;
|
||||
|
||||
int queue_severity;
|
||||
int print_severity;
|
||||
char print_id[81];
|
||||
|
||||
#ifndef LIBDAX_MSGS_SINGLE_THREADED
|
||||
pthread_mutex_t lock_mutex;
|
||||
#endif
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif /* LIBDAX_MSGS_H_INTERNAL */
|
||||
|
||||
|
||||
#ifndef LIBDAX_MSGS_H_INCLUDED
|
||||
#define LIBDAX_MSGS_H_INCLUDED 1
|
||||
|
||||
|
||||
#ifndef LIBDAX_MSGS_H_INTERNAL
|
||||
|
||||
|
||||
/* Public Opaque Handles */
|
||||
|
||||
/** A pointer to this is a opaque handle to a message handling facility */
|
||||
struct libdax_msgs;
|
||||
|
||||
/** A pointer to this is a opaque handle to a single message item */
|
||||
struct libdax_msgs_item;
|
||||
|
||||
#endif /* ! LIBDAX_MSGS_H_INTERNAL */
|
||||
|
||||
|
||||
/* Public Macros */
|
||||
|
||||
|
||||
/* Registered Severities */
|
||||
|
||||
/* It is well advisable to let applications select severities via strings and
|
||||
forwarded functions libdax_msgs__text_to_sev(), libdax_msgs__sev_to_text().
|
||||
These macros are for use by libdax/libburn only.
|
||||
*/
|
||||
|
||||
/** Use this to get messages of any severity. Do not use for submitting.
|
||||
*/
|
||||
#define LIBDAX_MSGS_SEV_ALL 0x00000000
|
||||
|
||||
/** Debugging messages not to be visible to normal users by default
|
||||
*/
|
||||
#define LIBDAX_MSGS_SEV_DEBUG 0x10000000
|
||||
|
||||
/** Update of a progress report about long running actions
|
||||
*/
|
||||
#define LIBDAX_MSGS_SEV_UPDATE 0x20000000
|
||||
|
||||
/** Not so usual events which were gracefully handled
|
||||
*/
|
||||
#define LIBDAX_MSGS_SEV_NOTE 0x30000000
|
||||
|
||||
/** Possibilities to achieve a better result
|
||||
*/
|
||||
#define LIBDAX_MSGS_SEV_HINT 0x40000000
|
||||
|
||||
/** Warnings about problems which could not be handled optimally
|
||||
*/
|
||||
#define LIBDAX_MSGS_SEV_WARNING 0x50000000
|
||||
|
||||
/** Non-fatal error messages indicating that parts of the action failed
|
||||
but processing will/should go on
|
||||
*/
|
||||
#define LIBDAX_MSGS_SEV_SORRY 0x60000000
|
||||
|
||||
/** An error message which puts the whole operation of libdax in question
|
||||
*/
|
||||
#define LIBDAX_MSGS_SEV_FATAL 0x70000000
|
||||
|
||||
/** A message from an abort handler which will finally finish libburn
|
||||
*/
|
||||
#define LIBDAX_MSGS_SEV_ABORT 0x71000000
|
||||
|
||||
/** A severity to exclude resp. discard any possible message.
|
||||
Do not use this severity for submitting.
|
||||
*/
|
||||
#define LIBDAX_MSGS_SEV_NEVER 0x7fffffff
|
||||
|
||||
|
||||
/* Registered Priorities */
|
||||
|
||||
/* Priorities are to be used by libburn/libdax only. */
|
||||
|
||||
#define LIBDAX_MSGS_PRIO_ZERO 0x00000000
|
||||
#define LIBDAX_MSGS_PRIO_LOW 0x10000000
|
||||
#define LIBDAX_MSGS_PRIO_MEDIUM 0x20000000
|
||||
#define LIBDAX_MSGS_PRIO_HIGH 0x30000000
|
||||
#define LIBDAX_MSGS_PRIO_TOP 0x7ffffffe
|
||||
|
||||
/* Do not use this priority for submitting */
|
||||
#define LIBDAX_MSGS_PRIO_NEVER 0x7fffffff
|
||||
|
||||
|
||||
/* Public Functions */
|
||||
|
||||
/* Calls initiated from inside libdax/libburn */
|
||||
|
||||
|
||||
/** Create new empty message handling facility with queue.
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@return >0 success, <=0 failure
|
||||
*/
|
||||
int libdax_msgs_new(struct libdax_msgs **m, int flag);
|
||||
|
||||
|
||||
/** Destroy a message handling facility and all its eventual messages.
|
||||
The submitted pointer gets set to NULL.
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@return 1 for success, 0 for pointer to NULL
|
||||
*/
|
||||
int libdax_msgs_destroy(struct libdax_msgs **m, int flag);
|
||||
|
||||
|
||||
/** Submit a message to a message handling facility.
|
||||
@param driveno libdax drive number. Use -1 if no number is known.
|
||||
@param error_code Unique error code. Use only registered codes. See below.
|
||||
The same unique error_code may be issued at different
|
||||
occasions but those should be equivalent out of the view
|
||||
of a libdax application. (E.g. "cannot open ATA drive"
|
||||
versus "cannot open SCSI drive" would be equivalent.)
|
||||
@param severity The LIBDAX_MSGS_SEV_* of the event.
|
||||
@param priority The LIBDAX_MSGS_PRIO_* number of the event.
|
||||
@param msg_text Printable and human readable message text.
|
||||
@param os_errno Eventual error code from operating system (0 if none)
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@return 1 on success, 0 on rejection, <0 for severe errors
|
||||
*/
|
||||
int libdax_msgs_submit(struct libdax_msgs *m, int driveno, int error_code,
|
||||
int severity, int priority, char *msg_text,
|
||||
int os_errno, int flag);
|
||||
|
||||
|
||||
/* Calls from applications (to be forwarded by libdax/libburn) */
|
||||
|
||||
|
||||
/** Convert a registered severity number into a severity name
|
||||
@param flag Bitfield for control purposes:
|
||||
bit0= list all severity names in a newline separated string
|
||||
@return >0 success, <=0 failure
|
||||
*/
|
||||
int libdax_msgs__sev_to_text(int severity, char **severity_name,
|
||||
int flag);
|
||||
|
||||
|
||||
/** Convert a severity name into a severity number,
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@return >0 success, <=0 failure
|
||||
*/
|
||||
int libdax_msgs__text_to_sev(char *severity_name, int *severity,
|
||||
int flag);
|
||||
|
||||
|
||||
/** Set minimum severity for messages to be queued (default
|
||||
LIBDAX_MSGS_SEV_ALL) and for messages to be printed directly to stderr
|
||||
(default LIBDAX_MSGS_SEV_NEVER).
|
||||
@param print_id A text of at most 80 characters to be printed before
|
||||
any eventually printed message (default is "libdax: ").
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@return always 1 for now
|
||||
*/
|
||||
int libdax_msgs_set_severities(struct libdax_msgs *m, int queue_severity,
|
||||
int print_severity, char *print_id, int flag);
|
||||
|
||||
|
||||
/** Obtain a message item that has at least the given severity and priority.
|
||||
Usually all older messages of lower severity are discarded then. If no
|
||||
item of sufficient severity was found, all others are discarded from the
|
||||
queue.
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@return 1 if a matching item was found, 0 if not, <0 for severe errors
|
||||
*/
|
||||
int libdax_msgs_obtain(struct libdax_msgs *m, struct libdax_msgs_item **item,
|
||||
int severity, int priority, int flag);
|
||||
|
||||
|
||||
/** Destroy a message item obtained by libdax_msgs_obtain(). The submitted
|
||||
pointer gets set to NULL.
|
||||
Caution: Copy eventually obtained msg_text before destroying the item,
|
||||
if you want to use it further.
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@return 1 for success, 0 for pointer to NULL, <0 for severe errors
|
||||
*/
|
||||
int libdax_msgs_destroy_item(struct libdax_msgs *m,
|
||||
struct libdax_msgs_item **item, int flag);
|
||||
|
||||
|
||||
/** Obtain from a message item the three application oriented components as
|
||||
submitted with the originating call of libdax_msgs_submit().
|
||||
Caution: msg_text becomes a pointer into item, not a copy.
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@return 1 on success, 0 on invalid item, <0 for servere errors
|
||||
*/
|
||||
int libdax_msgs_item_get_msg(struct libdax_msgs_item *item,
|
||||
int *error_code, char **msg_text, int *os_errno,
|
||||
int flag);
|
||||
|
||||
|
||||
/** Obtain from a message item the submitter identification submitted
|
||||
with the originating call of libdax_msgs_submit().
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@return 1 on success, 0 on invalid item, <0 for servere errors
|
||||
*/
|
||||
int libdax_msgs_item_get_origin(struct libdax_msgs_item *item,
|
||||
double *timestamp, pid_t *process_id, int *driveno,
|
||||
int flag);
|
||||
|
||||
|
||||
/** Obtain from a message item severity and priority as submitted
|
||||
with the originating call of libdax_msgs_submit().
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@return 1 on success, 0 on invalid item, <0 for servere errors
|
||||
*/
|
||||
int libdax_msgs_item_get_rank(struct libdax_msgs_item *item,
|
||||
int *severity, int *priority, int flag);
|
||||
|
||||
|
||||
#ifdef LIDBAX_MSGS_________________
|
||||
|
||||
|
||||
/* Registered Error Codes */
|
||||
|
||||
|
||||
Format: error_code (LIBDAX_MSGS_SEV_*,LIBDAX_MSGS_PRIO_*) = explanation
|
||||
If no severity or priority are fixely associates, use "(,)".
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Range "libdax_msgs" : 0x00000000 to 0x0000ffff
|
||||
|
||||
0x00000000 (ALL,ZERO) = Initial setting in new libdax_msgs_item
|
||||
0x00000001 (DEBUG,ZERO) = Test error message
|
||||
0x00000002 (DEBUG,ZERO) = Debugging message
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Range "elmom" : 0x00010000 to 0x0001ffff
|
||||
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Range "scdbackup" : 0x00020000 to 0x0002ffff
|
||||
|
||||
Acessing and defending drives:
|
||||
|
||||
0x00020001 (SORRY,LOW) = Cannot open busy device
|
||||
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
|
||||
0x00020006 (FATAL,HIGH) = Too many scsi siblings
|
||||
0x00020007 (NOTE,HIGH) = Closed O_EXCL scsi siblings
|
||||
|
||||
From the hunt on Assert:
|
||||
|
||||
0x00020101 (WARNING,HIGH) = Cannot find given worker item
|
||||
0x00020102 (SORRY,HIGH) = A drive operation is still going on
|
||||
0x00020103 (WARNING,HIGH) = After scan a drive operation is still going on
|
||||
0x00020104 (SORRY,HIGH) = NULL pointer caught
|
||||
0x00020105 (SORRY,HIGH) = Drive is already released
|
||||
0x00020106 (SORRY,HIGH) = Drive is busy on attempt to close
|
||||
0x00020107 (SORRY,HIGH) = Drive is busy on attempt to shut down library
|
||||
0x00020108 (SORRY,HIGH) = Drive is not grabbed on disc status inquiry
|
||||
0x00020108 (FATAL,HIGH) = Could not allocate new drive object
|
||||
0x00020109 (FATAL,HIGH) = Library not running
|
||||
0x0002010a (FATAL,HIGH) = Unsuitable track mode
|
||||
0x0002010b (FATAL,HIGH) = Burn run failed
|
||||
0x0002010c (FATAL,HIGH) = Failed to transfer command to drive
|
||||
0x0002010d (DEBUG,HIGH) = Could not inquire TOC
|
||||
0x0002010e (FATAL,HIGH) = Attempt to read ATIP from ungrabbed drive
|
||||
0x0002010f
|
||||
0x00020110 (FATAL,HIGH) = Persistent drive address too long
|
||||
0x00020111 (FATAL,HIGH) = Could not allocate new auxiliary object
|
||||
0x00020112 (SORRY,HIGH) = Bad combination of write_type and block_type
|
||||
0x00020113 (FATAL,HIGH) = Drive capabilities not inquired yet
|
||||
0x00020114 (SORRY,HIGH) = Attempt to set ISRC with bad data
|
||||
0x00020115 (SORRY,HIGH) = Attempt to set track mode to unusable value
|
||||
0x00020116 (FATAL,HIGH) = Track mode has unusable value
|
||||
0x00020117 (FATAL,HIGH) = toc_entry of drive is already in use
|
||||
|
||||
libdax_audioxtr:
|
||||
0x00020200 (SORRY,HIGH) = Cannot open audio source file
|
||||
0x00020201 (SORRY,HIGH) = Audio source file has unsuitable format
|
||||
0x00020202 (SORRY,HIGH) = Failed to prepare reading of audio data
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
#endif /* LIDBAX_MSGS_________________ */
|
||||
|
||||
|
||||
|
||||
#ifdef LIBDAX_MSGS_H_INTERNAL
|
||||
|
||||
/* Internal Functions */
|
||||
|
||||
|
||||
/** Lock before doing side effect operations on m */
|
||||
static int libdax_msgs_lock(struct libdax_msgs *m, int flag);
|
||||
|
||||
/** Unlock after effect operations on m are done */
|
||||
static int libdax_msgs_unlock(struct libdax_msgs *m, int flag);
|
||||
|
||||
|
||||
/** Create new empty message item.
|
||||
@param link Previous item in queue
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@return >0 success, <=0 failure
|
||||
*/
|
||||
static int libdax_msgs_item_new(struct libdax_msgs_item **item,
|
||||
struct libdax_msgs_item *link, int flag);
|
||||
|
||||
/** Destroy a message item obtained by libdax_msgs_obtain(). The submitted
|
||||
pointer gets set to NULL.
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@return 1 for success, 0 for pointer to NULL
|
||||
*/
|
||||
static int libdax_msgs_item_destroy(struct libdax_msgs_item **item, int flag);
|
||||
|
||||
|
||||
#endif /* LIBDAX_MSGS_H_INTERNAL */
|
||||
|
||||
|
||||
#endif /* ! LIBDAX_MSGS_H_INCLUDED */
|
@ -1,108 +0,0 @@
|
||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
|
||||
#include "message.h"
|
||||
#include "libburn.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
struct message_list
|
||||
{
|
||||
struct message_list *next;
|
||||
|
||||
struct burn_message *msg;
|
||||
};
|
||||
|
||||
static struct message_list *queue;
|
||||
|
||||
void burn_message_free(struct burn_message *msg)
|
||||
{
|
||||
free(msg);
|
||||
}
|
||||
|
||||
void burn_message_clear_queue(void)
|
||||
{
|
||||
struct burn_message *msg;
|
||||
|
||||
if ((msg = burn_get_message())) {
|
||||
burn_print(0,
|
||||
"YOU HAVE MESSAGES QUEUED FROM THE LAST OPERATION. "
|
||||
"YOU SHOULD BE GRABBING THEM ALL!\n");
|
||||
do {
|
||||
burn_message_free(msg);
|
||||
} while ((msg = burn_get_message()));
|
||||
}
|
||||
}
|
||||
|
||||
struct burn_message *burn_get_message()
|
||||
{
|
||||
struct burn_message *msg = NULL;
|
||||
|
||||
if (queue) {
|
||||
struct message_list *next;
|
||||
|
||||
next = queue->next;
|
||||
msg = queue->msg;
|
||||
free(queue);
|
||||
queue = next;
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
static void queue_push_tail(struct burn_message *msg)
|
||||
{
|
||||
struct message_list *node;
|
||||
|
||||
node = malloc(sizeof(struct message_list));
|
||||
node->next = NULL;
|
||||
node->msg = msg;
|
||||
|
||||
if (!queue)
|
||||
queue = node;
|
||||
else {
|
||||
struct message_list *it;
|
||||
|
||||
for (it = queue; it->next; it = it->next) ;
|
||||
it->next = node;
|
||||
}
|
||||
}
|
||||
|
||||
void burn_message_info_new(struct burn_drive *drive,
|
||||
enum burn_message_info message)
|
||||
{
|
||||
struct burn_message *msg;
|
||||
|
||||
msg = malloc(sizeof(struct burn_message));
|
||||
msg->drive = drive;
|
||||
msg->type = BURN_MESSAGE_INFO;
|
||||
msg->detail.info.message = message;
|
||||
|
||||
queue_push_tail(msg);
|
||||
}
|
||||
|
||||
void burn_message_warning_new(struct burn_drive *drive,
|
||||
enum burn_message_info message)
|
||||
{
|
||||
struct burn_message *msg;
|
||||
|
||||
msg = malloc(sizeof(struct burn_message));
|
||||
msg->drive = drive;
|
||||
msg->type = BURN_MESSAGE_WARNING;
|
||||
msg->detail.warning.message = message;
|
||||
|
||||
queue_push_tail(msg);
|
||||
}
|
||||
|
||||
void burn_message_error_new(struct burn_drive *drive,
|
||||
enum burn_message_info message)
|
||||
{
|
||||
struct burn_message *msg;
|
||||
|
||||
msg = malloc(sizeof(struct burn_message));
|
||||
msg->drive = drive;
|
||||
msg->type = BURN_MESSAGE_ERROR;
|
||||
msg->detail.error.message = message;
|
||||
|
||||
queue_push_tail(msg);
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
|
||||
#ifndef __MESSAGE
|
||||
#define __MESSAGE
|
||||
|
||||
#include "libburn.h"
|
||||
|
||||
void burn_message_clear_queue(void);
|
||||
|
||||
void burn_message_info_new(struct burn_drive *drive,
|
||||
enum burn_message_info message);
|
||||
|
||||
void burn_message_warning_new(struct burn_drive *drive,
|
||||
enum burn_message_info message);
|
||||
|
||||
void burn_message_error_new(struct burn_drive *drive,
|
||||
enum burn_message_info message);
|
||||
|
||||
#endif
|
325
libburn/mmc.c
325
libburn/mmc.c
@ -1,6 +1,8 @@
|
||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
|
||||
#include <assert.h>
|
||||
/* ts A61009 */
|
||||
/* #include <a ssert.h> */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
@ -18,6 +20,12 @@
|
||||
#include "structure.h"
|
||||
#include "options.h"
|
||||
|
||||
/* ts A61005 */
|
||||
#include "libdax_msgs.h"
|
||||
extern struct libdax_msgs *libdax_messenger;
|
||||
|
||||
|
||||
|
||||
static unsigned char MMC_GET_TOC[] = { 0x43, 2, 2, 0, 0, 0, 0, 16, 0, 0 };
|
||||
static unsigned char MMC_GET_ATIP[] = { 0x43, 2, 4, 0, 0, 0, 0, 16, 0, 0 };
|
||||
static unsigned char MMC_GET_DISC_INFO[] =
|
||||
@ -39,6 +47,9 @@ static unsigned char MMC_TRACK_INFO[] = { 0x52, 0, 0, 0, 0, 0, 0, 16, 0, 0 };
|
||||
static unsigned char MMC_SEND_CUE_SHEET[] =
|
||||
{ 0x5D, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
/* ts A61023 : get size and free space of drive buffer */
|
||||
static unsigned char MMC_READ_BUFFER_CAPACITY[] = { 0x5C, 0, 0, 0, 0, 0, 0, 16, 0, 0 };
|
||||
|
||||
|
||||
static int mmc_function_spy_do_tell = 0;
|
||||
|
||||
@ -99,19 +110,43 @@ int mmc_get_nwa(struct burn_drive *d)
|
||||
+ (data[14] << 8) + data[15];
|
||||
}
|
||||
|
||||
void mmc_close_disc(struct burn_drive *d, struct burn_write_opts *o)
|
||||
/* ts A61009 : function is obviously unused. */
|
||||
/* void mmc_close_disc(struct burn_drive *d, struct burn_write_opts *o) */
|
||||
void mmc_close_disc(struct burn_write_opts *o)
|
||||
{
|
||||
struct burn_drive *d;
|
||||
|
||||
mmc_function_spy("mmc_close_disc");
|
||||
assert(o->drive == d);
|
||||
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
|
||||
"HOW THAT ? mmc_close_disc() was called", 0, 0);
|
||||
|
||||
/* ts A61009 : made impossible by removing redundant parameter d */
|
||||
/* a ssert(o->drive == d); */
|
||||
d = o->drive;
|
||||
|
||||
o->multi = 0;
|
||||
spc_select_write_params(d, o);
|
||||
mmc_close(d, 1, 0);
|
||||
}
|
||||
|
||||
void mmc_close_session(struct burn_drive *d, struct burn_write_opts *o)
|
||||
/* ts A61009 : function is obviously unused. */
|
||||
/* void mmc_close_session(struct burn_drive *d, struct burn_write_opts *o) */
|
||||
void mmc_close_session(struct burn_write_opts *o)
|
||||
{
|
||||
struct burn_drive *d;
|
||||
|
||||
mmc_function_spy("mmc_close_session");
|
||||
assert(o->drive == d);
|
||||
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
|
||||
"HOW THAT ? mmc_close_session() was called", 0, 0);
|
||||
|
||||
/* ts A61009 : made impossible by removing redundant parameter d */
|
||||
/* a ssert(o->drive == d); */
|
||||
d = o->drive;
|
||||
|
||||
o->multi = 3;
|
||||
spc_select_write_params(d, o);
|
||||
mmc_close(d, 1, 0);
|
||||
@ -121,7 +156,12 @@ void mmc_close(struct burn_drive *d, int session, int track)
|
||||
{
|
||||
struct command c;
|
||||
|
||||
mmc_function_spy("mmc_close_session");
|
||||
mmc_function_spy("mmc_close");
|
||||
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
|
||||
"HOW THAT ? mmc_close() was called", 0, 0);
|
||||
|
||||
c.retry = 1;
|
||||
c.oplen = sizeof(MMC_CLOSE);
|
||||
memcpy(c.opcode, MMC_CLOSE, sizeof(MMC_CLOSE));
|
||||
@ -154,6 +194,7 @@ void mmc_get_event(struct burn_drive *d)
|
||||
c.page->data[5], c.page->data[6], c.page->data[7]);
|
||||
}
|
||||
|
||||
|
||||
void mmc_write_12(struct burn_drive *d, int start, struct buffer *buf)
|
||||
{
|
||||
struct command c;
|
||||
@ -161,7 +202,10 @@ void mmc_write_12(struct burn_drive *d, int start, struct buffer *buf)
|
||||
|
||||
mmc_function_spy("mmc_write_12");
|
||||
len = buf->sectors;
|
||||
assert(buf->bytes >= buf->sectors); /* can be == at 0... */
|
||||
|
||||
/* ts A61009 */
|
||||
/* a ssert(buf->bytes >= buf->sectors);*/ /* can be == at 0... */
|
||||
|
||||
burn_print(100, "trying to write %d at %d\n", len, start);
|
||||
memcpy(c.opcode, MMC_WRITE_12, sizeof(MMC_WRITE_12));
|
||||
c.retry = 1;
|
||||
@ -195,7 +239,10 @@ int mmc_write(struct burn_drive *d, int start, struct buffer *buf)
|
||||
return BE_CANCELLED;
|
||||
|
||||
len = buf->sectors;
|
||||
assert(buf->bytes >= buf->sectors); /* can be == at 0... */
|
||||
|
||||
/* ts A61009 : buffer fill problems are to be handled by caller */
|
||||
/* a ssert(buf->bytes >= buf->sectors);*/ /* can be == at 0... */
|
||||
|
||||
burn_print(100, "trying to write %d at %d\n", len, start);
|
||||
memcpy(c.opcode, MMC_WRITE_10, sizeof(MMC_WRITE_10));
|
||||
c.retry = 1;
|
||||
@ -228,7 +275,7 @@ void mmc_read_toc(struct burn_drive *d)
|
||||
struct buffer buf;
|
||||
struct command c;
|
||||
int dlen;
|
||||
int i;
|
||||
int i, bpl= 12;
|
||||
unsigned char *tdata;
|
||||
|
||||
mmc_function_spy("mmc_read_toc");
|
||||
@ -242,7 +289,23 @@ void mmc_read_toc(struct burn_drive *d)
|
||||
d->issue_command(d, &c);
|
||||
|
||||
if (c.error) {
|
||||
|
||||
/* ts A61020 : this snaps on non-blank DVD media */
|
||||
/* Very unsure wether this old measure is ok.
|
||||
Obviously higher levels do not care about this.
|
||||
DVD+RW burns go on after passing through here.
|
||||
|
||||
d->busy = BURN_DRIVE_IDLE;
|
||||
*/
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x0002010d,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Could not inquire TOC (non-blank DVD media ?)", 0,0);
|
||||
d->status = BURN_DISC_UNSUITABLE;
|
||||
d->toc_entries = 0;
|
||||
/* Prefering memory leaks over fandangos */
|
||||
d->toc_entry = malloc(sizeof(struct burn_toc_entry));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -251,7 +314,8 @@ void mmc_read_toc(struct burn_drive *d)
|
||||
/*
|
||||
some drives fail this check.
|
||||
|
||||
assert(((dlen - 2) % 11) == 0);
|
||||
ts A61007 : if re-enabled then not via Assert.
|
||||
a ssert(((dlen - 2) % 11) == 0);
|
||||
*/
|
||||
d->toc_entry = malloc(d->toc_entries * sizeof(struct burn_toc_entry));
|
||||
tdata = c.page->data + 4;
|
||||
@ -265,14 +329,27 @@ void mmc_read_toc(struct burn_drive *d)
|
||||
burn_disc_add_session(d->disc, session, BURN_POS_END);
|
||||
burn_session_free(session);
|
||||
}
|
||||
|
||||
/* ts A61022 */
|
||||
burn_print(bpl, "-----------------------------------\n");
|
||||
|
||||
for (i = 0; i < d->toc_entries; i++, tdata += 11) {
|
||||
burn_print(12, "S %d, PT %d, TNO %d : ", tdata[0], tdata[3],
|
||||
|
||||
/* ts A61022: was burn_print level 12 */
|
||||
burn_print(bpl, "S %d, PT %2.2Xh, TNO %d :", tdata[0],tdata[3],
|
||||
tdata[2]);
|
||||
burn_print(12, "(%d:%d:%d)", tdata[8], tdata[9], tdata[10]);
|
||||
burn_print(12, "A(%d:%d:%d)", tdata[4], tdata[5], tdata[6]);
|
||||
burn_print(12, " - control %d, adr %d\n", tdata[1] & 0xF,
|
||||
burn_print(bpl, " MSF(%d:%d:%d)", tdata[4],tdata[5],tdata[6]);
|
||||
burn_print(bpl, " PMSF(%d:%d:%d %d)",
|
||||
tdata[8], tdata[9], tdata[10],
|
||||
burn_msf_to_lba(tdata[8], tdata[9], tdata[10])
|
||||
);
|
||||
burn_print(bpl, " - control %d, adr %d\n", tdata[1] & 0xF,
|
||||
tdata[1] >> 4);
|
||||
|
||||
/*
|
||||
fprintf(stderr, "libburn_experimental: toc entry #%d : %d %d %d\n",i,tdata[8], tdata[9], tdata[10]);
|
||||
*/
|
||||
|
||||
if (tdata[3] == 1) {
|
||||
if (burn_msf_to_lba(tdata[8], tdata[9], tdata[10])) {
|
||||
d->disc->session[0]->hidefirst = 1;
|
||||
@ -311,6 +388,10 @@ void mmc_read_toc(struct burn_drive *d)
|
||||
d->disc->session[tdata[0] - 1]->leadout_entry =
|
||||
&d->toc_entry[i];
|
||||
}
|
||||
|
||||
/* ts A61022 */
|
||||
burn_print(bpl, "-----------------------------------\n");
|
||||
|
||||
if (d->status != BURN_DISC_APPENDABLE)
|
||||
d->status = BURN_DISC_FULL;
|
||||
toc_find_modes(d);
|
||||
@ -339,11 +420,26 @@ void mmc_read_disc_info(struct burn_drive *d)
|
||||
|
||||
data = c.page->data;
|
||||
d->erasable = !!(data[2] & 16);
|
||||
|
||||
/* ts A61020 */
|
||||
d->start_lba = d->end_lba = -2000000000;
|
||||
|
||||
/*
|
||||
fprintf(stderr, "libburn_experimental: data[2]= %d 0x%x\n",
|
||||
(unsigned) data[2], (unsigned) data[2]);
|
||||
*/
|
||||
switch (data[2] & 3) {
|
||||
case 0:
|
||||
d->toc_entries = 0;
|
||||
d->start_lba = burn_msf_to_lba(data[17], data[18], data[19]);
|
||||
d->end_lba = burn_msf_to_lba(data[21], data[22], data[23]);
|
||||
|
||||
/*
|
||||
fprintf(stderr, "libburn_experimental: start_lba = %d (%d %d %d) , end_lba = %d (%d %d %d)\n",
|
||||
d->start_lba, data[17], data[18], data[19],
|
||||
d->end_lba, data[21], data[22], data[23]);
|
||||
*/
|
||||
|
||||
d->status = BURN_DISC_BLANK;
|
||||
break;
|
||||
case 1:
|
||||
@ -359,6 +455,17 @@ void mmc_read_atip(struct burn_drive *d)
|
||||
struct buffer buf;
|
||||
struct command c;
|
||||
|
||||
/* ts A61021 */
|
||||
unsigned char *data;
|
||||
/* Speed values from A1:
|
||||
With 4 cdrecord tells "10" or "8" where MMC-1 says "8".
|
||||
cdrecord "8" appear on 4xCD-RW and thus seem to be quite invalid.
|
||||
My CD-R (>=24 speed) tell no A1.
|
||||
The higher non-MMC-1 values are hearsay.
|
||||
*/
|
||||
static int speed_value[16]= { 0, 2, 4, 6, 10, -5, 16, -7,
|
||||
24, 32, 40, 48, -12, -13, -14, -15};
|
||||
|
||||
mmc_function_spy("mmc_read_atip");
|
||||
memcpy(c.opcode, MMC_GET_ATIP, sizeof(MMC_GET_ATIP));
|
||||
c.retry = 1;
|
||||
@ -370,6 +477,125 @@ void mmc_read_atip(struct burn_drive *d)
|
||||
c.dir = FROM_DRIVE;
|
||||
d->issue_command(d, &c);
|
||||
burn_print(1, "atip shit for you\n");
|
||||
|
||||
|
||||
/* ts A61021 */
|
||||
data = c.page->data;
|
||||
d->erasable= !!(data[6]&64);
|
||||
d->start_lba= burn_msf_to_lba(data[8],data[9],data[10]);
|
||||
d->end_lba= burn_msf_to_lba(data[12],data[13],data[14]);
|
||||
if (data[6]&4) {
|
||||
if (speed_value[(data[16]>>4)&7] > 0)
|
||||
d->mdata->min_write_speed =
|
||||
speed_value[(data[16]>>4)&7]*176;
|
||||
if (speed_value[(data[16])&15] > 0)
|
||||
d->mdata->max_write_speed =
|
||||
speed_value[(data[16])&15]*176;
|
||||
}
|
||||
|
||||
#ifdef Burn_mmc_be_verbous_about_atiP
|
||||
{ int i;
|
||||
fprintf(stderr,"libburn_experimental: Returned ATIP Data\n");
|
||||
for(i= 0; i<28; i++)
|
||||
fprintf(stderr,"%3.3d (0x%2.2x)%s",
|
||||
data[i],data[i],((i+1)%5 ? " ":"\n"));
|
||||
fprintf(stderr,"\n");
|
||||
|
||||
fprintf(stderr,
|
||||
"libburn_experimental: Indicative Target Writing Power= %d\n",
|
||||
(data[4]>>4)&7);
|
||||
fprintf(stderr,
|
||||
"libburn_experimental: Reference speed= %d ->%d\n",
|
||||
data[4]&7, speed_value[data[4]&7]);
|
||||
fprintf(stderr,
|
||||
"libburn_experimental: Is %sunrestricted\n",
|
||||
(data[5]&64?"":"not "));
|
||||
fprintf(stderr,
|
||||
"libburn_experimental: Is %serasable, sub-type %d\n",
|
||||
(data[6]&64?"":"not "),(data[6]>>3)&3);
|
||||
fprintf(stderr,
|
||||
"libburn_experimental: lead in: %d (%-2.2d:%-2.2d/%-2.2d)\n",
|
||||
burn_msf_to_lba(data[8],data[9],data[10]),
|
||||
data[8],data[9],data[10]);
|
||||
fprintf(stderr,
|
||||
"libburn_experimental: lead out: %d (%-2.2d:%-2.2d/%-2.2d)\n",
|
||||
burn_msf_to_lba(data[12],data[13],data[14]),
|
||||
data[12],data[13],data[14]);
|
||||
if(data[6]&4)
|
||||
fprintf(stderr,
|
||||
"libburn_experimental: A1 speed low %d speed high %d\n",
|
||||
speed_value[(data[16]>>4)&7], speed_value[(data[16])&7]);
|
||||
if(data[6]&2)
|
||||
fprintf(stderr,
|
||||
"libburn_experimental: A2 speed low %d speed high %d\n",
|
||||
speed_value[(data[20]>>4)&7], speed_value[(data[20])&7]);
|
||||
if(data[6]&1)
|
||||
fprintf(stderr,
|
||||
"libburn_experimental: A3 speed low %d speed high %d\n",
|
||||
speed_value[(data[24]>>4)&7], speed_value[(data[24])&7]);
|
||||
}
|
||||
|
||||
#endif /* Burn_mmc_be_verbous_about_atiP */
|
||||
|
||||
/* ts A61020
|
||||
http://www.t10.org/ftp/t10/drafts/mmc/mmc-r10a.pdf , table 77 :
|
||||
|
||||
0 ATIP Data Length MSB
|
||||
1 ATIP Data Length LSB
|
||||
2 Reserved
|
||||
3 Reserved
|
||||
4 bit7=1, bit4-6="Indicative Target Writing Power", bit3=reserved ,
|
||||
bit0-2="Reference speed"
|
||||
5 bit7=0, bit6="URU" , bit0-5=reserved
|
||||
6 bit7=1, bit6="Disc Type", bit3-4="Disc Sub-Type",
|
||||
bit2="A1", bit1="A2", bit0="A3"
|
||||
7 reserved
|
||||
8 ATIP Start Time of lead-in (Min)
|
||||
9 ATIP Start Time of lead-in (Sec)
|
||||
10 ATIP Start Time of lead-in (Frame)
|
||||
11 reserved
|
||||
12 ATIP Last Possible Start Time of lead-out (Min)
|
||||
13 ATIP Last Possible Start Time of lead-out (Sec)
|
||||
14 ATIP Last Possible Start Time of lead-out (Frame)
|
||||
15 reserved
|
||||
16 bit7=0, bit4-6="Lowest Usable CLV Recording speed"
|
||||
bit0-3="Highest Usable CLV Recording speed"
|
||||
17 bit7=0, bit4-6="Power Multiplication Factor p",
|
||||
bit1-3="Target y value of the Modulation/Power function", bit0=reserved
|
||||
18 bit7=1, bit4-6="Recommended Erase/Write Power Ratio (P(inf)/W(inf))"
|
||||
bit0-3=reserved
|
||||
19 reserved
|
||||
20-22 A2 Values
|
||||
23 reserved
|
||||
24-26 A3 Values
|
||||
27 reserved
|
||||
|
||||
Disc Type - zero indicates CD-R media; one indicates CD-RW media.
|
||||
|
||||
Disc Sub-Type - shall be set to zero.
|
||||
|
||||
A1 - when set to one, indicates that bytes 16-18 are valid.
|
||||
|
||||
Lowest Usable CLV Recording Speed
|
||||
000b Reserved
|
||||
001b 2X
|
||||
010b - 111b Reserved
|
||||
|
||||
Highest CLV Recording Speeds
|
||||
000b Reserved
|
||||
001b 2X
|
||||
010b 4X
|
||||
011b 6X
|
||||
100b 8X
|
||||
101b - 111b Reserved
|
||||
|
||||
MMC-3 seems to recommend MODE SENSE (5Ah) page 2Ah rather than A1, A2, A3.
|
||||
This page is loaded in libburn function spc_sense_caps() .
|
||||
Speed is given in kbytes/sec there. But i suspect this to be independent
|
||||
of media. So one would habe to associate the speed descriptor blocks with
|
||||
the ATIP media characteristics ? How ?
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
void mmc_read_sectors(struct burn_drive *d,
|
||||
@ -382,9 +608,14 @@ void mmc_read_sectors(struct burn_drive *d,
|
||||
struct command c;
|
||||
|
||||
mmc_function_spy("mmc_read_sectors");
|
||||
assert(len >= 0);
|
||||
/* if the drive isn't busy, why the hell are we here? */
|
||||
assert(d->busy);
|
||||
|
||||
/* ts A61009 : to be ensured by callers */
|
||||
/* a ssert(len >= 0); */
|
||||
|
||||
/* if the drive isn't busy, why the hell are we here? */
|
||||
/* ts A61006 : i second that question */
|
||||
/* a ssert(d->busy); */
|
||||
|
||||
burn_print(12, "reading %d from %d\n", len, start);
|
||||
memcpy(c.opcode, MMC_READ_CD, sizeof(MMC_READ_CD));
|
||||
c.retry = 1;
|
||||
@ -542,3 +773,63 @@ void mmc_sync_cache(struct burn_drive *d)
|
||||
c.dir = NO_TRANSFER;
|
||||
d->issue_command(d, &c);
|
||||
}
|
||||
|
||||
|
||||
/* ts A61023 : http://libburn.pykix.org/ticket/14
|
||||
get size and free space of drive buffer
|
||||
*/
|
||||
int mmc_read_buffer_capacity(struct burn_drive *d)
|
||||
{
|
||||
struct buffer buf;
|
||||
struct command c;
|
||||
unsigned char *data;
|
||||
|
||||
mmc_function_spy("mmc_read_buffer_capacity");
|
||||
memcpy(c.opcode, MMC_READ_BUFFER_CAPACITY,
|
||||
sizeof(MMC_READ_BUFFER_CAPACITY));
|
||||
c.retry = 1;
|
||||
c.oplen = sizeof(MMC_READ_BUFFER_CAPACITY);
|
||||
c.page = &buf;
|
||||
c.page->bytes = 0;
|
||||
c.page->sectors = 0;
|
||||
|
||||
c.dir = FROM_DRIVE;
|
||||
d->issue_command(d, &c);
|
||||
|
||||
/* >>> ??? error diagnostics */
|
||||
|
||||
data = c.page->data;
|
||||
|
||||
d->progress.buffer_capacity =
|
||||
(data[4]<<24)|(data[5]<<16)|(data[6]<<8)|data[7];
|
||||
d->progress.buffer_available =
|
||||
(data[8]<<24)|(data[9]<<16)|(data[10]<<8)|data[11];
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ts A61021 : the mmc specific part of sg.c:enumerate_common()
|
||||
*/
|
||||
int mmc_setup_drive(struct burn_drive *d)
|
||||
{
|
||||
d->read_atip = mmc_read_atip;
|
||||
d->read_toc = mmc_read_toc;
|
||||
d->write = mmc_write;
|
||||
d->erase = mmc_erase;
|
||||
d->read_sectors = mmc_read_sectors;
|
||||
d->perform_opc = mmc_perform_opc;
|
||||
d->set_speed = mmc_set_speed;
|
||||
d->send_cue_sheet = mmc_send_cue_sheet;
|
||||
d->sync_cache = mmc_sync_cache;
|
||||
d->get_nwa = mmc_get_nwa;
|
||||
d->close_disc = mmc_close_disc;
|
||||
d->close_session = mmc_close_session;
|
||||
d->read_buffer_capacity = mmc_read_buffer_capacity;
|
||||
|
||||
/* ts A61020 */
|
||||
d->start_lba= -2000000000;
|
||||
d->end_lba= -2000000000;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -12,8 +12,13 @@ struct cue_sheet;
|
||||
/* MMC commands */
|
||||
|
||||
void mmc_read(struct burn_drive *);
|
||||
void mmc_close_session(struct burn_drive *, struct burn_write_opts *);
|
||||
void mmc_close_disc(struct burn_drive *, struct burn_write_opts *);
|
||||
|
||||
/* ts A61009 : removed redundant parameter d in favor of o->drive */
|
||||
/* void mmc_close_session(struct burn_drive *, struct burn_write_opts *); */
|
||||
/* void mmc_close_disc(struct burn_drive *, struct burn_write_opts *); */
|
||||
void mmc_close_session(struct burn_write_opts *o);
|
||||
void mmc_close_disc(struct burn_write_opts *o);
|
||||
|
||||
void mmc_close(struct burn_drive *, int session, int track);
|
||||
void mmc_get_event(struct burn_drive *);
|
||||
int mmc_write(struct burn_drive *, int start, struct buffer *buf);
|
||||
@ -34,4 +39,12 @@ void mmc_perform_opc(struct burn_drive *);
|
||||
void mmc_get_configuration(struct burn_drive *);
|
||||
int mmc_get_nwa(struct burn_drive *);
|
||||
void mmc_send_cue_sheet(struct burn_drive *, struct cue_sheet *);
|
||||
|
||||
/* ts A61023 : get size and free space of drive buffer */
|
||||
int mmc_read_buffer_capacity(struct burn_drive *d);
|
||||
|
||||
/* ts A61021 : the mmc specific part of sg.c:enumerate_common()
|
||||
*/
|
||||
int mmc_setup_drive(struct burn_drive *d);
|
||||
|
||||
#endif /*__MMC*/
|
||||
|
@ -2,14 +2,27 @@
|
||||
#include "options.h"
|
||||
#include "transport.h"
|
||||
|
||||
#include <assert.h>
|
||||
/* ts A61007 */
|
||||
/* #include <a ssert.h> */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libdax_msgs.h"
|
||||
extern struct libdax_msgs *libdax_messenger;
|
||||
|
||||
|
||||
struct burn_write_opts *burn_write_opts_new(struct burn_drive *drive)
|
||||
{
|
||||
struct burn_write_opts *opts;
|
||||
|
||||
opts = malloc(sizeof(struct burn_write_opts));
|
||||
if (opts == NULL) {
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020111,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Could not allocate new auxiliary object", 0, 0);
|
||||
return NULL;
|
||||
}
|
||||
opts->drive = drive;
|
||||
opts->refcount = 1;
|
||||
opts->write_type = BURN_WRITE_TAO;
|
||||
@ -61,14 +74,32 @@ int burn_write_opts_set_write_type(struct burn_write_opts *opts,
|
||||
enum burn_write_types write_type,
|
||||
int block_type)
|
||||
{
|
||||
if ((write_type == BURN_WRITE_SAO && block_type == BURN_BLOCK_SAO) ||
|
||||
(opts->drive->block_types[write_type] & block_type)) {
|
||||
opts->write_type = write_type;
|
||||
opts->block_type = block_type;
|
||||
return 1;
|
||||
int sector_get_outmode(enum burn_write_types write_type,
|
||||
enum burn_block_types block_type);
|
||||
int spc_block_type(enum burn_block_types b);
|
||||
|
||||
/* ts A61007 */
|
||||
if (! ( (write_type == BURN_WRITE_SAO && block_type == BURN_BLOCK_SAO)
|
||||
|| (opts->drive->block_types[write_type] & block_type) ) ) {
|
||||
bad_combination:;
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020112,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Bad combination of write_type and block_type", 0, 0);
|
||||
return 0;
|
||||
}
|
||||
assert(0);
|
||||
return 0;
|
||||
/* ts A61007 : obsoleting Assert in sector.c:get_outmode() */
|
||||
if (sector_get_outmode(write_type, (enum burn_block_types) block_type)
|
||||
== -1)
|
||||
goto bad_combination;
|
||||
/* ts A61007 : obsoleting Assert in spc.c:spc_block_type() */
|
||||
if (spc_block_type((enum burn_block_types) block_type) == -1)
|
||||
goto bad_combination;
|
||||
|
||||
opts->write_type = write_type;
|
||||
opts->block_type = block_type;
|
||||
return 1;
|
||||
|
||||
/* a ssert(0); */
|
||||
}
|
||||
|
||||
void burn_write_opts_set_toc_entries(struct burn_write_opts *opts, int count,
|
||||
|
@ -1,9 +1,14 @@
|
||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
|
||||
#include <malloc.h>
|
||||
/* #include <m alloc.h> ts A61013 : not in Linux man 3 malloc */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* ts A61007 */
|
||||
/* #include <a ssert.h> */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
@ -11,7 +16,11 @@
|
||||
#include "libburn.h"
|
||||
#include "drive.h"
|
||||
#include "transport.h"
|
||||
|
||||
/* ts A60925 : obsoleted by libdax_msgs.h
|
||||
#include "message.h"
|
||||
*/
|
||||
|
||||
#include "crc.h"
|
||||
#include "debug.h"
|
||||
#include "init.h"
|
||||
@ -33,11 +42,16 @@ void burn_disc_read(struct burn_drive *d, const struct burn_read_opts *o)
|
||||
struct buffer page;
|
||||
int speed;
|
||||
|
||||
assert((o->version & 0xfffff000) == (OPTIONS_VERSION & 0xfffff000));
|
||||
/* ts A61007 : if this function gets revived, then these
|
||||
tests have to be done more graceful */
|
||||
a ssert((o->version & 0xfffff000) == (OPTIONS_VERSION & 0xfffff000));
|
||||
a ssert(!d->busy);
|
||||
a ssert(d->toc->valid);
|
||||
a ssert(o->datafd != -1);
|
||||
|
||||
/* moved up from spc_select_error_params alias d->send_parameters() */
|
||||
a ssert(d->mdata->valid);
|
||||
|
||||
assert(!d->busy);
|
||||
assert(d->toc->valid);
|
||||
assert(o->datafd != -1);
|
||||
/* XXX not sure this is a good idea. copy it? */
|
||||
/* XXX also, we have duplicated data now, do we remove the fds from struct
|
||||
drive, or only store a subset of the _opts structs in drives */
|
||||
@ -47,6 +61,7 @@ drive, or only store a subset of the _opts structs in drives */
|
||||
d->set_speed(d, speed, 0);
|
||||
|
||||
d->params.retries = o->hardware_error_retries;
|
||||
|
||||
d->send_parameters(d, o);
|
||||
|
||||
d->cancel = 0;
|
||||
@ -124,7 +139,10 @@ drive, or only store a subset of the _opts structs in drives */
|
||||
page.sectors = (finish < maxsects) ? finish : maxsects;
|
||||
printf("reading %d sectors from %d\n", page.sectors,
|
||||
drive_lba);
|
||||
d->read_sectors(d, drive_lba, page.sectors, o, &page);
|
||||
|
||||
/* >>> ts A61009 : ensure page.sectors >= 0 before calling */
|
||||
d->r ead_sectors(d, drive_lba, page.sectors, o, &page);
|
||||
|
||||
printf("Read %d\n", page.sectors);
|
||||
}
|
||||
#endif
|
||||
|
@ -2,9 +2,7 @@
|
||||
|
||||
/* scsi block commands */
|
||||
|
||||
#include <scsi/scsi.h>
|
||||
#include <string.h>
|
||||
#include <scsi/sg.h>
|
||||
|
||||
#include "transport.h"
|
||||
#include "sbc.h"
|
||||
@ -38,3 +36,13 @@ void sbc_eject(struct burn_drive *d)
|
||||
c.dir = NO_TRANSFER;
|
||||
d->issue_command(d, &c);
|
||||
}
|
||||
|
||||
/* ts A61021 : the sbc specific part of sg.c:enumerate_common()
|
||||
*/
|
||||
int sbc_setup_drive(struct burn_drive *d)
|
||||
{
|
||||
d->eject = sbc_eject;
|
||||
d->load = sbc_load;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -8,4 +8,8 @@ struct burn_drive;
|
||||
void sbc_load(struct burn_drive *);
|
||||
void sbc_eject(struct burn_drive *);
|
||||
|
||||
/* ts A61021 : the sbc specific part of sg.c:enumerate_common()
|
||||
*/
|
||||
int sbc_setup_drive(struct burn_drive *d);
|
||||
|
||||
#endif /* __SBC */
|
||||
|
163
libburn/sector.c
163
libburn/sector.c
@ -1,7 +1,10 @@
|
||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* ts A61010 */
|
||||
/* #include <a ssert.h> */
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include "error.h"
|
||||
@ -37,13 +40,14 @@ static void uncook_subs(unsigned char *dest, unsigned char *source)
|
||||
}
|
||||
}
|
||||
|
||||
/* 0 means "same as inmode" */
|
||||
static int get_outmode(struct burn_write_opts *o)
|
||||
/* @return >=0 : valid , <0 invalid */
|
||||
int sector_get_outmode(enum burn_write_types write_type,
|
||||
enum burn_block_types block_type)
|
||||
{
|
||||
if (o->write_type == BURN_WRITE_SAO)
|
||||
if (write_type == BURN_WRITE_SAO)
|
||||
return 0;
|
||||
else
|
||||
switch (o->block_type) {
|
||||
switch (block_type) {
|
||||
case BURN_BLOCK_RAW0:
|
||||
return BURN_MODE_RAW;
|
||||
case BURN_BLOCK_RAW16:
|
||||
@ -54,13 +58,28 @@ static int get_outmode(struct burn_write_opts *o)
|
||||
return BURN_MODE_RAW | BURN_SUBCODE_R96;
|
||||
case BURN_BLOCK_MODE1:
|
||||
return BURN_MODE1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
assert(0); /* return BURN_MODE_UNIMPLEMENTED :) */
|
||||
|
||||
/* ts A61007 : now handled in burn_write_opts_set_write_type() */
|
||||
/* a ssert(0); */ /* return BURN_MODE_UNIMPLEMENTED :) */
|
||||
}
|
||||
|
||||
/* 0 means "same as inmode" */
|
||||
static int get_outmode(struct burn_write_opts *o)
|
||||
{
|
||||
/* ts A61007 */
|
||||
return sector_get_outmode(o->write_type, o->block_type);
|
||||
|
||||
/* -1 is prevented by check in burn_write_opts_set_write_type() */
|
||||
/* a ssert(0); */ /* return BURN_MODE_UNIMPLEMENTED :) */
|
||||
}
|
||||
|
||||
|
||||
static void get_bytes(struct burn_track *track, int count, unsigned char *data)
|
||||
{
|
||||
int valid, shortage, curr;
|
||||
int valid, shortage, curr, i, tr;
|
||||
|
||||
/* no track pointer means we're just generating 0s */
|
||||
if (!track) {
|
||||
@ -80,7 +99,7 @@ static void get_bytes(struct burn_track *track, int count, unsigned char *data)
|
||||
shortage = count - valid;
|
||||
|
||||
if (!shortage)
|
||||
return;
|
||||
goto ex;
|
||||
|
||||
/* Next we use source data */
|
||||
curr = valid;
|
||||
@ -97,7 +116,7 @@ static void get_bytes(struct burn_track *track, int count, unsigned char *data)
|
||||
shortage = count - curr;
|
||||
|
||||
if (!shortage)
|
||||
return;
|
||||
goto ex;
|
||||
|
||||
/* Before going to the next track, we run through any tail */
|
||||
|
||||
@ -113,7 +132,7 @@ static void get_bytes(struct burn_track *track, int count, unsigned char *data)
|
||||
shortage -= valid;
|
||||
|
||||
if (!shortage)
|
||||
return;
|
||||
goto ex;
|
||||
|
||||
/* If we're still short, and there's a "next" pointer, we pull from that.
|
||||
if that depletes, we'll just fill with 0s.
|
||||
@ -128,10 +147,30 @@ static void get_bytes(struct burn_track *track, int count, unsigned char *data)
|
||||
curr += valid;
|
||||
}
|
||||
}
|
||||
if (!shortage)
|
||||
return;
|
||||
memset(data + curr, 0, shortage);
|
||||
ex:;
|
||||
/* ts A61024 : general finalizing processing */
|
||||
if(shortage)
|
||||
memset(data + curr, 0, shortage); /* this is old icculus.org */
|
||||
if (track->swap_source_bytes == 1) {
|
||||
|
||||
/*
|
||||
{ static int swapping_count= 0;
|
||||
fprintf(stderr,"\rlibburn_debug: swapping #%d \r",
|
||||
swapping_count);
|
||||
swapping_count++;
|
||||
}
|
||||
*/
|
||||
|
||||
for (i = 1; i < count; i += 2) {
|
||||
tr = data[i];
|
||||
data[i] = data[i-1];
|
||||
data[i-1] = tr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ts A61009 : seems to hand out sector start pointer in opts->drive->buffer
|
||||
and to count hand outs as well as reserved bytes */
|
||||
static unsigned char *get_sector(struct burn_write_opts *opts, int inmode)
|
||||
{
|
||||
struct burn_drive *d = opts->drive;
|
||||
@ -144,7 +183,13 @@ static unsigned char *get_sector(struct burn_write_opts *opts, int inmode)
|
||||
if (outmode == 0)
|
||||
outmode = inmode;
|
||||
|
||||
seclen = burn_sector_length(outmode) + burn_subcode_length(outmode);
|
||||
/* ts A61009 : react on eventual failure of burn_sector_length()
|
||||
(should not happen if API tested properly).
|
||||
Ensures out->bytes >= out->sectors */
|
||||
seclen = burn_sector_length(outmode);
|
||||
if (seclen <= 0)
|
||||
return NULL;
|
||||
seclen += burn_subcode_length(outmode);
|
||||
|
||||
if (out->bytes + (seclen) >= BUFFER_SIZE) {
|
||||
int err;
|
||||
@ -164,7 +209,9 @@ static unsigned char *get_sector(struct burn_write_opts *opts, int inmode)
|
||||
}
|
||||
|
||||
/* either inmode == outmode, or outmode == raw. anything else is bad news */
|
||||
static void convert_data(struct burn_write_opts *o, struct burn_track *track,
|
||||
/* ts A61010 : changed type to int in order to propagate said bad news */
|
||||
/** @return 1 is ok, <= 0 is failure */
|
||||
static int convert_data(struct burn_write_opts *o, struct burn_track *track,
|
||||
int inmode, unsigned char *data)
|
||||
{
|
||||
int outlen, inlen;
|
||||
@ -177,14 +224,21 @@ static void convert_data(struct burn_write_opts *o, struct burn_track *track,
|
||||
|
||||
outlen = burn_sector_length(outmode);
|
||||
inlen = burn_sector_length(inmode);
|
||||
assert(outlen >= inlen);
|
||||
|
||||
/* ts A61010 */
|
||||
/* a ssert(outlen >= inlen); */
|
||||
if (outlen < inlen)
|
||||
return 0;
|
||||
|
||||
if ((outmode & BURN_MODE_BITS) == (inmode & BURN_MODE_BITS)) {
|
||||
get_bytes(track, inlen, data);
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert(outmode & BURN_MODE_RAW);
|
||||
/* ts A61010 */
|
||||
/* a ssert(outmode & BURN_MODE_RAW); */
|
||||
if (!(outmode & BURN_MODE_RAW))
|
||||
return 0;
|
||||
|
||||
if (inmode & BURN_MODE1)
|
||||
offset = 16;
|
||||
@ -192,9 +246,16 @@ static void convert_data(struct burn_write_opts *o, struct burn_track *track,
|
||||
offset = 0;
|
||||
if (inmode & BURN_AUDIO)
|
||||
offset = 0;
|
||||
assert(offset != -1);
|
||||
|
||||
/* ts A61010 */
|
||||
/* a ssert(offset != -1); */
|
||||
if (offset == -1)
|
||||
return 0;
|
||||
|
||||
get_bytes(track, inlen, data + offset);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void convert_subs(struct burn_write_opts *o, int inmode,
|
||||
unsigned char *subs, unsigned char *sector)
|
||||
{
|
||||
@ -275,9 +336,11 @@ int sector_toc(struct burn_write_opts *o, int mode)
|
||||
unsigned char subs[96];
|
||||
|
||||
data = get_sector(o, mode);
|
||||
if (!data)
|
||||
if (data == NULL)
|
||||
return 0;
|
||||
/* ts A61010 */
|
||||
if (convert_data(o, NULL, mode, data) <= 0)
|
||||
return 0;
|
||||
convert_data(o, NULL, mode, data);
|
||||
subcode_toc(d, mode, subs);
|
||||
convert_subs(o, mode, subs, data);
|
||||
sector_headers(o, data, mode, 1);
|
||||
@ -293,9 +356,11 @@ int sector_pregap(struct burn_write_opts *o,
|
||||
unsigned char subs[96];
|
||||
|
||||
data = get_sector(o, mode);
|
||||
if (!data)
|
||||
if (data == NULL)
|
||||
return 0;
|
||||
/* ts A61010 */
|
||||
if (convert_data(o, NULL, mode, data) <= 0)
|
||||
return 0;
|
||||
convert_data(o, NULL, mode, data);
|
||||
subcode_user(o, subs, tno, control, 0, NULL, 1);
|
||||
convert_subs(o, mode, subs, data);
|
||||
sector_headers(o, data, mode, 0);
|
||||
@ -311,9 +376,11 @@ int sector_postgap(struct burn_write_opts *o,
|
||||
unsigned char *data;
|
||||
|
||||
data = get_sector(o, mode);
|
||||
if (!data)
|
||||
if (data == NULL)
|
||||
return 0;
|
||||
convert_data(o, NULL, mode, data);
|
||||
/* ts A61010 */
|
||||
if (convert_data(o, NULL, mode, data) <= 0)
|
||||
return 0;;
|
||||
/* use last index in track */
|
||||
subcode_user(o, subs, tno, control, 1, NULL, 1);
|
||||
convert_subs(o, mode, subs, data);
|
||||
@ -362,7 +429,9 @@ static char char_to_isrc(char c)
|
||||
return 0x11 + (c - 'A');
|
||||
if (c >= 'a' && c <= 'z')
|
||||
return 0x11 + (c - 'a');
|
||||
assert(0);
|
||||
|
||||
/* ts A61008 : obsoleted by test in burn_track_set_isrc() */
|
||||
/* a ssert(0); */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -398,7 +467,8 @@ void subcode_user(struct burn_write_opts *o, unsigned char *subcodes,
|
||||
}
|
||||
}
|
||||
|
||||
assert(qmode == 1 || qmode == 2 || qmode == 3);
|
||||
/* ts A61010 : this cannot happen. Assert for fun ? */
|
||||
/* a ssert(qmode == 1 || qmode == 2 || qmode == 3); */
|
||||
|
||||
switch (qmode) {
|
||||
case 1:
|
||||
@ -480,7 +550,9 @@ int sector_lout(struct burn_write_opts *o, unsigned char control, int mode)
|
||||
data = get_sector(o, mode);
|
||||
if (!data)
|
||||
return 0;
|
||||
convert_data(o, NULL, mode, data);
|
||||
/* ts A61010 */
|
||||
if (convert_data(o, NULL, mode, data) <= 0)
|
||||
return 0;
|
||||
subcode_lout(o, control, subs);
|
||||
convert_subs(o, mode, subs, data);
|
||||
sector_headers(o, data, mode, 0);
|
||||
@ -497,7 +569,9 @@ int sector_data(struct burn_write_opts *o, struct burn_track *t, int psub)
|
||||
data = get_sector(o, t->mode);
|
||||
if (!data)
|
||||
return 0;
|
||||
convert_data(o, t, t->mode, data);
|
||||
/* ts A61010 */
|
||||
if (convert_data(o, t, t->mode, data) <= 0)
|
||||
return 0;
|
||||
|
||||
if (!t->source->read_sub)
|
||||
subcode_user(o, subs, t->entry->point,
|
||||
@ -542,6 +616,17 @@ int dec_to_bcd(int d)
|
||||
return (top << 4) + bottom;
|
||||
}
|
||||
|
||||
int sector_headers_is_ok(struct burn_write_opts *o, int mode)
|
||||
{
|
||||
if (mode & BURN_AUDIO) /* no headers for "audio" */
|
||||
return 1;
|
||||
if (o->write_type == BURN_WRITE_SAO)
|
||||
return 1;
|
||||
if (mode & BURN_MODE1)
|
||||
return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sector_headers(struct burn_write_opts *o, unsigned char *out,
|
||||
int mode, int leadin)
|
||||
{
|
||||
@ -550,6 +635,17 @@ void sector_headers(struct burn_write_opts *o, unsigned char *out,
|
||||
int min, sec, frame;
|
||||
int modebyte = -1;
|
||||
|
||||
/* ts A61009 */
|
||||
#if 1
|
||||
int ret;
|
||||
|
||||
ret = sector_headers_is_ok(o, mode);
|
||||
if (ret != 2)
|
||||
return;
|
||||
modebyte = 1;
|
||||
|
||||
#else
|
||||
|
||||
if (mode & BURN_AUDIO) /* no headers for "audio" */
|
||||
return;
|
||||
if (o->write_type == BURN_WRITE_SAO)
|
||||
@ -557,7 +653,10 @@ void sector_headers(struct burn_write_opts *o, unsigned char *out,
|
||||
if (mode & BURN_MODE1)
|
||||
modebyte = 1;
|
||||
|
||||
assert(modebyte == 1);
|
||||
#endif
|
||||
|
||||
/* ts A61009 : now ensured by burn_disc_write_is_ok() */
|
||||
/* a ssert(modebyte == 1); */
|
||||
|
||||
out[0] = 0;
|
||||
memset(out + 1, 0xFF, 10); /* sync */
|
||||
@ -629,7 +728,9 @@ void process_q(struct burn_drive *d, unsigned char *q)
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
|
||||
/* ts A61009 : if reactivated then witout Assert */
|
||||
a ssert(0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -18,6 +18,10 @@ int sector_postgap(struct burn_write_opts *, unsigned char tno,
|
||||
unsigned char control, int mode);
|
||||
int sector_lout(struct burn_write_opts *, unsigned char control, int mode);
|
||||
int sector_data(struct burn_write_opts *, struct burn_track *t, int psub);
|
||||
|
||||
/* ts A61009 */
|
||||
int sector_headers_is_ok(struct burn_write_opts *o, int mode);
|
||||
|
||||
void sector_headers(struct burn_write_opts *, unsigned char *,
|
||||
int mode, int leadin);
|
||||
void subcode_user(struct burn_write_opts *, unsigned char *s,
|
||||
|
768
libburn/sg-freebsd.c
Normal file
768
libburn/sg-freebsd.c
Normal file
@ -0,0 +1,768 @@
|
||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
|
||||
|
||||
/* >>> ts A61021 : for testing the new arrangement of code
|
||||
please outcomment these defines : */
|
||||
|
||||
/* Keeps alive old enumerate_common(). New version delegates much work
|
||||
to methods in drive, mmc, spc, and sbc .
|
||||
*/
|
||||
#define Scsi_freebsd_make_own_enumeratE 1
|
||||
|
||||
|
||||
/* Keeps alive old sg_enumerate(). New version delegates most work to
|
||||
sg_give_next_adr().
|
||||
*/
|
||||
#define Scsi_freebsd_old_sg_enumeratE 1
|
||||
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/poll.h>
|
||||
#include <camlib.h>
|
||||
#include <cam/scsi/scsi_message.h>
|
||||
#include <cam/scsi/scsi_pass.h>
|
||||
|
||||
#include <err.h> /* XXX */
|
||||
|
||||
|
||||
#include "transport.h"
|
||||
#include "drive.h"
|
||||
#include "sg.h"
|
||||
#include "spc.h"
|
||||
#include "mmc.h"
|
||||
#include "sbc.h"
|
||||
#include "debug.h"
|
||||
#include "toc.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "libdax_msgs.h"
|
||||
extern struct libdax_msgs *libdax_messenger;
|
||||
|
||||
static void enumerate_common(char *fname, int bus_no, int host_no,
|
||||
int channel_no, int target_no, int lun_no);
|
||||
|
||||
/* ts A51221 */
|
||||
int burn_drive_is_banned(char *device_address);
|
||||
|
||||
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
int mmc_function_spy(char * text);
|
||||
|
||||
|
||||
#ifdef Scsi_freebsd_old_sg_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_sg_enumeratE */
|
||||
|
||||
/* ts A61021 : Moved most code from sg_enumerate under sg_give_next_adr() */
|
||||
/* Some helper functions for sg_give_next_adr() */
|
||||
|
||||
static int sg_init_enumerator(burn_drive_enumerator_t *idx)
|
||||
{
|
||||
idx->skip_device = 0;
|
||||
|
||||
if ((idx->fd = open(XPT_DEVICE, O_RDWR)) == -1) {
|
||||
warn("couldn't open %s", XPT_DEVICE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bzero(&(idx->ccb), sizeof(union ccb));
|
||||
|
||||
idx->ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
|
||||
idx->ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
|
||||
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);
|
||||
if (idx->ccb.cdm.matches == NULL) {
|
||||
warnx("can't malloc memory for matches");
|
||||
close(idx->fd);
|
||||
return -1;
|
||||
}
|
||||
idx->ccb.cdm.num_matches = 0;
|
||||
idx->i = idx->ccb.cdm.num_matches; /* to trigger buffer load */
|
||||
|
||||
/*
|
||||
* We fetch all nodes, since we display most of them in the default
|
||||
* case, and all in the verbose case.
|
||||
*/
|
||||
idx->ccb.cdm.num_patterns = 0;
|
||||
idx->ccb.cdm.pattern_buf_len = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int sg_next_enumeration_buffer(burn_drive_enumerator_t *idx)
|
||||
{
|
||||
/*
|
||||
* We do the ioctl multiple times if necessary, in case there are
|
||||
* more than 100 nodes in the EDT.
|
||||
*/
|
||||
if (ioctl(idx->fd, CAMIOCOMMAND, &(idx->ccb)) == -1) {
|
||||
warn("error sending CAMIOCOMMAND ioctl");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((idx->ccb.ccb_h.status != CAM_REQ_CMP)
|
||||
|| ((idx->ccb.cdm.status != CAM_DEV_MATCH_LAST)
|
||||
&& (idx->ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
|
||||
warnx("got CAM error %#x, CDM error %d\n",
|
||||
idx->ccb.ccb_h.status, idx->ccb.cdm.status);
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/** Returns the next index number and the next enumerated drive address.
|
||||
@param idx An opaque handle. Make no own theories about it.
|
||||
@param adr Takes the reply
|
||||
@param adr_size Gives maximum size of reply including final 0
|
||||
@param initialize 1 = start new,
|
||||
0 = continue, use no other values for now
|
||||
-1 = finish
|
||||
@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,
|
||||
char adr[], int adr_size, int initialize)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (initialize == 1) {
|
||||
ret = sg_init_enumerator(idx);
|
||||
if (ret<=0)
|
||||
return ret;
|
||||
} else if (initialize == -1) {
|
||||
if(idx->fd != -1)
|
||||
close(idx->fd);
|
||||
idx->fd = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
try_item:; /* This spaghetti loop keeps the number of tabs small */
|
||||
|
||||
/* Loop content from old sg_enumerate() */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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[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];
|
||||
|
||||
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);
|
||||
|
||||
/* 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 */
|
||||
}
|
||||
|
||||
|
||||
int sg_is_enumerable_adr(char* adr)
|
||||
{
|
||||
burn_drive_enumerator_t idx;
|
||||
int initialize = 1;
|
||||
char buf[64];
|
||||
|
||||
while(1) {
|
||||
ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
|
||||
initialize = 0;
|
||||
if (ret <= 0)
|
||||
break;
|
||||
if (strcmp(adr, buf) == 0) {
|
||||
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/** Try to obtain SCSI address parameters.
|
||||
@return 1 is success , 0 is failure
|
||||
*/
|
||||
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;
|
||||
char buf[64];
|
||||
struct periph_match_result* result;
|
||||
|
||||
while(1) {
|
||||
ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
|
||||
initialize = 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;
|
||||
}
|
||||
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
#endif /* ! Scsi_freebsd_old_sg_enumeratE */
|
||||
|
||||
|
||||
int sg_close_drive(struct burn_drive * d)
|
||||
{
|
||||
if (d->cam != NULL) {
|
||||
cam_close_device(d->cam);
|
||||
d->cam = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sg_drive_is_open(struct burn_drive * d)
|
||||
{
|
||||
return (d->cam != NULL);
|
||||
}
|
||||
|
||||
|
||||
void ata_enumerate(void)
|
||||
{
|
||||
/* ts A61021: Only a dummy function is needed in FreeBSD */
|
||||
/* The difference between sg and ata should be encapsulated
|
||||
in sg-linux.c */
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
void sg_enumerate(void)
|
||||
{
|
||||
|
||||
#ifdef Scsi_freebsd_old_sg_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_sg_enumeratE */
|
||||
|
||||
burn_drive_enumerator_t idx;
|
||||
int initialize = 1;
|
||||
char buf[64];
|
||||
|
||||
while(1) {
|
||||
ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
|
||||
initialize = 0;
|
||||
if (ret <= 0)
|
||||
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);
|
||||
}
|
||||
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
|
||||
|
||||
#endif /* ! Scsi_freebsd_old_sg_enumeratE */
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifdef Scsi_freebsd_make_own_enumeratE
|
||||
|
||||
/* ts A61021: The old version which mixes SCSI and operating system adapter
|
||||
*/
|
||||
static void enumerate_common(char *fname, int bus_no, int host_no,
|
||||
int channel_no, int target_no, int lun_no)
|
||||
{
|
||||
struct burn_drive *t;
|
||||
struct burn_drive out;
|
||||
|
||||
/* ts A60923 */
|
||||
out.bus_no = bus_no;
|
||||
out.host = host_no;
|
||||
out.id = target_no;
|
||||
out.channel = channel_no;
|
||||
out.lun = lun_no;
|
||||
|
||||
out.devname = burn_strdup(fname);
|
||||
out.cam = NULL;
|
||||
|
||||
out.start_lba= -2000000000;
|
||||
out.end_lba= -2000000000;
|
||||
out.read_atip = mmc_read_atip;
|
||||
|
||||
out.grab = sg_grab;
|
||||
out.release = sg_release;
|
||||
out.drive_is_open= sg_drive_is_open;
|
||||
out.issue_command = sg_issue_command;
|
||||
out.getcaps = spc_getcaps;
|
||||
out.released = 1;
|
||||
out.status = BURN_DISC_UNREADY;
|
||||
|
||||
out.eject = sbc_eject;
|
||||
out.load = sbc_load;
|
||||
out.lock = spc_prevent;
|
||||
out.unlock = spc_allow;
|
||||
out.read_disc_info = spc_sense_write_params;
|
||||
out.get_erase_progress = spc_get_erase_progress;
|
||||
out.test_unit_ready = spc_test_unit_ready;
|
||||
out.probe_write_modes = spc_probe_write_modes;
|
||||
out.read_toc = mmc_read_toc;
|
||||
out.write = mmc_write;
|
||||
out.erase = mmc_erase;
|
||||
out.read_sectors = mmc_read_sectors;
|
||||
out.perform_opc = mmc_perform_opc;
|
||||
out.set_speed = mmc_set_speed;
|
||||
out.send_parameters = spc_select_error_params;
|
||||
out.send_write_parameters = spc_select_write_params;
|
||||
out.send_cue_sheet = mmc_send_cue_sheet;
|
||||
out.sync_cache = mmc_sync_cache;
|
||||
out.get_nwa = mmc_get_nwa;
|
||||
out.close_disc = mmc_close_disc;
|
||||
out.close_session = mmc_close_session;
|
||||
out.read_buffer_capacity = mmc_read_buffer_capacity;
|
||||
out.idata = malloc(sizeof(struct burn_scsi_inquiry_data));
|
||||
out.idata->valid = 0;
|
||||
out.mdata = malloc(sizeof(struct scsi_mode_data));
|
||||
out.mdata->valid = 0;
|
||||
if (out.idata == NULL || out.mdata == NULL) {
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020108,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Could not allocate new drive object", 0, 0);
|
||||
return;
|
||||
}
|
||||
memset(&out.params, 0, sizeof(struct params));
|
||||
t = burn_drive_register(&out);
|
||||
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
mmc_function_spy("enumerate_common : -------- doing grab");
|
||||
|
||||
/* try to get the drive info */
|
||||
if (t->grab(t)) {
|
||||
burn_print(2, "getting drive info\n");
|
||||
t->getcaps(t);
|
||||
t->unlock(t);
|
||||
t->released = 1;
|
||||
} else {
|
||||
burn_print(2, "unable to grab new located drive\n");
|
||||
}
|
||||
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
mmc_function_spy("enumerate_common : ----- would release ");
|
||||
|
||||
}
|
||||
|
||||
#else /* Scsi_freebsd_make_own_enumeratE */
|
||||
|
||||
/* The new, more concise version of enumerate_common */
|
||||
static void enumerate_common(char *fname, int bus_no, int host_no,
|
||||
int channel_no, int target_no, int lun_no)
|
||||
{
|
||||
int ret;
|
||||
struct burn_drive out;
|
||||
|
||||
/* General libburn drive setup */
|
||||
burn_setup_drive(&out, fname);
|
||||
|
||||
/* This transport adapter uses SCSI-family commands and models
|
||||
(seems the adapter would know better than its boss, if ever) */
|
||||
ret = burn_scsi_setup_drive(&out, bus_no, host_no, channel_no,
|
||||
target_no, lun_no, 0);
|
||||
if (ret<=0)
|
||||
return;
|
||||
|
||||
/* Operating system adapter is CAM */
|
||||
/* Adapter specific handles and data */
|
||||
out.cam = NULL;
|
||||
/* Adapter specific functions */
|
||||
out.grab = sg_grab;
|
||||
out.release = sg_release;
|
||||
out.drive_is_open = sg_drive_is_open;
|
||||
out.issue_command = sg_issue_command;
|
||||
|
||||
/* Finally register drive and inquire drive information */
|
||||
burn_drive_finish_enum(&out);
|
||||
}
|
||||
|
||||
#endif /* ! Scsi_freebsd_make_own_enumeratE */
|
||||
|
||||
/* ts A61021: do not believe this:
|
||||
we use the sg reference count to decide whether we can use the
|
||||
drive or not.
|
||||
if refcount is not one, drive is open somewhere else.
|
||||
*/
|
||||
int sg_grab(struct burn_drive *d)
|
||||
{
|
||||
int count;
|
||||
struct cam_device *cam;
|
||||
|
||||
mmc_function_spy("sg_grab");
|
||||
|
||||
assert(d->cam == NULL);
|
||||
|
||||
cam = cam_open_device(d->devname, O_RDWR);
|
||||
if (cam == NULL) {
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020003,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Could not grab drive", 0/*os_errno*/, 0);
|
||||
return 0;
|
||||
}
|
||||
/* er = ioctl(fd, SG_GET_ACCESS_COUNT, &count);*/
|
||||
count = 1;
|
||||
if (1 == count) {
|
||||
d->cam = cam;
|
||||
fcntl(cam->fd, F_SETOWN, getpid());
|
||||
d->released = 0;
|
||||
return 1;
|
||||
}
|
||||
burn_print(1, "could not acquire drive - already open\n");
|
||||
sg_close_drive(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
non zero return means you still have the drive and it's not
|
||||
in a state to be released? (is that even possible?)
|
||||
*/
|
||||
|
||||
int sg_release(struct burn_drive *d)
|
||||
{
|
||||
mmc_function_spy("sg_release");
|
||||
|
||||
if (d->cam == NULL) {
|
||||
burn_print(1, "release an ungrabbed drive. die\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mmc_function_spy("sg_release ----------- closing.");
|
||||
|
||||
sg_close_drive(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sg_issue_command(struct burn_drive *d, struct command *c)
|
||||
{
|
||||
int done = 0;
|
||||
int err;
|
||||
union ccb *ccb;
|
||||
|
||||
char buf[161];
|
||||
snprintf(buf, sizeof (buf), "sg_issue_command d->cam=%p d->released=%d",
|
||||
(void*)d->cam, d->released);
|
||||
mmc_function_spy(buf);
|
||||
|
||||
if (d->cam == NULL) {
|
||||
c->error = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
c->error = 0;
|
||||
|
||||
ccb = cam_getccb(d->cam);
|
||||
cam_fill_csio(&ccb->csio,
|
||||
1, /* retries */
|
||||
NULL, /* cbfncp */
|
||||
CAM_DEV_QFRZDIS, /* flags */
|
||||
MSG_SIMPLE_Q_TAG, /* tag_action */
|
||||
NULL, /* data_ptr */
|
||||
0, /* dxfer_len */
|
||||
sizeof (ccb->csio.sense_data), /* sense_len */
|
||||
0, /* cdb_len */
|
||||
30*1000); /* timeout */
|
||||
switch (c->dir) {
|
||||
case TO_DRIVE:
|
||||
ccb->csio.ccb_h.flags |= CAM_DIR_OUT;
|
||||
break;
|
||||
case FROM_DRIVE:
|
||||
ccb->csio.ccb_h.flags |= CAM_DIR_IN;
|
||||
break;
|
||||
case NO_TRANSFER:
|
||||
ccb->csio.ccb_h.flags |= CAM_DIR_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
ccb->csio.cdb_len = c->oplen;
|
||||
memcpy(&ccb->csio.cdb_io.cdb_bytes, &c->opcode, c->oplen);
|
||||
|
||||
memset(&ccb->csio.sense_data, 0, sizeof (ccb->csio.sense_data));
|
||||
|
||||
if (c->page) {
|
||||
ccb->csio.data_ptr = c->page->data;
|
||||
if (c->dir == FROM_DRIVE) {
|
||||
ccb->csio.dxfer_len = BUFFER_SIZE;
|
||||
/* touch page so we can use valgrind */
|
||||
memset(c->page->data, 0, BUFFER_SIZE);
|
||||
} else {
|
||||
assert(c->page->bytes > 0);
|
||||
ccb->csio.dxfer_len = c->page->bytes;
|
||||
}
|
||||
} else {
|
||||
ccb->csio.data_ptr = NULL;
|
||||
ccb->csio.dxfer_len = 0;
|
||||
}
|
||||
|
||||
do {
|
||||
err = cam_send_ccb(d->cam, ccb);
|
||||
if (err == -1) {
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
d->global_index, 0x0002010c,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Failed to transfer command to drive",
|
||||
errno, 0);
|
||||
cam_freeccb(ccb);
|
||||
sg_close_drive(d);
|
||||
d->released = 1;
|
||||
d->busy = BURN_DRIVE_IDLE;
|
||||
c->error = 1;
|
||||
return -1;
|
||||
}
|
||||
/* XXX */
|
||||
memcpy(c->sense, &ccb->csio.sense_data, ccb->csio.sense_len);
|
||||
if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
|
||||
if (!c->retry) {
|
||||
c->error = 1;
|
||||
cam_freeccb(ccb);
|
||||
return 1;
|
||||
}
|
||||
switch (scsi_error(d, c->sense, 0)) {
|
||||
case RETRY:
|
||||
done = 0;
|
||||
break;
|
||||
case FAIL:
|
||||
done = 1;
|
||||
c->error = 1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
done = 1;
|
||||
}
|
||||
} while (!done);
|
||||
cam_freeccb(ccb);
|
||||
return 1;
|
||||
}
|
||||
|
||||
enum response scsi_error(struct burn_drive *d, unsigned char *sense,
|
||||
int senselen)
|
||||
{
|
||||
int key, asc, ascq;
|
||||
|
||||
senselen = senselen;
|
||||
key = sense[2];
|
||||
asc = sense[12];
|
||||
ascq = sense[13];
|
||||
|
||||
burn_print(12, "CONDITION: 0x%x 0x%x 0x%x on %s %s\n",
|
||||
key, asc, ascq, d->idata->vendor, d->idata->product);
|
||||
|
||||
switch (asc) {
|
||||
case 0:
|
||||
burn_print(12, "NO ERROR!\n");
|
||||
return RETRY;
|
||||
|
||||
case 2:
|
||||
burn_print(1, "not ready\n");
|
||||
return RETRY;
|
||||
case 4:
|
||||
burn_print(1,
|
||||
"logical unit is in the process of becoming ready\n");
|
||||
return RETRY;
|
||||
case 0x20:
|
||||
if (key == 5)
|
||||
burn_print(1, "bad opcode\n");
|
||||
return FAIL;
|
||||
case 0x21:
|
||||
burn_print(1, "invalid address or something\n");
|
||||
return FAIL;
|
||||
case 0x24:
|
||||
if (key == 5)
|
||||
burn_print(1, "invalid field in cdb\n");
|
||||
else
|
||||
break;
|
||||
return FAIL;
|
||||
case 0x26:
|
||||
if (key == 5)
|
||||
burn_print( 1, "invalid field in parameter list\n" );
|
||||
return FAIL;
|
||||
case 0x28:
|
||||
if (key == 6)
|
||||
burn_print(1,
|
||||
"Not ready to ready change, medium may have changed\n");
|
||||
else
|
||||
break;
|
||||
return RETRY;
|
||||
case 0x3A:
|
||||
burn_print(12, "Medium not present in %s %s\n",
|
||||
d->idata->vendor, d->idata->product);
|
||||
|
||||
d->status = BURN_DISC_EMPTY;
|
||||
return FAIL;
|
||||
}
|
||||
burn_print(1, "unknown failure\n");
|
||||
burn_print(1, "key:0x%x, asc:0x%x, ascq:0x%x\n", key, asc, ascq);
|
||||
return FAIL;
|
||||
}
|
||||
|
797
libburn/sg-linux.c
Normal file
797
libburn/sg-linux.c
Normal file
@ -0,0 +1,797 @@
|
||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
|
||||
/* ts A61010 */
|
||||
/* #include <a ssert.h> */
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
/* #include <m alloc.h> ts A61013 : not in Linux man 3 malloc */
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/poll.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <stdlib.h>
|
||||
#include <scsi/sg.h>
|
||||
#include <scsi/scsi.h>
|
||||
|
||||
#include "transport.h"
|
||||
#include "drive.h"
|
||||
#include "sg.h"
|
||||
#include "spc.h"
|
||||
#include "mmc.h"
|
||||
#include "sbc.h"
|
||||
#include "debug.h"
|
||||
#include "toc.h"
|
||||
#include "util.h"
|
||||
|
||||
/* kludge! glibc headers don't define all the SCSI stuff that we use! */
|
||||
#ifndef SG_GET_ACCESS_COUNT
|
||||
# define SG_GET_ACCESS_COUNT 0x2289
|
||||
#endif
|
||||
|
||||
#include "libdax_msgs.h"
|
||||
extern struct libdax_msgs *libdax_messenger;
|
||||
|
||||
static void enumerate_common(char *fname, int bus_no, int host_no,
|
||||
int channel_no, int target_no, int lun_no);
|
||||
|
||||
/* ts A51221 */
|
||||
int burn_drive_is_banned(char *device_address);
|
||||
|
||||
/* ts A60813 : storage objects are in libburn/init.c
|
||||
wether to use O_EXCL
|
||||
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_open_o_nonblock;
|
||||
extern int burn_sg_open_abort_busy;
|
||||
|
||||
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
int mmc_function_spy(char * text);
|
||||
|
||||
|
||||
static int sgio_test(int fd)
|
||||
{
|
||||
unsigned char test_ops[] = { 0, 0, 0, 0, 0, 0 };
|
||||
sg_io_hdr_t s;
|
||||
|
||||
memset(&s, 0, sizeof(sg_io_hdr_t));
|
||||
s.interface_id = 'S';
|
||||
s.dxfer_direction = SG_DXFER_NONE;
|
||||
s.cmd_len = 6;
|
||||
s.cmdp = test_ops;
|
||||
s.timeout = 12345;
|
||||
return ioctl(fd, SG_IO, &s);
|
||||
}
|
||||
|
||||
|
||||
/* ts A60925 : ticket 74 */
|
||||
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;
|
||||
}
|
||||
|
||||
int sg_drive_is_open(struct burn_drive * d)
|
||||
{
|
||||
/* a bit more detailed case distinction than needed */
|
||||
if (d->fd == -1337)
|
||||
return 0;
|
||||
if (d->fd < 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ts A60924 */
|
||||
int sg_handle_busy_device(char *fname, int os_errno)
|
||||
{
|
||||
char msg[4096];
|
||||
|
||||
/* ts A60814 : i saw no way to do this more nicely */
|
||||
if (burn_sg_open_abort_busy) {
|
||||
fprintf(stderr,
|
||||
"\nlibburn: FATAL : Application triggered abort on busy device '%s'\n",
|
||||
fname);
|
||||
|
||||
/* ts A61007 */
|
||||
abort();
|
||||
/* a ssert("drive busy" == "non fatal"); */
|
||||
}
|
||||
|
||||
/* ts A60924 : now reporting to libdax_msgs */
|
||||
sprintf(msg, "Cannot open busy device '%s'", fname);
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020001,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_LOW,
|
||||
msg, os_errno, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ts A60922 ticket 33 */
|
||||
/** Returns the next index number and the next enumerated drive address.
|
||||
@param idx An opaque handle. Make no own theories about it.
|
||||
@param adr Takes the reply
|
||||
@param adr_size Gives maximum size of reply including final 0
|
||||
@param initialize 1 = start new,
|
||||
0 = continue, use no other values for now
|
||||
-1 = finish
|
||||
@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,
|
||||
char adr[], int adr_size, int initialize)
|
||||
{
|
||||
/* sg.h : typedef int burn_drive_enumerator_t; */
|
||||
static int sg_limit = 32, ata_limit = 26;
|
||||
int baseno = 0;
|
||||
|
||||
if (initialize == -1)
|
||||
return 0;
|
||||
|
||||
if (initialize == 1)
|
||||
*idx = -1;
|
||||
(*idx)++;
|
||||
if (*idx >= sg_limit)
|
||||
goto next_ata;
|
||||
if (adr_size < 10)
|
||||
return -1;
|
||||
sprintf(adr, "/dev/sg%d", *idx);
|
||||
return 1;
|
||||
next_ata:;
|
||||
baseno += sg_limit;
|
||||
if (*idx - baseno >= ata_limit)
|
||||
goto next_nothing;
|
||||
if (adr_size < 9)
|
||||
return -1;
|
||||
sprintf(adr, "/dev/hd%c", 'a' + (*idx - baseno));
|
||||
return 1;
|
||||
next_nothing:;
|
||||
baseno += ata_limit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sg_is_enumerable_adr(char *adr)
|
||||
{
|
||||
char fname[4096];
|
||||
int i, ret = 0, first = 1;
|
||||
|
||||
while (1) {
|
||||
ret= sg_give_next_adr(&i, fname, sizeof(fname), first);
|
||||
if(ret <= 0)
|
||||
break;
|
||||
first = 0;
|
||||
if (strcmp(adr, fname) == 0)
|
||||
return 1;
|
||||
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/* ts A60926 */
|
||||
int sg_release_siblings(int sibling_fds[], 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);
|
||||
if(*sibling_count > 0) {
|
||||
sprintf(msg, "Closed %d O_EXCL scsi siblings", *sibling_count);
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020007,
|
||||
LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH, msg, 0,0);
|
||||
}
|
||||
*sibling_count = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ts A60926 */
|
||||
int sg_open_drive_fd(char *fname, int scan_mode)
|
||||
{
|
||||
int open_mode = O_RDWR, fd;
|
||||
char msg[81];
|
||||
|
||||
/* ts A60813 - A60927
|
||||
O_EXCL with devices is a non-POSIX feature
|
||||
of Linux kernels. Possibly introduced 2002.
|
||||
Mentioned in "The Linux SCSI Generic (sg) HOWTO" */
|
||||
if(burn_sg_open_o_excl)
|
||||
open_mode |= O_EXCL;
|
||||
/* 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. */
|
||||
if(burn_sg_open_o_nonblock)
|
||||
open_mode |= O_NONBLOCK;
|
||||
|
||||
/* <<< 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));
|
||||
*/
|
||||
|
||||
fd = open(fname, open_mode);
|
||||
if (fd == -1) {
|
||||
/* <<< debugging
|
||||
fprintf(stderr,
|
||||
"\nlibburn: experimental: fname= %s , errno= %d\n",
|
||||
fname,errno);
|
||||
*/
|
||||
if (errno == EBUSY) {
|
||||
sg_handle_busy_device(fname, errno);
|
||||
return -1;
|
||||
|
||||
}
|
||||
if (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,
|
||||
msg, errno, 0);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
/* ts A60926 */
|
||||
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 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];
|
||||
|
||||
static char tldev[][81]= {"/dev/sr%d", "/dev/scd%d", "/dev/st%d", ""};
|
||||
|
||||
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);
|
||||
|
||||
for (tld = 0; tldev[tld][0] != 0; tld++) {
|
||||
for (i = 0; i < 32; i++) {
|
||||
sprintf(fname, tldev[tld], i);
|
||||
ret = sg_obtain_scsi_adr(fname, &i_bus_no, &i_host_no,
|
||||
&i_channel_no, &i_target_no, &i_lun_no);
|
||||
if (ret <= 0)
|
||||
continue;
|
||||
if (i_host_no != host_no || i_channel_no != channel_no)
|
||||
continue;
|
||||
if (i_target_no != id_no || i_lun_no != lun_no)
|
||||
continue;
|
||||
|
||||
fd = sg_open_drive_fd(fname, 0);
|
||||
if (fd < 0)
|
||||
goto failed;
|
||||
|
||||
if (*sibling_count>=LIBBURN_SG_MAX_SIBLINGS) {
|
||||
sprintf(msg, "Too many scsi siblings of '%s'",
|
||||
path);
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
driveno, 0x00020006,
|
||||
LIBDAX_MSGS_SEV_FATAL,
|
||||
LIBDAX_MSGS_PRIO_HIGH, msg, 0, 0);
|
||||
goto failed;
|
||||
}
|
||||
sprintf(msg, "Opened O_EXCL scsi sibling '%s' of '%s'",
|
||||
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;
|
||||
(*sibling_count)++;
|
||||
}
|
||||
}
|
||||
return(1);
|
||||
failed:;
|
||||
sg_release_siblings(sibling_fds, sibling_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* ts A60926 */
|
||||
int sg_close_drive(struct burn_drive *d)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!burn_drive_is_open(d))
|
||||
return 0;
|
||||
sg_release_siblings(d->sibling_fds, &(d->sibling_count));
|
||||
ret = sg_close_drive_fd(d->devname, d->global_index, &(d->fd), 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ata_enumerate(void)
|
||||
{
|
||||
struct hd_driveid tm;
|
||||
int i, fd;
|
||||
char fname[10];
|
||||
|
||||
for (i = 0; i < 26; i++) {
|
||||
sprintf(fname, "/dev/hd%c", 'a' + i);
|
||||
/* ts A51221 */
|
||||
if (burn_drive_is_banned(fname))
|
||||
continue;
|
||||
fd = sg_open_drive_fd(fname, 1);
|
||||
if (fd == -1)
|
||||
continue;
|
||||
|
||||
/* found a drive */
|
||||
ioctl(fd, HDIO_GET_IDENTITY, &tm);
|
||||
|
||||
/* not atapi */
|
||||
if (!(tm.config & 0x8000) || (tm.config & 0x4000)) {
|
||||
sg_close_drive_fd(fname, -1, &fd, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if SG_IO fails on an atapi device, we should stop trying to
|
||||
use hd* devices */
|
||||
if (sgio_test(fd) == -1) {
|
||||
sg_close_drive_fd(fname, -1, &fd, 0);
|
||||
return;
|
||||
}
|
||||
if (sg_close_drive_fd(fname, -1, &fd, 1) <= 0)
|
||||
continue;
|
||||
enumerate_common(fname, -1, -1, -1, -1, -1);
|
||||
}
|
||||
}
|
||||
|
||||
void sg_enumerate(void)
|
||||
{
|
||||
struct sg_scsi_id sid;
|
||||
int i, fd, sibling_fds[LIBBURN_SG_MAX_SIBLINGS], sibling_count= 0, ret;
|
||||
int bus_no = -1;
|
||||
char fname[10];
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
sprintf(fname, "/dev/sg%d", i);
|
||||
/* ts A51221 */
|
||||
if (burn_drive_is_banned(fname))
|
||||
continue;
|
||||
/* ts A60927 */
|
||||
fd = sg_open_drive_fd(fname, 1);
|
||||
if (fd == -1)
|
||||
continue;
|
||||
|
||||
/* found a drive */
|
||||
ioctl(fd, SG_GET_SCSI_ID, &sid);
|
||||
|
||||
#ifdef SCSI_IOCTL_GET_BUS_NUMBER
|
||||
/* Hearsay A61005 */
|
||||
if (ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, &bus_no) == -1)
|
||||
bus_no = -1;
|
||||
#endif
|
||||
|
||||
if (sg_close_drive_fd(fname, -1, &fd,
|
||||
sid.scsi_type == TYPE_ROM ) <= 0)
|
||||
continue;
|
||||
if (sid.scsi_type != TYPE_ROM)
|
||||
continue;
|
||||
|
||||
/* 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,
|
||||
sid.host_no, sid.channel,
|
||||
sid.scsi_id, sid.lun);
|
||||
if (ret<=0) {
|
||||
sg_handle_busy_device(fname, 0);
|
||||
continue;
|
||||
}
|
||||
/* the final occupation will be done in sg_grab() */
|
||||
sg_release_siblings(sibling_fds, &sibling_count);
|
||||
}
|
||||
#ifdef SCSI_IOCTL_GET_BUS_NUMBER
|
||||
if(bus_no == -1)
|
||||
bus_no = 1000 * (sid.host_no + 1) + sid.channel;
|
||||
#else
|
||||
bus_no = sid.host_no;
|
||||
#endif
|
||||
enumerate_common(fname, bus_no, sid.host_no, sid.channel,
|
||||
sid.scsi_id, sid.lun);
|
||||
}
|
||||
}
|
||||
|
||||
/* ts A60923 - A61005 : introduced new SCSI parameters */
|
||||
/* ts A61021 : moved non os-specific code to spc,sbc,mmc,drive */
|
||||
static void enumerate_common(char *fname, int bus_no, int host_no,
|
||||
int channel_no, int target_no, int lun_no)
|
||||
{
|
||||
int ret, i;
|
||||
struct burn_drive out;
|
||||
|
||||
/* General libburn drive setup */
|
||||
burn_setup_drive(&out, fname);
|
||||
|
||||
/* This transport adapter uses SCSI-family commands and models
|
||||
(seems the adapter would know better than its boss, if ever) */
|
||||
ret = burn_scsi_setup_drive(&out, bus_no, host_no, channel_no,
|
||||
target_no, lun_no, 0);
|
||||
if (ret<=0)
|
||||
return;
|
||||
|
||||
/* Operating system adapter is Linux Generic SCSI (sg) */
|
||||
/* Adapter specific handles and data */
|
||||
out.fd = -1337;
|
||||
out.sibling_count = 0;
|
||||
for(i= 0; i<LIBBURN_SG_MAX_SIBLINGS; i++)
|
||||
out.sibling_fds[i] = -1337;
|
||||
/* Adapter specific functions */
|
||||
out.grab = sg_grab;
|
||||
out.release = sg_release;
|
||||
out.drive_is_open= sg_drive_is_open;
|
||||
out.issue_command = sg_issue_command;
|
||||
|
||||
/* Finally register drive and inquire drive information */
|
||||
burn_drive_finish_enum(&out);
|
||||
}
|
||||
|
||||
/*
|
||||
we use the sg reference count to decide whether we can use the
|
||||
drive or not.
|
||||
if refcount is not one, drive is open somewhere else.
|
||||
|
||||
ts A60813: this test is too late. O_EXCL is the stronger solution.
|
||||
After all the test was disabled already in icculus.org/burn CVS.
|
||||
*/
|
||||
int sg_grab(struct burn_drive *d)
|
||||
{
|
||||
int fd, count, os_errno= 0, ret;
|
||||
|
||||
/* ts A60813 */
|
||||
int open_mode = O_RDWR;
|
||||
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
mmc_function_spy("sg_grab");
|
||||
|
||||
|
||||
/* ts A60813 - A60927
|
||||
O_EXCL with devices is a non-POSIX feature
|
||||
of Linux kernels. Possibly introduced 2002.
|
||||
Mentioned in "The Linux SCSI Generic (sg) HOWTO".
|
||||
*/
|
||||
if(burn_sg_open_o_excl)
|
||||
open_mode |= O_EXCL;
|
||||
|
||||
/* ts A60813
|
||||
O_NONBLOCK was hardcoded here. So it should stay default mode. */
|
||||
if(burn_sg_open_o_nonblock)
|
||||
open_mode |= O_NONBLOCK;
|
||||
|
||||
/* ts A60813
|
||||
After enumeration the drive fd is probably still open.
|
||||
-1337 is the initial value of burn_drive.fd and the value after
|
||||
relase of drive. Unclear why not the official error return
|
||||
value -1 of open(2) war used. */
|
||||
/* ts A60822: was if(d->fd == -1337) { */
|
||||
if(! burn_drive_is_open(d)) {
|
||||
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
mmc_function_spy("sg_grab ----------- opening");
|
||||
|
||||
/* 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->host, d->channel, d->id, d->lun);
|
||||
if(ret <= 0)
|
||||
goto drive_is_in_use;
|
||||
}
|
||||
|
||||
fd = open(d->devname, open_mode);
|
||||
os_errno = errno;
|
||||
} else
|
||||
fd= d->fd;
|
||||
|
||||
/* ts A61007 : this is redundant */
|
||||
/* a ssert(fd != -1337); */
|
||||
|
||||
if (fd >= 0) {
|
||||
|
||||
/* ts A60814:
|
||||
according to my experiments this test would work now ! */
|
||||
|
||||
/* ts A60926 : this was disabled */
|
||||
/* Tests with growisofs on kernel 2.4.21 yielded that this
|
||||
does not help against blocking on busy drives.
|
||||
*/
|
||||
/* <<< the old dummy */
|
||||
/* er = ioctl(fd, SG_GET_ACCESS_COUNT, &count);*/
|
||||
count = 1;
|
||||
|
||||
if (1 == count) {
|
||||
d->fd = fd;
|
||||
fcntl(fd, F_SETOWN, getpid());
|
||||
d->released = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
drive_is_in_use:;
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020003,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Could not grab drive - already in use", 0, 0);
|
||||
sg_close_drive(d);
|
||||
d->fd = -1337;
|
||||
return 0;
|
||||
}
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020003,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Could not grab drive", os_errno, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
non zero return means you still have the drive and it's not
|
||||
in a state to be released? (is that even possible?)
|
||||
*/
|
||||
|
||||
int sg_release(struct burn_drive *d)
|
||||
{
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
mmc_function_spy("sg_release");
|
||||
|
||||
if (d->fd < 1) {
|
||||
burn_print(1, "release an ungrabbed drive. die\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
mmc_function_spy("sg_release ----------- closing");
|
||||
|
||||
sg_close_drive(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
char buf[161];
|
||||
sprintf(buf,"sg_issue_command d->fd= %d d->released= %d\n",
|
||||
d->fd,d->released);
|
||||
mmc_function_spy(buf);
|
||||
|
||||
/* ts A61010 : with no fd there is no chance to send an ioctl */
|
||||
if (d->fd < 0) {
|
||||
c->error = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
c->error = 0;
|
||||
memset(&s, 0, sizeof(sg_io_hdr_t));
|
||||
|
||||
s.interface_id = 'S';
|
||||
|
||||
if (c->dir == TO_DRIVE)
|
||||
s.dxfer_direction = SG_DXFER_TO_DEV;
|
||||
else if (c->dir == FROM_DRIVE)
|
||||
s.dxfer_direction = SG_DXFER_FROM_DEV;
|
||||
else if (c->dir == NO_TRANSFER) {
|
||||
s.dxfer_direction = SG_DXFER_NONE;
|
||||
|
||||
/* ts A61007 */
|
||||
/* a ssert(!c->page); */
|
||||
no_c_page = 1;
|
||||
}
|
||||
s.cmd_len = c->oplen;
|
||||
s.cmdp = c->opcode;
|
||||
s.mx_sb_len = 32;
|
||||
s.sbp = c->sense;
|
||||
memset(c->sense, 0, sizeof(c->sense));
|
||||
s.timeout = 200000;
|
||||
if (c->page && !no_c_page) {
|
||||
s.dxferp = c->page->data;
|
||||
if (c->dir == FROM_DRIVE) {
|
||||
s.dxfer_len = BUFFER_SIZE;
|
||||
/* touch page so we can use valgrind */
|
||||
memset(c->page->data, 0, BUFFER_SIZE);
|
||||
} else {
|
||||
|
||||
/* ts A61010 */
|
||||
/* a ssert(c->page->bytes > 0); */
|
||||
if (c->page->bytes <= 0) {
|
||||
c->error = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s.dxfer_len = c->page->bytes;
|
||||
}
|
||||
} else {
|
||||
s.dxferp = NULL;
|
||||
s.dxfer_len = 0;
|
||||
}
|
||||
s.usr_ptr = c;
|
||||
|
||||
do {
|
||||
err = ioctl(d->fd, SG_IO, &s);
|
||||
|
||||
/* ts A61010 */
|
||||
/* a ssert(err != -1); */
|
||||
if (err == -1) {
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
d->global_index, 0x0002010c,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Failed to transfer command to drive",
|
||||
errno, 0);
|
||||
sg_close_drive(d);
|
||||
d->released = 1;
|
||||
d->busy = BURN_DRIVE_IDLE;
|
||||
c->error = 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (s.sb_len_wr) {
|
||||
if (!c->retry) {
|
||||
c->error = 1;
|
||||
return 1;
|
||||
}
|
||||
switch (scsi_error(d, s.sbp, s.sb_len_wr)) {
|
||||
case RETRY:
|
||||
done = 0;
|
||||
break;
|
||||
case FAIL:
|
||||
done = 1;
|
||||
c->error = 1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
done = 1;
|
||||
}
|
||||
} while (!done);
|
||||
return 1;
|
||||
}
|
||||
|
||||
enum response scsi_error(struct burn_drive *d, unsigned char *sense,
|
||||
int senselen)
|
||||
{
|
||||
int key, asc, ascq;
|
||||
|
||||
senselen = senselen;
|
||||
key = sense[2];
|
||||
asc = sense[12];
|
||||
ascq = sense[13];
|
||||
|
||||
burn_print(12, "CONDITION: 0x%x 0x%x 0x%x on %s %s\n",
|
||||
key, asc, ascq, d->idata->vendor, d->idata->product);
|
||||
|
||||
switch (asc) {
|
||||
case 0:
|
||||
burn_print(12, "NO ERROR!\n");
|
||||
return RETRY;
|
||||
|
||||
case 2:
|
||||
burn_print(1, "not ready\n");
|
||||
return RETRY;
|
||||
case 4:
|
||||
burn_print(1,
|
||||
"logical unit is in the process of becoming ready\n");
|
||||
return RETRY;
|
||||
case 0x20:
|
||||
if (key == 5)
|
||||
burn_print(1, "bad opcode\n");
|
||||
return FAIL;
|
||||
case 0x21:
|
||||
burn_print(1, "invalid address or something\n");
|
||||
return FAIL;
|
||||
case 0x24:
|
||||
if (key == 5)
|
||||
burn_print(1, "invalid field in cdb\n");
|
||||
else
|
||||
break;
|
||||
return FAIL;
|
||||
case 0x26:
|
||||
if ( key == 5 )
|
||||
burn_print( 1, "invalid field in parameter list\n" );
|
||||
return FAIL;
|
||||
case 0x28:
|
||||
if (key == 6)
|
||||
burn_print(1,
|
||||
"Not ready to ready change, medium may have changed\n");
|
||||
else
|
||||
break;
|
||||
return RETRY;
|
||||
case 0x3A:
|
||||
burn_print(12, "Medium not present in %s %s\n",
|
||||
d->idata->vendor, d->idata->product);
|
||||
|
||||
d->status = BURN_DISC_EMPTY;
|
||||
return FAIL;
|
||||
}
|
||||
burn_print(1, "unknown failure\n");
|
||||
burn_print(1, "key:0x%x, asc:0x%x, ascq:0x%x\n", key, asc, ascq);
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
/* ts A60922 */
|
||||
/** Try to obtain SCSI address parameters.
|
||||
@return 1 is success , 0 is failure
|
||||
*/
|
||||
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;
|
||||
struct my_scsi_idlun {
|
||||
int x;
|
||||
int host_unique_id;
|
||||
};
|
||||
struct my_scsi_idlun idlun;
|
||||
|
||||
if (strncmp(path, "/dev/hd", 7) == 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);
|
||||
if(fd < 0)
|
||||
return 0;
|
||||
|
||||
#ifdef SCSI_IOCTL_GET_BUS_NUMBER
|
||||
/* Hearsay A61005 */
|
||||
if (ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, bus_no) == -1)
|
||||
*bus_no = -1;
|
||||
#endif
|
||||
|
||||
/* http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO/scsi_g_idlun.html */
|
||||
ret = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &idlun);
|
||||
|
||||
sg_close_drive_fd(path, -1, &fd, 0);
|
||||
if (ret == -1)
|
||||
return(0);
|
||||
*host_no= (idlun.x>>24)&255;
|
||||
*channel_no= (idlun.x>>16)&255;
|
||||
*target_no= (idlun.x)&255;
|
||||
*lun_no= (idlun.x>>8)&255;
|
||||
#ifdef SCSI_IOCTL_GET_BUS_NUMBER
|
||||
if(*bus_no == -1)
|
||||
*bus_no = 1000 * (*host_no + 1) + *channel_no;
|
||||
#else
|
||||
*bus_no= *host_no;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
499
libburn/sg.c
499
libburn/sg.c
@ -1,500 +1,13 @@
|
||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <sys/poll.h>
|
||||
#include <linux/hdreg.h>
|
||||
/* ts A61013 : It would be nice if autotools could do that job */
|
||||
|
||||
#include "transport.h"
|
||||
#include "drive.h"
|
||||
#include "sg.h"
|
||||
#include "spc.h"
|
||||
#include "mmc.h"
|
||||
#include "sbc.h"
|
||||
#include "debug.h"
|
||||
#include "toc.h"
|
||||
#include "util.h"
|
||||
#ifdef __FreeBSD__
|
||||
|
||||
static void enumerate_common(char *fname);
|
||||
#include "sg-freebsd.c"
|
||||
|
||||
/* ts A51221 */
|
||||
int burn_drive_is_banned(char *device_address);
|
||||
#else
|
||||
|
||||
/* ts A60813 : storage objects are in libburn/init.c
|
||||
wether to use O_EXCL
|
||||
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_open_o_nonblock;
|
||||
extern int burn_sg_open_abort_busy;
|
||||
#include "sg-linux.c"
|
||||
|
||||
#endif
|
||||
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
int mmc_function_spy(char * text);
|
||||
|
||||
|
||||
static int sgio_test(int fd)
|
||||
{
|
||||
unsigned char test_ops[] = { 0, 0, 0, 0, 0, 0 };
|
||||
sg_io_hdr_t s;
|
||||
|
||||
memset(&s, 0, sizeof(sg_io_hdr_t));
|
||||
s.interface_id = 'S';
|
||||
s.dxfer_direction = SG_DXFER_NONE;
|
||||
s.cmd_len = 6;
|
||||
s.cmdp = test_ops;
|
||||
s.timeout = 12345;
|
||||
return ioctl(fd, SG_IO, &s);
|
||||
}
|
||||
|
||||
void ata_enumerate(void)
|
||||
{
|
||||
struct hd_driveid tm;
|
||||
int i, fd;
|
||||
char fname[10];
|
||||
|
||||
/* ts A60813 */
|
||||
int open_mode = O_RDWR;
|
||||
|
||||
/* ts A60813
|
||||
O_EXCL with block devices is an unpublished feature
|
||||
of Linux kernels. Possibly introduced 2002.
|
||||
It can only be used if libburn stops opening several
|
||||
file descriptor on the same block device.
|
||||
See comment in sg_grab() */
|
||||
if(burn_sg_open_o_excl)
|
||||
open_mode |= O_EXCL;
|
||||
/* 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. */
|
||||
if(burn_sg_open_o_nonblock)
|
||||
open_mode |= O_NONBLOCK;
|
||||
|
||||
for (i = 0; i < 26; i++) {
|
||||
sprintf(fname, "/dev/hd%c", 'a' + i);
|
||||
/* open O_RDWR so we don't think read only drives are
|
||||
in some way useful
|
||||
*/
|
||||
/* ts A51221 */
|
||||
if (burn_drive_is_banned(fname))
|
||||
continue;
|
||||
fd = open(fname, open_mode);
|
||||
if (fd == -1) {
|
||||
/* <<< debugging
|
||||
fprintf(stderr,
|
||||
"\nlibburn: experimental: fname= %s , errno= %d\n",
|
||||
fname,errno);
|
||||
*/
|
||||
/* ts A60814 : i see no way to do this more nicely */
|
||||
if (errno == EBUSY && burn_sg_open_abort_busy) {
|
||||
fprintf(stderr,
|
||||
"\nlibburn: FATAL : Application triggered abort on busy drive '%s'\n",
|
||||
fname);
|
||||
/* <<< maybe one should plainly exit here */
|
||||
assert("drive busy" == "non fatal");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* found a drive */
|
||||
ioctl(fd, HDIO_GET_IDENTITY, &tm);
|
||||
|
||||
/* not atapi */
|
||||
if (!(tm.config & 0x8000) || (tm.config & 0x4000)) {
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if SG_IO fails on an atapi device, we should stop trying to
|
||||
use hd* devices */
|
||||
if (sgio_test(fd) == -1) {
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
close(fd);
|
||||
enumerate_common(fname);
|
||||
}
|
||||
}
|
||||
|
||||
void sg_enumerate(void)
|
||||
{
|
||||
struct sg_scsi_id sid;
|
||||
int i, fd;
|
||||
char fname[10];
|
||||
|
||||
/* ts A60813 */
|
||||
int open_mode = O_RDWR;
|
||||
|
||||
/* ts A60813
|
||||
O_EXCL with block devices is an unpublished feature
|
||||
of Linux kernels. Possibly introduced 2002.
|
||||
It can only be used if libburn stops opening several
|
||||
file descriptor on the same block device.
|
||||
See comment in sg_grab() */
|
||||
if(burn_sg_open_o_excl)
|
||||
open_mode |= O_EXCL;
|
||||
/* ts A60813
|
||||
O_NONBLOCK was not hardcoded in sg_ but was in ata_.
|
||||
I myself test mainly sg_ and it seems to be ok with
|
||||
O_NONBLOCK. So it should stay default mode. */
|
||||
if(burn_sg_open_o_nonblock)
|
||||
open_mode |= O_NONBLOCK;
|
||||
|
||||
/* <<< 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));
|
||||
|
||||
*/
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
sprintf(fname, "/dev/sg%d", i);
|
||||
/* open RDWR so we don't accidentally think read only drives
|
||||
are in some way useful
|
||||
*/
|
||||
/* ts A51221 */
|
||||
if (burn_drive_is_banned(fname))
|
||||
continue;
|
||||
fd = open(fname, open_mode);
|
||||
|
||||
if (fd == -1) {
|
||||
/* <<< debugging
|
||||
fprintf(stderr,
|
||||
"\n cdrskin: experimental: fname= %s , errno= %d\n",
|
||||
fname,errno);
|
||||
*/
|
||||
/* ts A60814 : i see no way to do this more nicely */
|
||||
if (errno == EBUSY && burn_sg_open_abort_busy) {
|
||||
fprintf(stderr,
|
||||
"\nlibburn: FATAL : Application triggered abort on busy drive '%s'\n",
|
||||
fname);
|
||||
/* <<< maybe one should plainly exit here */
|
||||
assert("drive busy" == "non fatal");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* found a drive */
|
||||
ioctl(fd, SG_GET_SCSI_ID, &sid);
|
||||
close(fd);
|
||||
if (sid.scsi_type != TYPE_ROM)
|
||||
continue;
|
||||
|
||||
enumerate_common(fname);
|
||||
}
|
||||
}
|
||||
|
||||
static void enumerate_common(char *fname)
|
||||
{
|
||||
struct burn_drive *t;
|
||||
struct burn_drive out;
|
||||
|
||||
out.devname = burn_strdup(fname);
|
||||
out.fd = -1337;
|
||||
|
||||
out.grab = sg_grab;
|
||||
out.release = sg_release;
|
||||
out.issue_command = sg_issue_command;
|
||||
out.getcaps = spc_getcaps;
|
||||
out.released = 1;
|
||||
out.status = BURN_DISC_UNREADY;
|
||||
|
||||
out.eject = sbc_eject;
|
||||
out.load = sbc_load;
|
||||
out.lock = spc_prevent;
|
||||
out.unlock = spc_allow;
|
||||
out.read_disc_info = spc_sense_write_params;
|
||||
out.get_erase_progress = spc_get_erase_progress;
|
||||
out.test_unit_ready = spc_test_unit_ready;
|
||||
out.probe_write_modes = spc_probe_write_modes;
|
||||
out.read_toc = mmc_read_toc;
|
||||
out.write = mmc_write;
|
||||
out.erase = mmc_erase;
|
||||
out.read_sectors = mmc_read_sectors;
|
||||
out.perform_opc = mmc_perform_opc;
|
||||
out.set_speed = mmc_set_speed;
|
||||
out.send_parameters = spc_select_error_params;
|
||||
out.send_write_parameters = spc_select_write_params;
|
||||
out.send_cue_sheet = mmc_send_cue_sheet;
|
||||
out.sync_cache = mmc_sync_cache;
|
||||
out.get_nwa = mmc_get_nwa;
|
||||
out.close_disc = mmc_close_disc;
|
||||
out.close_session = mmc_close_session;
|
||||
out.idata = malloc(sizeof(struct scsi_inquiry_data));
|
||||
out.idata->valid = 0;
|
||||
out.mdata = malloc(sizeof(struct scsi_mode_data));
|
||||
out.mdata->valid = 0;
|
||||
memset(&out.params, 0, sizeof(struct params));
|
||||
t = burn_drive_register(&out);
|
||||
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
mmc_function_spy("enumerate_common : -------- doing grab");
|
||||
|
||||
/* try to get the drive info */
|
||||
if (sg_grab(t)) {
|
||||
burn_print(2, "getting drive info\n");
|
||||
t->getcaps(t);
|
||||
t->unlock(t);
|
||||
t->released = 1;
|
||||
} else {
|
||||
burn_print(2, "unable to grab new located drive\n");
|
||||
}
|
||||
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
mmc_function_spy("enumerate_common : ----- would release ");
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
we use the sg reference count to decide whether we can use the
|
||||
drive or not.
|
||||
if refcount is not one, drive is open somewhere else.
|
||||
|
||||
ts A60813: this test is too late. O_EXCL is the stronger solution.
|
||||
After all the test was diabled already in icculus.org/burn CVS.
|
||||
*/
|
||||
int sg_grab(struct burn_drive *d)
|
||||
{
|
||||
int fd, count;
|
||||
|
||||
/* ts A60813 */
|
||||
int open_mode = O_RDWR;
|
||||
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
mmc_function_spy("sg_grab");
|
||||
|
||||
|
||||
/* ts A60813
|
||||
O_EXCL with block devices is an unpublished feature
|
||||
of Linux kernels. Possibly introduced 2002.
|
||||
It can only be used if libburn stops opening several
|
||||
file descriptor on the same block device.
|
||||
See comment below */
|
||||
if(burn_sg_open_o_excl)
|
||||
open_mode |= O_EXCL;
|
||||
|
||||
/* ts A60813
|
||||
O_NONBLOCK was hardcoded here. So it should stay default mode. */
|
||||
if(burn_sg_open_o_nonblock)
|
||||
open_mode |= O_NONBLOCK;
|
||||
|
||||
/* ts A60813
|
||||
After enumeration the drive fd is probably still open.
|
||||
-1337 is the initial value of burn_drive.fd and the value after
|
||||
relase of drive. Unclear why not the official error return
|
||||
value -1 of open(2) war used. */
|
||||
/* ts A60822: was if(d->fd == -1337) { */
|
||||
if(! burn_drive_is_open(d)) {
|
||||
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
mmc_function_spy("sg_grab ----------- opening");
|
||||
|
||||
fd = open(d->devname, open_mode);
|
||||
} else
|
||||
fd= d->fd;
|
||||
|
||||
assert(fd != -1337);
|
||||
if (-1 != fd) {
|
||||
|
||||
/* ts A60814:
|
||||
according to my experiments this test would work now ! */
|
||||
|
||||
/* er = ioctl(fd, SG_GET_ACCESS_COUNT, &count);*/
|
||||
count = 1;
|
||||
if (1 == count) {
|
||||
d->fd = fd;
|
||||
fcntl(fd, F_SETOWN, getpid());
|
||||
d->released = 0;
|
||||
return 1;
|
||||
}
|
||||
burn_print(1, "could not acquire drive - already open\n");
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
burn_print(1, "could not acquire drive\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
non zero return means you still have the drive and it's not
|
||||
in a state to be released? (is that even possible?)
|
||||
*/
|
||||
|
||||
int sg_release(struct burn_drive *d)
|
||||
{
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
mmc_function_spy("sg_release");
|
||||
|
||||
if (d->fd < 1) {
|
||||
burn_print(1, "release an ungrabbed drive. die\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
mmc_function_spy("sg_release ----------- closing");
|
||||
|
||||
close(d->fd);
|
||||
d->fd = -1337;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sg_issue_command(struct burn_drive *d, struct command *c)
|
||||
{
|
||||
int done = 0;
|
||||
int err;
|
||||
sg_io_hdr_t s;
|
||||
|
||||
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
char buf[161];
|
||||
sprintf(buf,"sg_issue_command d->fd= %d d->released= %d\n",
|
||||
d->fd,d->released);
|
||||
mmc_function_spy(buf);
|
||||
|
||||
|
||||
c->error = 0;
|
||||
/*
|
||||
this is valid during the mode probe in scan
|
||||
if (d->fd < 1 || d->released) {
|
||||
burn_print(1,
|
||||
"command issued on ungrabbed drive, chaos.\n");
|
||||
burn_print(1, "fd = %d, released = %d\n", d->fd,
|
||||
d->released);
|
||||
}
|
||||
*/
|
||||
memset(&s, 0, sizeof(sg_io_hdr_t));
|
||||
|
||||
s.interface_id = 'S';
|
||||
|
||||
if (c->dir == TO_DRIVE)
|
||||
s.dxfer_direction = SG_DXFER_TO_DEV;
|
||||
else if (c->dir == FROM_DRIVE)
|
||||
s.dxfer_direction = SG_DXFER_FROM_DEV;
|
||||
else if (c->dir == NO_TRANSFER) {
|
||||
s.dxfer_direction = SG_DXFER_NONE;
|
||||
assert(!c->page);
|
||||
}
|
||||
s.cmd_len = c->oplen;
|
||||
s.cmdp = c->opcode;
|
||||
s.mx_sb_len = 32;
|
||||
s.sbp = c->sense;
|
||||
memset(c->sense, 0, sizeof(c->sense));
|
||||
s.timeout = 200000;
|
||||
if (c->page) {
|
||||
s.dxferp = c->page->data;
|
||||
if (c->dir == FROM_DRIVE) {
|
||||
s.dxfer_len = BUFFER_SIZE;
|
||||
/* touch page so we can use valgrind */
|
||||
memset(c->page->data, 0, BUFFER_SIZE);
|
||||
} else {
|
||||
assert(c->page->bytes > 0);
|
||||
s.dxfer_len = c->page->bytes;
|
||||
}
|
||||
} else {
|
||||
s.dxferp = NULL;
|
||||
s.dxfer_len = 0;
|
||||
}
|
||||
s.usr_ptr = c;
|
||||
|
||||
do {
|
||||
err = ioctl(d->fd, SG_IO, &s);
|
||||
assert(err != -1);
|
||||
if (s.sb_len_wr) {
|
||||
if (!c->retry) {
|
||||
c->error = 1;
|
||||
return 1;
|
||||
}
|
||||
switch (scsi_error(d, s.sbp, s.sb_len_wr)) {
|
||||
case RETRY:
|
||||
done = 0;
|
||||
break;
|
||||
case FAIL:
|
||||
done = 1;
|
||||
c->error = 1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
done = 1;
|
||||
}
|
||||
} while (!done);
|
||||
return 1;
|
||||
}
|
||||
|
||||
enum response scsi_error(struct burn_drive *d, unsigned char *sense,
|
||||
int senselen)
|
||||
{
|
||||
int key, asc, ascq;
|
||||
|
||||
senselen = senselen;
|
||||
key = sense[2];
|
||||
asc = sense[12];
|
||||
ascq = sense[13];
|
||||
|
||||
burn_print(12, "CONDITION: 0x%x 0x%x 0x%x on %s %s\n",
|
||||
key, asc, ascq, d->idata->vendor, d->idata->product);
|
||||
|
||||
switch (asc) {
|
||||
case 0:
|
||||
burn_print(12, "NO ERROR!\n");
|
||||
return RETRY;
|
||||
|
||||
case 2:
|
||||
burn_print(1, "not ready\n");
|
||||
return RETRY;
|
||||
case 4:
|
||||
burn_print(1,
|
||||
"logical unit is in the process of becoming ready\n");
|
||||
return RETRY;
|
||||
case 0x20:
|
||||
if (key == 5)
|
||||
burn_print(1, "bad opcode\n");
|
||||
return FAIL;
|
||||
case 0x21:
|
||||
burn_print(1, "invalid address or something\n");
|
||||
return FAIL;
|
||||
case 0x24:
|
||||
if (key == 5)
|
||||
burn_print(1, "invalid field in cdb\n");
|
||||
else
|
||||
break;
|
||||
return FAIL;
|
||||
case 0x26:
|
||||
if ( key == 5 )
|
||||
burn_print( 1, "invalid field in parameter list\n" );
|
||||
return FAIL;
|
||||
case 0x28:
|
||||
if (key == 6)
|
||||
burn_print(1,
|
||||
"Not ready to ready change, medium may have changed\n");
|
||||
else
|
||||
break;
|
||||
return RETRY;
|
||||
case 0x3A:
|
||||
burn_print(12, "Medium not present in %s %s\n",
|
||||
d->idata->vendor, d->idata->product);
|
||||
|
||||
d->status = BURN_DISC_EMPTY;
|
||||
return FAIL;
|
||||
}
|
||||
burn_print(1, "unknown failure\n");
|
||||
burn_print(1, "key:0x%x, asc:0x%x, ascq:0x%x\n", key, asc, ascq);
|
||||
return FAIL;
|
||||
}
|
||||
|
49
libburn/sg.h
49
libburn/sg.h
@ -3,12 +3,60 @@
|
||||
#ifndef __SG
|
||||
#define __SG
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
|
||||
/* >>> To hold all state information of BSD device enumeration
|
||||
which are now local in sg_enumerate() . So that sg_give_next_adr()
|
||||
can work in BSD and sg_enumerate() can use it. */
|
||||
struct burn_drive_enumeration_state {
|
||||
|
||||
#ifdef Scsi_freebsd_old_sg_enumeratE
|
||||
int dummy;
|
||||
#else
|
||||
union ccb ccb;
|
||||
int bufsize, fd;
|
||||
unsigned int i;
|
||||
int skip_device;
|
||||
#endif /* ! Scsi_freebsd_old_sg_enumeratE */
|
||||
|
||||
};
|
||||
typedef struct burn_drive_enumeration_state burn_drive_enumerator_t;
|
||||
|
||||
#else /* __FreeBSD__ */
|
||||
|
||||
/* <<< just for testing the C syntax */
|
||||
struct burn_drive_enumeration_state {
|
||||
int dummy;
|
||||
};
|
||||
typedef struct burn_drive_enumeration_state burn_drive_enumerator_tX;
|
||||
|
||||
typedef int burn_drive_enumerator_t;
|
||||
|
||||
#endif /* ! __FreeBSD__ */
|
||||
|
||||
struct burn_drive;
|
||||
struct command;
|
||||
|
||||
enum response
|
||||
{ RETRY, FAIL };
|
||||
|
||||
/* ts A60925 : ticket 74 */
|
||||
int sg_close_drive_fd(char *fname, int driveno, int *fd, int sorry);
|
||||
|
||||
/* ts A60922 ticket 33 */
|
||||
int sg_give_next_adr(burn_drive_enumerator_t *enm_context,
|
||||
char adr[], int adr_size, int initialize);
|
||||
int sg_is_enumerable_adr(char *adr);
|
||||
int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
|
||||
int *target_no, int *lun_no);
|
||||
|
||||
/* ts A60926 : ticket 33 ++ */
|
||||
int sg_open_scsi_siblings(char *fname, int driveno,
|
||||
int sibling_fds[], int *sibling_count,
|
||||
int host_no, int channel_no, int id_no, int lun_no);
|
||||
int sg_release_siblings(int sibling_fds[], int *sibling_count);
|
||||
int sg_close_drive(struct burn_drive *d);
|
||||
|
||||
void sg_enumerate(void);
|
||||
void ata_enumerate(void);
|
||||
int sg_grab(struct burn_drive *);
|
||||
@ -16,4 +64,5 @@ int sg_release(struct burn_drive *);
|
||||
int sg_issue_command(struct burn_drive *, struct command *);
|
||||
enum response scsi_error(struct burn_drive *, unsigned char *, int);
|
||||
|
||||
|
||||
#endif /* __SG */
|
||||
|
@ -29,8 +29,7 @@ struct burn_source *burn_source_new(void)
|
||||
{
|
||||
struct burn_source *out;
|
||||
|
||||
out = malloc(sizeof(struct burn_source));
|
||||
memset(out, 0, sizeof(struct burn_source));
|
||||
out = calloc(1, sizeof(struct burn_source));
|
||||
out->refcount = 1;
|
||||
return out;
|
||||
}
|
||||
|
110
libburn/spc.c
110
libburn/spc.c
@ -9,7 +9,10 @@
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* ts A61008 */
|
||||
/* #include <a ssert.h> */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "transport.h"
|
||||
@ -20,6 +23,10 @@
|
||||
#include "debug.h"
|
||||
#include "options.h"
|
||||
|
||||
#include "libdax_msgs.h"
|
||||
extern struct libdax_msgs *libdax_messenger;
|
||||
|
||||
|
||||
/* spc command set */
|
||||
static unsigned char SPC_INQUIRY[] = { 0x12, 0, 0, 0, 255, 0 };
|
||||
|
||||
@ -72,7 +79,7 @@ int spc_get_erase_progress(struct burn_drive *d)
|
||||
void spc_inquiry(struct burn_drive *d)
|
||||
{
|
||||
struct buffer buf;
|
||||
struct scsi_inquiry_data *id;
|
||||
struct burn_scsi_inquiry_data *id;
|
||||
struct command c;
|
||||
|
||||
memcpy(c.opcode, SPC_INQUIRY, sizeof(SPC_INQUIRY));
|
||||
@ -84,7 +91,7 @@ void spc_inquiry(struct burn_drive *d)
|
||||
c.dir = FROM_DRIVE;
|
||||
d->issue_command(d, &c);
|
||||
|
||||
id = (struct scsi_inquiry_data *)d->idata;
|
||||
id = (struct burn_scsi_inquiry_data *)d->idata;
|
||||
id->vendor[8] = 0;
|
||||
id->product[16] = 0;
|
||||
id->revision[4] = 0;
|
||||
@ -154,10 +161,24 @@ void spc_sense_caps(struct burn_drive *d)
|
||||
m->cdrw_write = page[3] & 2;
|
||||
m->cdr_read = page[2] & 1;
|
||||
m->cdr_write = page[3] & 1;
|
||||
|
||||
/* ts A61021 : these fields are marked obsolete in MMC 3 */
|
||||
m->max_read_speed = page[8] * 256 + page[9];
|
||||
m->cur_read_speed = page[14] * 256 + page[15];
|
||||
|
||||
/* in MMC-3 : see [30-31] and blocks beginning at [32] */
|
||||
m->max_write_speed = page[18] * 256 + page[19];
|
||||
/* New field to be set by atip */
|
||||
m->min_write_speed = m->max_write_speed;
|
||||
|
||||
/* in MMC-3 : [28-29] */
|
||||
m->cur_write_speed = page[20] * 256 + page[21];
|
||||
|
||||
/* >>> ts A61021 : iterate over all speeds :
|
||||
data[30-31]: number of speed performance descriptor blocks
|
||||
data[32-35]: block 0 : [+2-3] speed in kbytes/sec
|
||||
*/
|
||||
|
||||
m->c2_pointers = page[5] & 16;
|
||||
m->valid = 1;
|
||||
m->underrun_proof = page[4] & 128;
|
||||
@ -202,7 +223,10 @@ void spc_select_error_params(struct burn_drive *d,
|
||||
c.page = &buf;
|
||||
c.page->bytes = 0;
|
||||
c.page->sectors = 0;
|
||||
assert(d->mdata->valid);
|
||||
|
||||
/* ts A61007 : moved up to only caller burn_disc_read() */
|
||||
/* a ssert(d->mdata->valid); */
|
||||
|
||||
memset(c.page->data, 0, 8 + 2 + d->mdata->retry_page_length);
|
||||
c.page->bytes = 8 + 2 + d->mdata->retry_page_length;
|
||||
c.page->data[8] = 1;
|
||||
@ -227,8 +251,9 @@ void spc_sense_write_params(struct burn_drive *d)
|
||||
unsigned char *page;
|
||||
struct command c;
|
||||
|
||||
assert(d->mdata->cdr_write || d->mdata->cdrw_write ||
|
||||
d->mdata->dvdr_write || d->mdata->dvdram_write);
|
||||
/* ts A61007 : Done in soft at only caller burn_drive_grab() */
|
||||
/* a ssert(d->mdata->cdr_write || d->mdata->cdrw_write ||
|
||||
d->mdata->dvdr_write || d->mdata->dvdram_write); */
|
||||
|
||||
memcpy(c.opcode, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
|
||||
c.retry = 1;
|
||||
@ -256,7 +281,9 @@ void spc_select_write_params(struct burn_drive *d,
|
||||
struct command c;
|
||||
int bufe, sim;
|
||||
|
||||
assert(o->drive == d);
|
||||
/* ts A61007 : All current callers are safe. */
|
||||
/* a ssert(o->drive == d); */
|
||||
|
||||
memcpy(c.opcode, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
|
||||
c.retry = 1;
|
||||
c.oplen = sizeof(SPC_MODE_SELECT);
|
||||
@ -264,7 +291,10 @@ void spc_select_write_params(struct burn_drive *d,
|
||||
c.page = &buf;
|
||||
c.page->bytes = 0;
|
||||
c.page->sectors = 0;
|
||||
assert(d->mdata->valid);
|
||||
|
||||
/* ts A61007 : moved up to burn_disc_write() */
|
||||
/* a ssert(d->mdata->valid); */
|
||||
|
||||
memset(c.page->data, 0, 8 + 2 + d->mdata->write_page_length);
|
||||
c.page->bytes = 8 + 2 + d->mdata->write_page_length;
|
||||
c.page->data[8] = 5;
|
||||
@ -375,6 +405,7 @@ void spc_probe_write_modes(struct burn_drive *d)
|
||||
}
|
||||
}
|
||||
|
||||
/** @return -1 = error */
|
||||
int spc_block_type(enum burn_block_types b)
|
||||
{
|
||||
switch (b) {
|
||||
@ -400,6 +431,67 @@ int spc_block_type(enum burn_block_types b)
|
||||
return 12;
|
||||
case BURN_BLOCK_MODE2_OK:
|
||||
return 13;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
assert(0);
|
||||
/* ts A61007 : already prevented in burn_write_opts_set_write_type() */
|
||||
/* a ssert(0); */;
|
||||
}
|
||||
|
||||
/* ts A61021 : the spc specific part of sg.c:enumerate_common()
|
||||
*/
|
||||
int spc_setup_drive(struct burn_drive *d)
|
||||
{
|
||||
d->getcaps = spc_getcaps;
|
||||
d->lock = spc_prevent;
|
||||
d->unlock = spc_allow;
|
||||
d->read_disc_info = spc_sense_write_params;
|
||||
d->get_erase_progress = spc_get_erase_progress;
|
||||
d->test_unit_ready = spc_test_unit_ready;
|
||||
d->probe_write_modes = spc_probe_write_modes;
|
||||
d->send_parameters = spc_select_error_params;
|
||||
d->send_write_parameters = spc_select_write_params;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ts A61021 : the general SCSI specific part of sg.c:enumerate_common()
|
||||
@param flag Bitfiled for control purposes
|
||||
bit0= do not setup spc/sbc/mmc
|
||||
*/
|
||||
int burn_scsi_setup_drive(struct burn_drive *d, int bus_no, int host_no,
|
||||
int channel_no, int target_no, int lun_no, int flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* ts A60923 */
|
||||
d->bus_no = bus_no;
|
||||
d->host = host_no;
|
||||
d->id = target_no;
|
||||
d->channel = channel_no;
|
||||
d->lun = lun_no;
|
||||
|
||||
d->idata = malloc(sizeof(struct burn_scsi_inquiry_data));
|
||||
d->idata->valid = 0;
|
||||
d->mdata = malloc(sizeof(struct scsi_mode_data));
|
||||
d->mdata->valid = 0;
|
||||
|
||||
/* ts A61007 : obsolete Assert in drive_getcaps() */
|
||||
if(d->idata == NULL || d->mdata == NULL) {
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020108,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Could not allocate new drive object", 0, 0);
|
||||
return -1;
|
||||
}
|
||||
if(!(flag & 1)) {
|
||||
ret = spc_setup_drive(d);
|
||||
if (ret<=0)
|
||||
return ret;
|
||||
ret = sbc_setup_drive(d);
|
||||
if (ret<=0)
|
||||
return ret;
|
||||
ret = mmc_setup_drive(d);
|
||||
if (ret<=0)
|
||||
return ret;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -22,4 +22,16 @@ int spc_block_type(enum burn_block_types b);
|
||||
int spc_get_erase_progress(struct burn_drive *d);
|
||||
int spc_test_unit_ready(struct burn_drive *d);
|
||||
|
||||
/* ts A61021 : the spc specific part of sg.c:enumerate_common()
|
||||
*/
|
||||
int spc_setup_drive(struct burn_drive *d);
|
||||
|
||||
/* ts A61021 : the general SCSI specific part of sg.c:enumerate_common()
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= do not setup spc/sbc/mmc
|
||||
*/
|
||||
int burn_scsi_setup_drive(struct burn_drive *d, int bus_no, int host_no,
|
||||
int channel_no, int target_no, int lun_no, int flag);
|
||||
|
||||
|
||||
#endif /*__SPC*/
|
||||
|
@ -1,4 +1,7 @@
|
||||
#include <assert.h>
|
||||
|
||||
/* ts A61008 */
|
||||
/* #include <a ssert.h> */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -7,10 +10,18 @@
|
||||
#include "write.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include "libdax_msgs.h"
|
||||
extern struct libdax_msgs *libdax_messenger;
|
||||
|
||||
|
||||
/* ts A61008 : replaced Assert by if and return 0 */
|
||||
/* a ssert(!(pos > BURN_POS_END)); */
|
||||
|
||||
#define RESIZE(TO, NEW, pos) {\
|
||||
void *tmp;\
|
||||
\
|
||||
assert(!(pos > BURN_POS_END));\
|
||||
if (pos > BURN_POS_END)\
|
||||
return 0;\
|
||||
if (pos == BURN_POS_END)\
|
||||
pos = TO->NEW##s;\
|
||||
if (pos > TO->NEW##s)\
|
||||
@ -28,8 +39,7 @@
|
||||
struct burn_disc *burn_disc_create(void)
|
||||
{
|
||||
struct burn_disc *d;
|
||||
d = malloc(sizeof(struct burn_disc));
|
||||
memset(d, 0, sizeof(struct burn_disc));
|
||||
d = calloc(1, sizeof(struct burn_disc));
|
||||
d->refcnt = 1;
|
||||
d->sessions = 0;
|
||||
d->session = NULL;
|
||||
@ -53,8 +63,7 @@ void burn_disc_free(struct burn_disc *d)
|
||||
struct burn_session *burn_session_create(void)
|
||||
{
|
||||
struct burn_session *s;
|
||||
s = malloc(sizeof(struct burn_session));
|
||||
memset(s, 0, sizeof(struct burn_session));
|
||||
s = calloc(1, sizeof(struct burn_session));
|
||||
s->refcnt = 1;
|
||||
s->tracks = 0;
|
||||
s->track = NULL;
|
||||
@ -94,8 +103,7 @@ int burn_disc_add_session(struct burn_disc *d, struct burn_session *s,
|
||||
struct burn_track *burn_track_create(void)
|
||||
{
|
||||
struct burn_track *t;
|
||||
t = malloc(sizeof(struct burn_track));
|
||||
memset(t, 0, sizeof(struct burn_track));
|
||||
t = calloc(1, sizeof(struct burn_track));
|
||||
t->refcnt = 1;
|
||||
t->indices = 0;
|
||||
t->offset = 0;
|
||||
@ -110,6 +118,9 @@ struct burn_track *burn_track_create(void)
|
||||
t->postgap = 0;
|
||||
t->pregap1 = 0;
|
||||
t->pregap2 = 0;
|
||||
|
||||
/* ts A61024 */
|
||||
t->swap_source_bytes = 0;
|
||||
return t;
|
||||
}
|
||||
|
||||
@ -138,30 +149,34 @@ int burn_session_remove_track(struct burn_session *s, struct burn_track *t)
|
||||
struct burn_track **tmp;
|
||||
int i, pos = -1;
|
||||
|
||||
assert(s->track != NULL);
|
||||
/* ts A61008 */
|
||||
/* a ssert(s->track != NULL); */
|
||||
if (s->track == NULL)
|
||||
return 0;
|
||||
|
||||
burn_track_free(t);
|
||||
|
||||
/* Find the position */
|
||||
for (i = 0; i < s->tracks; i++) {
|
||||
if (t == s->track[i])
|
||||
if (t == s->track[i]) {
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos == -1)
|
||||
return 0;
|
||||
|
||||
/* Is it the last track? */
|
||||
if (pos != s->tracks) {
|
||||
memmove(s->track[pos], s->track[pos + 1],
|
||||
if (pos != s->tracks - 1) {
|
||||
memmove(&s->track[pos], &s->track[pos + 1],
|
||||
sizeof(struct burn_track *) * (s->tracks - (pos + 1)));
|
||||
}
|
||||
|
||||
s->tracks--;
|
||||
tmp = realloc(s->track, sizeof(struct burn_track *) * s->tracks);
|
||||
if (!tmp)
|
||||
return 0;
|
||||
s->track = tmp;
|
||||
if (tmp)
|
||||
s->track = tmp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -192,34 +207,96 @@ void burn_structure_print_track(struct burn_track *t)
|
||||
void burn_track_define_data(struct burn_track *t, int offset, int tail,
|
||||
int pad, int mode)
|
||||
{
|
||||
int type_to_form(int mode, unsigned char *ctladr, int *form);
|
||||
int burn_sector_length(int tracktype);
|
||||
unsigned char ctladr;
|
||||
int form = -1; /* unchanged form will be considered an error too */
|
||||
|
||||
type_to_form(mode, &ctladr, &form);
|
||||
if (form == -1 || burn_sector_length(mode) <= 0) {
|
||||
char msg[160];
|
||||
|
||||
sprintf(msg, "Attempt to set track mode to unusable value %d",
|
||||
mode);
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020115,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
t->offset = offset;
|
||||
t->pad = pad;
|
||||
t->mode = mode;
|
||||
t->tail = tail;
|
||||
}
|
||||
|
||||
|
||||
/* ts A61024 */
|
||||
int burn_track_set_byte_swap(struct burn_track *t, int swap_source_bytes)
|
||||
{
|
||||
if(swap_source_bytes!=0 && swap_source_bytes!=1)
|
||||
return 0;
|
||||
t->swap_source_bytes = swap_source_bytes;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void burn_track_set_isrc(struct burn_track *t, char *country, char *owner,
|
||||
unsigned char year, unsigned int serial)
|
||||
{
|
||||
int i;
|
||||
|
||||
t->isrc.has_isrc = 1;
|
||||
for (i = 0; i < 2; ++i) {
|
||||
assert((country[i] >= '0' || country[i] < '9') &&
|
||||
|
||||
/* ts A61008 : This is always true */
|
||||
/* a ssert((country[i] >= '0' || country[i] < '9') &&
|
||||
(country[i] >= 'a' || country[i] < 'z') &&
|
||||
(country[i] >= 'A' || country[i] < 'Z'));
|
||||
(country[i] >= 'A' || country[i] < 'Z')); */
|
||||
/* ts A61008 : now coordinated with sector.c: char_to_isrc() */
|
||||
if (! ((country[i] >= '0' && country[i] <= '9') ||
|
||||
(country[i] >= 'a' && country[i] <= 'z') ||
|
||||
(country[i] >= 'A' && country[i] <= 'Z') ) )
|
||||
goto is_not_allowed;
|
||||
|
||||
t->isrc.country[i] = country[i];
|
||||
}
|
||||
for (i = 0; i < 3; ++i) {
|
||||
assert((owner[i] >= '0' || owner[i] < '9') &&
|
||||
|
||||
/* ts A61008 : This is always true */
|
||||
/* a ssert((owner[i] >= '0' || owner[i] < '9') &&
|
||||
(owner[i] >= 'a' || owner[i] < 'z') &&
|
||||
(owner[i] >= 'A' || owner[i] < 'Z'));
|
||||
(owner[i] >= 'A' || owner[i] < 'Z')); */
|
||||
/* ts A61008 : now coordinated with sector.c: char_to_isrc() */
|
||||
if (! ((owner[i] >= '0' && owner[i] <= '9') ||
|
||||
(owner[i] >= 'a' && owner[i] <= 'z') ||
|
||||
(owner[i] >= 'A' && owner[i] <= 'Z') ) )
|
||||
goto is_not_allowed;
|
||||
|
||||
t->isrc.owner[i] = owner[i];
|
||||
}
|
||||
assert(year <= 99);
|
||||
|
||||
/* ts A61008 */
|
||||
/* a ssert(year <= 99); */
|
||||
if (year > 99)
|
||||
goto is_not_allowed;
|
||||
|
||||
t->isrc.year = year;
|
||||
assert(serial <= 99999);
|
||||
|
||||
/* ts A61008 */
|
||||
/* a ssert(serial <= 99999); */
|
||||
if (serial > 99999)
|
||||
goto is_not_allowed;
|
||||
|
||||
t->isrc.serial = serial;
|
||||
|
||||
/* ts A61008 */
|
||||
t->isrc.has_isrc = 1;
|
||||
return;
|
||||
is_not_allowed:;
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020114,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Attempt to set ISRC with bad data", 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
void burn_track_clear_isrc(struct burn_track *t)
|
||||
|
@ -41,6 +41,10 @@ struct burn_track
|
||||
/** The track contains a postgap */
|
||||
int postgap;
|
||||
struct isrc isrc;
|
||||
|
||||
/* ts A61024 */
|
||||
/** Byte swapping on source data stream : 0=none , 1=pairwise */
|
||||
int swap_source_bytes;
|
||||
};
|
||||
|
||||
struct burn_session
|
||||
|
@ -1,6 +1,8 @@
|
||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
|
||||
#include <assert.h>
|
||||
/* ts A61008 */
|
||||
/* #include <a ssert.h> */
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -51,7 +53,10 @@ static void write_clonecd2(volatile struct toc *toc, int f)
|
||||
case BURN_MODE2_FORM1:
|
||||
case BURN_MODE2_FORM2:
|
||||
case BURN_MODE_UNINITIALIZED:
|
||||
assert(0); /* unhandled! find out ccd's
|
||||
|
||||
/* ts A61008 : do this softly without Assert */
|
||||
|
||||
a ssert(0); /* unhandled! find out ccd's
|
||||
value for these modes! */
|
||||
}
|
||||
dprintf(f, "PreGapMode=%d\r\n", m);
|
||||
@ -95,7 +100,8 @@ void toc_find_modes(struct burn_drive *d)
|
||||
struct buffer mem;
|
||||
struct burn_toc_entry *e;
|
||||
|
||||
assert(d->busy);
|
||||
/* ts A61008 : to be prevented on the higher levels */
|
||||
/* a ssert(d->busy); */
|
||||
|
||||
mem.bytes = 0;
|
||||
mem.sectors = 1;
|
||||
|
@ -8,16 +8,17 @@
|
||||
#include <pthread.h>
|
||||
/* sg data structures */
|
||||
#include <sys/types.h>
|
||||
#include <scsi/sg.h>
|
||||
#include <scsi/scsi.h>
|
||||
|
||||
/* kludge! glibc headers don't define all the SCSI shit that we use! */
|
||||
#ifndef SG_GET_ACCESS_COUNT
|
||||
# define SG_GET_ACCESS_COUNT 0x2289
|
||||
#endif
|
||||
#ifdef __FreeBSD__
|
||||
|
||||
#define BUFFER_SIZE 65536/2
|
||||
|
||||
#else /* __FreeBSD__ */
|
||||
|
||||
#define BUFFER_SIZE 65536
|
||||
|
||||
#endif /* ! __FreeBSD__ */
|
||||
|
||||
enum transfer_direction
|
||||
{ TO_DRIVE, FROM_DRIVE, NO_TRANSFER };
|
||||
|
||||
@ -55,7 +56,7 @@ struct command
|
||||
struct buffer *page;
|
||||
};
|
||||
|
||||
struct scsi_inquiry_data
|
||||
struct burn_scsi_inquiry_data
|
||||
{
|
||||
char vendor[9];
|
||||
char product[17];
|
||||
@ -78,6 +79,10 @@ struct scsi_mode_data
|
||||
int simulate;
|
||||
int max_read_speed;
|
||||
int max_write_speed;
|
||||
|
||||
/* ts A61021 */
|
||||
int min_write_speed;
|
||||
|
||||
int cur_read_speed;
|
||||
int cur_write_speed;
|
||||
int retry_page_length;
|
||||
@ -90,16 +95,28 @@ struct scsi_mode_data
|
||||
};
|
||||
|
||||
|
||||
#define LIBBURN_SG_MAX_SIBLINGS 16
|
||||
|
||||
/** Gets initialized in enumerate_common() and burn_drive_register() */
|
||||
struct burn_drive
|
||||
{
|
||||
int bus_no;
|
||||
int host;
|
||||
int id;
|
||||
int channel;
|
||||
int lun;
|
||||
char *devname;
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
struct cam_device* cam;
|
||||
#else
|
||||
int fd;
|
||||
|
||||
/* ts A60926 : trying to lock against growisofs /dev/srN, /dev/scdN */
|
||||
int sibling_count;
|
||||
int sibling_fds[LIBBURN_SG_MAX_SIBLINGS];
|
||||
#endif
|
||||
|
||||
/* ts A60904 : ticket 62, contribution by elmom */
|
||||
/**
|
||||
Tells the index in scanned burn_drive_info array.
|
||||
@ -128,11 +145,19 @@ struct burn_drive
|
||||
/* transport functions */
|
||||
int (*grab) (struct burn_drive *);
|
||||
int (*release) (struct burn_drive *);
|
||||
|
||||
/* ts A61021 */
|
||||
int (*drive_is_open) (struct burn_drive *);
|
||||
|
||||
int (*issue_command) (struct burn_drive *, struct command *);
|
||||
|
||||
/* lower level functions */
|
||||
void (*erase) (struct burn_drive *, int);
|
||||
void (*getcaps) (struct burn_drive *);
|
||||
|
||||
/* ts A61021 */
|
||||
void (*read_atip) (struct burn_drive *);
|
||||
|
||||
int (*write) (struct burn_drive *, int, struct buffer *);
|
||||
void (*read_toc) (struct burn_drive *);
|
||||
void (*lock) (struct burn_drive *);
|
||||
@ -154,16 +179,27 @@ struct burn_drive
|
||||
void (*sync_cache) (struct burn_drive *);
|
||||
int (*get_erase_progress) (struct burn_drive *);
|
||||
int (*get_nwa) (struct burn_drive *);
|
||||
void (*close_disc) (struct burn_drive * d, struct burn_write_opts * o);
|
||||
void (*close_session) (struct burn_drive * d,
|
||||
|
||||
/* ts A61009 : removed d in favor of o->drive */
|
||||
/* void (*close_disc) (struct burn_drive * d,
|
||||
struct burn_write_opts * o);
|
||||
void (*close_session) (struct burn_drive * d,
|
||||
struct burn_write_opts * o);
|
||||
*/
|
||||
void (*close_disc) (struct burn_write_opts * o);
|
||||
void (*close_session) ( struct burn_write_opts * o);
|
||||
|
||||
int (*test_unit_ready) (struct burn_drive * d);
|
||||
void (*probe_write_modes) (struct burn_drive * d);
|
||||
struct params params;
|
||||
struct scsi_inquiry_data *idata;
|
||||
struct burn_scsi_inquiry_data *idata;
|
||||
struct scsi_mode_data *mdata;
|
||||
int toc_entries;
|
||||
struct burn_toc_entry *toc_entry;
|
||||
|
||||
/* ts A61023 : get size and free space of drive buffer */
|
||||
int (*read_buffer_capacity) (struct burn_drive *d);
|
||||
|
||||
};
|
||||
|
||||
/* end of generic 'drive' data structures */
|
||||
|
@ -1,5 +1,8 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* ts A61008 */
|
||||
/* #include <a ssert.h> */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "../version.h"
|
||||
#include "util.h"
|
||||
@ -10,7 +13,10 @@ char *burn_strdup(char *s)
|
||||
char *ret;
|
||||
int l;
|
||||
|
||||
assert(s);
|
||||
/* ts A61008 */
|
||||
/* a ssert(s); */
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
|
||||
l = strlen(s) + 1;
|
||||
ret = malloc(l);
|
||||
@ -24,8 +30,11 @@ char *burn_strndup(char *s, int n)
|
||||
char *ret;
|
||||
int l;
|
||||
|
||||
assert(s);
|
||||
assert(n > 0);
|
||||
/* ts A61008 */
|
||||
/* a ssert(s); */
|
||||
/* a ssert(n > 0); */
|
||||
if (s == NULL || n <= 0)
|
||||
return NULL;
|
||||
|
||||
l = strlen(s);
|
||||
ret = malloc(l < n ? l : n);
|
||||
|
187
libburn/write.c
187
libburn/write.c
@ -2,7 +2,11 @@
|
||||
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* ts A61009 */
|
||||
/* #include <a ssert.h> */
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
@ -12,7 +16,6 @@
|
||||
#include "libburn.h"
|
||||
#include "drive.h"
|
||||
#include "transport.h"
|
||||
#include "message.h"
|
||||
#include "crc.h"
|
||||
#include "debug.h"
|
||||
#include "init.h"
|
||||
@ -23,6 +26,10 @@
|
||||
#include "write.h"
|
||||
#include "options.h"
|
||||
|
||||
#include "libdax_msgs.h"
|
||||
extern struct libdax_msgs *libdax_messenger;
|
||||
|
||||
|
||||
static int type_to_ctrl(int mode)
|
||||
{
|
||||
int ctrl = 0;
|
||||
@ -37,7 +44,9 @@ static int type_to_ctrl(int mode)
|
||||
if (mode & BURN_PREEMPHASIS)
|
||||
ctrl |= 1;
|
||||
} else
|
||||
assert(0);
|
||||
/* ts A61008 */
|
||||
/* a ssert(0); */
|
||||
return -1;
|
||||
|
||||
if (mode & BURN_COPY)
|
||||
ctrl |= 2;
|
||||
@ -46,18 +55,40 @@ static int type_to_ctrl(int mode)
|
||||
}
|
||||
|
||||
/* only the ctrl nibble is set here (not adr) */
|
||||
static void type_to_form(int mode, unsigned char *ctladr, int *form)
|
||||
/* ts A61009 : removed "static" , reacted on type_to_ctrl() == -1
|
||||
preserved ignorance towards unknown modes (for now) */
|
||||
void type_to_form(int mode, unsigned char *ctladr, int *form)
|
||||
{
|
||||
*ctladr = type_to_ctrl(mode) << 4;
|
||||
int ret;
|
||||
|
||||
ret = type_to_ctrl(mode) << 4;
|
||||
if (ret == -1) {
|
||||
*ctladr = 0xff;
|
||||
*form = -1;
|
||||
return;
|
||||
}
|
||||
*ctladr = ret;
|
||||
|
||||
if (mode & BURN_AUDIO)
|
||||
*form = 0;
|
||||
if (mode & BURN_MODE0)
|
||||
assert(0);
|
||||
if (mode & BURN_MODE0) {
|
||||
|
||||
/* ts A61009 */
|
||||
/* a ssert(0); */
|
||||
*form = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode & BURN_MODE1)
|
||||
*form = 0x10;
|
||||
if (mode & BURN_MODE2)
|
||||
assert(0); /* XXX someone's gonna want this sometime */
|
||||
if (mode & BURN_MODE2) {
|
||||
|
||||
/* ts A61009 */
|
||||
/* a ssert(0); */ /* XXX someone's gonna want this sometime */
|
||||
*form = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode & BURN_MODE_RAW)
|
||||
*form = 0;
|
||||
if (mode & BURN_SUBCODE_P16) /* must be expanded to R96 */
|
||||
@ -110,7 +141,9 @@ static void print_cue(struct cue_sheet *sheet)
|
||||
#endif /* Libburn_write_with_print_cuE */
|
||||
|
||||
|
||||
static void add_cue(struct cue_sheet *sheet, unsigned char ctladr,
|
||||
/* ts A61009 : changed type from void to int */
|
||||
/** @return 1 = success , <=0 failure */
|
||||
static int add_cue(struct cue_sheet *sheet, unsigned char ctladr,
|
||||
unsigned char tno, unsigned char indx,
|
||||
unsigned char form, unsigned char scms, int lba)
|
||||
{
|
||||
@ -122,7 +155,17 @@ static void add_cue(struct cue_sheet *sheet, unsigned char ctladr,
|
||||
|
||||
sheet->count++;
|
||||
ptr = realloc(sheet->data, sheet->count * 8);
|
||||
assert(ptr);
|
||||
|
||||
/* ts A61009 */
|
||||
/* a ssert(ptr); */
|
||||
if (ptr == NULL) {
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020111,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Could not allocate new auxiliary object (cue_sheet->data)",
|
||||
0, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sheet->data = ptr;
|
||||
unit = sheet->data + (sheet->count - 1) * 8;
|
||||
unit[0] = ctladr;
|
||||
@ -133,12 +176,13 @@ static void add_cue(struct cue_sheet *sheet, unsigned char ctladr,
|
||||
unit[5] = m;
|
||||
unit[6] = s;
|
||||
unit[7] = f;
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o,
|
||||
struct burn_session *session)
|
||||
{
|
||||
int i, m, s, f, form, pform, runtime = -150;
|
||||
int i, m, s, f, form, pform, runtime = -150, ret;
|
||||
unsigned char ctladr;
|
||||
struct burn_drive *d;
|
||||
struct burn_toc_entry *e;
|
||||
@ -150,20 +194,49 @@ struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o,
|
||||
d = o->drive;
|
||||
|
||||
sheet = malloc(sizeof(struct cue_sheet));
|
||||
|
||||
/* ts A61009 : react on failures of malloc(), add_cue_sheet()
|
||||
type_to_form() */
|
||||
if (sheet == NULL) {
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020111,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Could not allocate new auxiliary object (cue_sheet)",
|
||||
0, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sheet->data = NULL;
|
||||
sheet->count = 0;
|
||||
|
||||
type_to_form(tar[0]->mode, &ctladr, &form);
|
||||
add_cue(sheet, ctladr | 1, 0, 0, 1, 0, runtime);
|
||||
add_cue(sheet, ctladr | 1, 1, 0, form, 0, runtime);
|
||||
if (form == -1) {
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020116,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Track mode has unusable value", 0, 0);
|
||||
goto failed;
|
||||
}
|
||||
ret = add_cue(sheet, ctladr | 1, 0, 0, 1, 0, runtime);
|
||||
if (ret <= 0)
|
||||
goto failed;
|
||||
ret = add_cue(sheet, ctladr | 1, 1, 0, form, 0, runtime);
|
||||
if (ret <= 0)
|
||||
goto failed;
|
||||
runtime += 150;
|
||||
|
||||
burn_print(1, "toc for %d tracks:\n", ntr);
|
||||
d->toc_entries = ntr + 3;
|
||||
assert(d->toc_entry == NULL);
|
||||
d->toc_entry = malloc(d->toc_entries * sizeof(struct burn_toc_entry));
|
||||
|
||||
/* ts A61009 */
|
||||
/* a ssert(d->toc_entry == NULL); */
|
||||
if (d->toc_entry != NULL) {
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
d->global_index, 0x00020117,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"toc_entry of drive is already in use", 0, 0);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
d->toc_entry = calloc(d->toc_entries, sizeof(struct burn_toc_entry));
|
||||
e = d->toc_entry;
|
||||
memset((void *)e, 0, d->toc_entries * sizeof(struct burn_toc_entry));
|
||||
e[0].point = 0xA0;
|
||||
if (tar[0]->mode & BURN_AUDIO)
|
||||
e[0].control = TOC_CONTROL_AUDIO;
|
||||
@ -188,7 +261,12 @@ struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o,
|
||||
for (i = 0; i < ntr; i++) {
|
||||
type_to_form(tar[i]->mode, &ctladr, &form);
|
||||
if (pform != form) {
|
||||
add_cue(sheet, ctladr | 1, i + 1, 0, form, 0, runtime);
|
||||
|
||||
ret = add_cue(sheet, ctladr | 1, i + 1, 0, form, 0,
|
||||
runtime);
|
||||
if (ret <= 0)
|
||||
goto failed;
|
||||
|
||||
runtime += 150;
|
||||
/* XXX fix pregap interval 1 for data tracks */
|
||||
/* ts A60813 silence righteous compiler warning about C++ style comments
|
||||
@ -211,7 +289,11 @@ struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o,
|
||||
e[3 + i].control = type_to_ctrl(tar[i]->mode);
|
||||
burn_print(1, "track %d control %d\n", tar[i]->mode,
|
||||
e[3 + i].control);
|
||||
add_cue(sheet, ctladr | 1, i + 1, 1, form, 0, runtime);
|
||||
|
||||
ret = add_cue(sheet, ctladr | 1, i + 1, 1, form, 0, runtime);
|
||||
if (ret <= 0)
|
||||
goto failed;
|
||||
|
||||
runtime += burn_track_get_sectors(tar[i]);
|
||||
/* if we're padding, we'll clear any current shortage.
|
||||
if we're not, we'll slip toc entries by a sector every time our
|
||||
@ -241,8 +323,15 @@ XXX this is untested :)
|
||||
burn_print(1, "point %d (%02d:%02d:%02d)\n",
|
||||
d->toc_entry[i].point, d->toc_entry[i].pmin,
|
||||
d->toc_entry[i].psec, d->toc_entry[i].pframe);
|
||||
add_cue(sheet, ctladr | 1, 0xAA, 1, 1, 0, runtime);
|
||||
ret = add_cue(sheet, ctladr | 1, 0xAA, 1, 1, 0, runtime);
|
||||
if (ret <= 0)
|
||||
goto failed;
|
||||
return sheet;
|
||||
|
||||
failed:;
|
||||
if (sheet != NULL)
|
||||
free((char *) sheet);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int burn_sector_length(int tracktype)
|
||||
@ -253,8 +342,9 @@ int burn_sector_length(int tracktype)
|
||||
return 2352;
|
||||
if (tracktype & BURN_MODE1)
|
||||
return 2048;
|
||||
assert(0);
|
||||
return 12345;
|
||||
/* ts A61009 */
|
||||
/* a ssert(0); */
|
||||
return -1;
|
||||
}
|
||||
|
||||
int burn_subcode_length(int tracktype)
|
||||
@ -395,12 +485,19 @@ int burn_write_track(struct burn_write_opts *o, struct burn_session *s,
|
||||
/* ts A60831: added tnum-line, extended print message on proposal
|
||||
by bonfire-app@wanadoo.fr in http://libburn.pykix.org/ticket/58 */
|
||||
d->progress.track = tnum;
|
||||
|
||||
burn_print(12, "track %d is %d sectors long\n", tnum, sectors);
|
||||
|
||||
if (tnum == s->tracks)
|
||||
tmp = sectors > 150 ? 150 : sectors;
|
||||
|
||||
for (i = 0; i < sectors - tmp; i++) {
|
||||
|
||||
/* ts A61023 : http://libburn.pykix.org/ticket/14
|
||||
From time to time inquire drive buffer */
|
||||
if ((i%64)==0)
|
||||
d->read_buffer_capacity(d);
|
||||
|
||||
if (!sector_data(o, t, 0))
|
||||
return 0;
|
||||
|
||||
@ -409,6 +506,11 @@ int burn_write_track(struct burn_write_opts *o, struct burn_session *s,
|
||||
}
|
||||
for (; i < sectors; i++) {
|
||||
burn_print(1, "last track, leadout prep\n");
|
||||
|
||||
/* ts A61023 */
|
||||
if ((i%64)==0)
|
||||
d->read_buffer_capacity(d);
|
||||
|
||||
if (!sector_data(o, t, 1))
|
||||
return 0;
|
||||
|
||||
@ -439,6 +541,27 @@ int burn_write_track(struct burn_write_opts *o, struct burn_session *s,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ts A61009 */
|
||||
int burn_disc_write_is_ok(struct burn_write_opts *o, struct burn_disc *disc)
|
||||
{
|
||||
int i, t;
|
||||
char msg[80];
|
||||
|
||||
for (i = 0; i < disc->sessions; i++)
|
||||
for (t = 0; t < disc->session[i]->tracks; t++)
|
||||
if (!sector_headers_is_ok(
|
||||
o, disc->session[i]->track[t]->mode))
|
||||
goto bad_track_mode_found;
|
||||
return 1;
|
||||
bad_track_mode_found:;
|
||||
sprintf(msg, "Unsuitable track mode 0x%x in track %d of session %d",
|
||||
disc->session[i]->track[t]->mode, i+1, t+1);
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x0002010a,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void burn_disc_write_sync(struct burn_write_opts *o, struct burn_disc *disc)
|
||||
{
|
||||
struct cue_sheet *sheet;
|
||||
@ -448,7 +571,9 @@ void burn_disc_write_sync(struct burn_write_opts *o, struct burn_disc *disc)
|
||||
int first = 1, i;
|
||||
int res;
|
||||
|
||||
/* ts A60924 : libburn/message.c gets obsoleted
|
||||
burn_message_clear_queue();
|
||||
*/
|
||||
|
||||
burn_print(1, "sync write of %d sessions\n", disc->sessions);
|
||||
d->buffer = &buf;
|
||||
@ -484,6 +609,10 @@ return crap. so we send the command, then ignore the result.
|
||||
d->progress.sectors = 0;
|
||||
d->progress.sector = 0;
|
||||
|
||||
/* ts A61023 */
|
||||
d->progress.buffer_capacity = 0;
|
||||
d->progress.buffer_available = 0;
|
||||
|
||||
d->busy = BURN_DRIVE_WRITING;
|
||||
|
||||
for (i = 0; i < disc->sessions; i++) {
|
||||
@ -492,6 +621,11 @@ return crap. so we send the command, then ignore the result.
|
||||
d->progress.tracks = disc->session[i]->tracks;
|
||||
|
||||
sheet = burn_create_toc_entries(o, disc->session[i]);
|
||||
|
||||
/* ts A61009 */
|
||||
if (sheet == NULL)
|
||||
goto fail;
|
||||
|
||||
/* print_cue(sheet);*/
|
||||
if (o->write_type == BURN_WRITE_SAO)
|
||||
d->send_cue_sheet(d, sheet);
|
||||
@ -539,8 +673,15 @@ return crap. so we send the command, then ignore the result.
|
||||
burn_print(1, "done\n");
|
||||
d->busy = BURN_DRIVE_IDLE;
|
||||
|
||||
/* ts A61012 : This return was traditionally missing, a suspect this
|
||||
to have caused Cdrskin_eject() failures */
|
||||
return;
|
||||
|
||||
fail:
|
||||
d->sync_cache(d);
|
||||
burn_print(1, "done - failed\n");
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index, 0x0002010b,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Burn run failed", 0, 0);
|
||||
d->busy = BURN_DRIVE_IDLE;
|
||||
}
|
||||
|
@ -12,6 +12,10 @@ struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o,
|
||||
struct burn_session *session);
|
||||
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);
|
||||
|
||||
void burn_disc_write_sync(struct burn_write_opts *o, struct burn_disc *disc);
|
||||
int burn_write_leadin(struct burn_write_opts *o,
|
||||
struct burn_session *s, int first);
|
||||
|
@ -319,6 +319,8 @@ ecma119_target_new(struct iso_volset *volset,
|
||||
if (t->joliet)
|
||||
joliet_calc_dir_pos(t, t->joliet_root);
|
||||
calc_file_pos(t, t->root);
|
||||
if (t->joliet)
|
||||
joliet_update_file_pos (t, t->joliet_root);
|
||||
|
||||
if (t->rockridge) {
|
||||
susp_finalize(t, t->root);
|
||||
@ -429,10 +431,10 @@ write_pri_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
struct ecma119_pri_vol_desc *vol = (struct ecma119_pri_vol_desc*)buf;
|
||||
struct iso_volume *volume = t->volset->volume[t->volnum];
|
||||
char *vol_id = wcstoascii(volume->volume_id);
|
||||
char *pub_id = wcstoascii(volume->publisher_id);
|
||||
char *data_id = wcstoascii(volume->data_preparer_id);
|
||||
char *volset_id = wcstoascii(t->volset->volset_id);
|
||||
char *vol_id = str2ascii(volume->volume_id);
|
||||
char *pub_id = str2ascii(volume->publisher_id);
|
||||
char *data_id = str2ascii(volume->data_preparer_id);
|
||||
char *volset_id = str2ascii(t->volset->volset_id);
|
||||
|
||||
vol->vol_desc_type[0] = 1;
|
||||
memcpy(vol->std_identifier, "CD001", 5);
|
||||
|
@ -129,6 +129,7 @@ joliet_calc_dir_pos(struct ecma119_write_target *t,
|
||||
|
||||
root->block = t->curblock;
|
||||
t->curblock += div_up(root->len, t->block_size);
|
||||
|
||||
t->dirlist_joliet[t->curfile++] = root;
|
||||
for (i = 0; i < root->nchildren; i++) {
|
||||
ch = root->children[i];
|
||||
@ -141,6 +142,30 @@ joliet_calc_dir_pos(struct ecma119_write_target *t,
|
||||
t->curfile = 0;
|
||||
}
|
||||
|
||||
void
|
||||
joliet_update_file_pos(struct ecma119_write_target *t,
|
||||
struct joliet_tree_node *dir)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
assert(dir && ISO_ISDIR(dir->iso_self));
|
||||
for (i = 0; i < dir->nchildren; i++) {
|
||||
struct joliet_tree_node *ch;
|
||||
ch = dir->children[i];
|
||||
|
||||
if (!ISO_ISDIR (ch->iso_self)) {
|
||||
struct iso_tree_node *iso = ch->iso_self;
|
||||
ch->block = iso->block;
|
||||
}
|
||||
else
|
||||
joliet_update_file_pos(t, ch);
|
||||
}
|
||||
|
||||
/* reset curfile when we're finished */
|
||||
if (!dir->parent)
|
||||
t->curfile = 0;
|
||||
}
|
||||
|
||||
struct joliet_tree_node*
|
||||
joliet_tree_create(struct ecma119_write_target *t,
|
||||
struct iso_tree_node *iso_root)
|
||||
@ -231,10 +256,10 @@ write_sup_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
struct ecma119_sup_vol_desc *vol = (struct ecma119_sup_vol_desc*)buf;
|
||||
struct iso_volume *volume = t->volset->volume[t->volnum];
|
||||
uint16_t *vol_id = wcstoucs(volume->volume_id);
|
||||
uint16_t *pub_id = wcstoucs(volume->publisher_id);
|
||||
uint16_t *data_id = wcstoucs(volume->data_preparer_id);
|
||||
uint16_t *volset_id = wcstoucs(t->volset->volset_id);
|
||||
uint16_t *vol_id = str2ucs(volume->volume_id);
|
||||
uint16_t *pub_id = str2ucs(volume->publisher_id);
|
||||
uint16_t *data_id = str2ucs(volume->data_preparer_id);
|
||||
uint16_t *volset_id = str2ucs(t->volset->volset_id);
|
||||
int vol_id_len = MIN(32, ucslen(vol_id) * 2);
|
||||
int pub_id_len = MIN(128, ucslen(pub_id) * 2);
|
||||
int data_id_len = MIN(128, ucslen(data_id) * 2);
|
||||
|
@ -52,6 +52,13 @@ joliet_calc_dir_size(struct ecma119_write_target *t, struct joliet_tree_node*);
|
||||
void
|
||||
joliet_calc_dir_pos(struct ecma119_write_target *t, struct joliet_tree_node*);
|
||||
|
||||
/**
|
||||
* Update the position of each file in the joliet hierarchy (to be called
|
||||
* AFTER the file positions in the iso tree have been set).
|
||||
*/
|
||||
void
|
||||
joliet_update_file_pos(struct ecma119_write_target *t, struct joliet_tree_node*);
|
||||
|
||||
/**
|
||||
* Calculate the size of the joliet path table and fill in the list of
|
||||
* directories.
|
||||
|
@ -86,7 +86,7 @@ iso_tree_add_new_file(struct iso_tree_node *parent, const char *name)
|
||||
|
||||
f->volume = parent ? parent->volume : NULL;
|
||||
f->parent = parent;
|
||||
f->name = parent ? towcs(name) : NULL;
|
||||
f->name = parent ? strdup(name) : NULL;
|
||||
f->attrib = get_attrib(parent);
|
||||
f->attrib.st_mode = 0777 | S_IFREG;
|
||||
f->loc.type = LIBISO_NONE;
|
||||
@ -192,7 +192,7 @@ iso_tree_print(const struct iso_tree_node *root, int spaces)
|
||||
memset(sp, ' ', spaces);
|
||||
sp[spaces] = '\0';
|
||||
|
||||
printf("%s%ls\n", sp, root->name);
|
||||
printf("%s%sn", sp, root->name);
|
||||
for (i=0; i < root->nchildren; i++) {
|
||||
iso_tree_print(root->children[i], spaces+2);
|
||||
}
|
||||
@ -219,5 +219,5 @@ void
|
||||
iso_tree_node_set_name(struct iso_tree_node *file, const char *name)
|
||||
{
|
||||
free(file->name);
|
||||
file->name = towcs(name);
|
||||
file->name = strdup(name);
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ struct iso_tree_node
|
||||
{
|
||||
struct iso_volume *volume;
|
||||
struct iso_tree_node *parent;
|
||||
wchar_t *name;
|
||||
char *name;
|
||||
struct stat attrib; /**< The POSIX attributes of this node as
|
||||
* documented in "man 2 stat". */
|
||||
struct iso_file_location loc;
|
||||
|
244
libisofs/util.c
244
libisofs/util.c
@ -4,6 +4,9 @@
|
||||
/**
|
||||
* Utility functions for the Libisofs library.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <wchar.h>
|
||||
#include <iconv.h>
|
||||
@ -13,9 +16,15 @@
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
/* avoids warning and names in iso, joliet and rockridge can't be > 255 bytes
|
||||
* anyway. There are at most 31 characters in iso level 1, 255 for rockridge,
|
||||
* 64 characters (* 2 since UCS) for joliet. */
|
||||
#define NAME_BUFFER_SIZE 255
|
||||
|
||||
int div_up(int n, int div)
|
||||
{
|
||||
return (n + div - 1) / div;
|
||||
@ -26,85 +35,162 @@ int round_up(int n, int mul)
|
||||
return div_up(n, mul) * mul;
|
||||
}
|
||||
|
||||
wchar_t *towcs(const char *str)
|
||||
/* this function must always return a name
|
||||
* since the caller never checks if a NULL
|
||||
* is returned. It also avoids some warnings. */
|
||||
char *str2ascii(const char *src_arg)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
wchar_t *ret = malloc(sizeof(wchar_t) * (len + 1));
|
||||
mbstate_t ps;
|
||||
wchar_t wsrc_[NAME_BUFFER_SIZE];
|
||||
char *src = (char*)wsrc_;
|
||||
char *ret_;
|
||||
char *ret;
|
||||
mbstate_t state;
|
||||
iconv_t conv;
|
||||
size_t numchars;
|
||||
size_t outbytes;
|
||||
size_t inbytes;
|
||||
size_t n;
|
||||
|
||||
memset(&ps, 0, sizeof(ps));
|
||||
n = mbsrtowcs(ret, &str, len, &ps);
|
||||
ret[len] = '\0';
|
||||
|
||||
if (n != len) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *wcstoascii(const wchar_t *wsrc)
|
||||
{
|
||||
if (!wsrc)
|
||||
if (!src_arg)
|
||||
return NULL;
|
||||
|
||||
iconv_t conv = iconv_open("ASCII", "WCHAR_T");
|
||||
size_t outbytes = wcslen(wsrc);
|
||||
size_t inbytes = outbytes * sizeof(wchar_t);
|
||||
char src_[inbytes + sizeof(wchar_t)];
|
||||
char *src = src_;
|
||||
char *ret_, *ret;
|
||||
size_t n;
|
||||
/* convert the string to a wide character string. Note: outbytes
|
||||
* is in fact the number of characters in the string and doesn't
|
||||
* include the last NULL character. */
|
||||
memset(&state, 0, sizeof(state));
|
||||
numchars = mbsrtowcs(wsrc_, &src_arg, NAME_BUFFER_SIZE-1, &state);
|
||||
if (numchars < 0)
|
||||
return NULL;
|
||||
|
||||
inbytes = numchars * sizeof(wchar_t);
|
||||
|
||||
ret_ = malloc(numchars+1);
|
||||
outbytes = numchars;
|
||||
ret = ret_;
|
||||
|
||||
/* initialize iconv */
|
||||
conv = iconv_open("ASCII", "WCHAR_T");
|
||||
if (conv == (iconv_t)-1)
|
||||
return NULL;
|
||||
|
||||
memcpy(src, wsrc, inbytes + sizeof(wchar_t));
|
||||
ret = malloc(outbytes+1);
|
||||
ret[outbytes] = '\0';
|
||||
ret_ = ret;
|
||||
|
||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||
if (n == -1) {
|
||||
free(ret_);
|
||||
return NULL;
|
||||
while(n == -1) {
|
||||
/* The destination buffer is too small. Stops here. */
|
||||
if(errno == E2BIG)
|
||||
break;
|
||||
|
||||
/* An incomplete multi bytes sequence was found. We
|
||||
* can't do anything here. That's quite unlikely. */
|
||||
if(errno == EINVAL)
|
||||
break;
|
||||
|
||||
/* The last possible error is an invalid multi bytes
|
||||
* sequence. Just replace the character with a "_".
|
||||
* Probably the character doesn't exist in ascii like
|
||||
* "é, è, à, ç, ..." in French. */
|
||||
*ret++ = '_';
|
||||
outbytes--;
|
||||
|
||||
if(!outbytes)
|
||||
break;
|
||||
|
||||
/* There was an error with one character but some other remain
|
||||
* to be converted. That's probably a multibyte character.
|
||||
* See above comment. */
|
||||
src += sizeof(wchar_t);
|
||||
inbytes -= sizeof(wchar_t);
|
||||
|
||||
if(!inbytes)
|
||||
break;
|
||||
|
||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||
}
|
||||
|
||||
iconv_close(conv);
|
||||
|
||||
*ret='\0';
|
||||
return ret_;
|
||||
}
|
||||
|
||||
/* FIXME: C&P */
|
||||
uint16_t *wcstoucs(const wchar_t *wsrc)
|
||||
uint16_t *str2ucs(const char *src_arg)
|
||||
{
|
||||
if (!wsrc)
|
||||
return calloc(2, 1); /* empty UCS string */
|
||||
|
||||
iconv_t conv = iconv_open("UCS-2BE", "WCHAR_T");
|
||||
size_t outbytes = wcslen(wsrc) * 2;
|
||||
size_t inbytes = outbytes * sizeof(wchar_t) / 2;
|
||||
char src_[inbytes + sizeof(wchar_t)];
|
||||
char *src = src_;
|
||||
char *ret_, *ret;
|
||||
wchar_t wsrc_[NAME_BUFFER_SIZE];
|
||||
char *src = (char*)wsrc_;
|
||||
char *ret_;
|
||||
char *ret;
|
||||
mbstate_t state;
|
||||
iconv_t conv;
|
||||
size_t outbytes;
|
||||
size_t numchars;
|
||||
size_t inbytes;
|
||||
size_t n;
|
||||
|
||||
if (conv == (iconv_t)-1)
|
||||
return calloc(2, 1);
|
||||
if (!src_arg)
|
||||
return calloc(2, 1); /* empty UCS string */
|
||||
|
||||
memcpy(src, wsrc, inbytes + sizeof(wchar_t));
|
||||
ret = malloc(outbytes + sizeof(wchar_t));
|
||||
ret[outbytes] = 0;
|
||||
ret[outbytes+1] = 0;
|
||||
ret_ = ret;
|
||||
/* convert the string to a wide character string. Note: outbytes
|
||||
* is in fact the number of characters in the string and doesn't
|
||||
* include the last NULL character. */
|
||||
memset(&state, 0, sizeof(state));
|
||||
numchars = mbsrtowcs(wsrc_, &src_arg, NAME_BUFFER_SIZE-1, &state);
|
||||
if (numchars < 0)
|
||||
return calloc(2, 1); /* empty UCS string */
|
||||
|
||||
inbytes = numchars * sizeof(wchar_t);
|
||||
|
||||
outbytes = numchars * sizeof(uint16_t);
|
||||
ret_ = malloc ((numchars+1) * sizeof(uint16_t));
|
||||
ret = ret_;
|
||||
|
||||
/* initialize iconv */
|
||||
conv = iconv_open("UCS-2BE", "WCHAR_T");
|
||||
if (conv == (iconv_t)-1)
|
||||
return calloc(2, 1); /* empty UCS string */
|
||||
|
||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||
if (n == -1) {
|
||||
perror ("error in iconv conversion");
|
||||
free(ret_);
|
||||
return calloc(2, 1);
|
||||
while(n == -1) {
|
||||
/* The destination buffer is too small. Stops here. */
|
||||
if(errno == E2BIG)
|
||||
break;
|
||||
|
||||
/* An incomplete multi bytes sequence was found. We
|
||||
* can't do anything here. That's quite unlikely. */
|
||||
if(errno == EINVAL)
|
||||
break;
|
||||
|
||||
/* The last possible error is an invalid multi bytes
|
||||
* sequence. Just replace the character with a "_".
|
||||
* Probably the character doesn't exist in ascii like
|
||||
* "é, è, à, ç, ..." in French. */
|
||||
*((uint16_t*) ret) = '_';
|
||||
ret += sizeof(uint16_t);
|
||||
outbytes -= sizeof(uint16_t);
|
||||
|
||||
if(!outbytes)
|
||||
break;
|
||||
|
||||
/* There was an error with one character but some other remain
|
||||
* to be converted. That's probably a multibyte character.
|
||||
* See above comment. */
|
||||
src += sizeof(wchar_t);
|
||||
inbytes -= sizeof(wchar_t);
|
||||
|
||||
if(!inbytes)
|
||||
break;
|
||||
|
||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||
}
|
||||
|
||||
iconv_close(conv);
|
||||
|
||||
/* close the ucs string */
|
||||
*((uint16_t*) ret) = 0;
|
||||
|
||||
return (uint16_t*)ret_;
|
||||
}
|
||||
|
||||
|
||||
static int valid_d_char(char c)
|
||||
{
|
||||
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c == '_');
|
||||
@ -132,9 +218,9 @@ static int valid_p_char(char c)
|
||||
|| (c == '.') || (c == '_') || (c == '-');
|
||||
}
|
||||
|
||||
static char *iso_dirid(const wchar_t *src, int size)
|
||||
static char *iso_dirid(const char *src, int size)
|
||||
{
|
||||
char *ret = wcstoascii(src);
|
||||
char *ret = str2ascii(src);
|
||||
size_t len, i;
|
||||
|
||||
if (!ret)
|
||||
@ -153,19 +239,19 @@ static char *iso_dirid(const wchar_t *src, int size)
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *iso_1_dirid(const wchar_t *src)
|
||||
char *iso_1_dirid(const char *src)
|
||||
{
|
||||
return iso_dirid(src, 8);
|
||||
}
|
||||
|
||||
char *iso_2_dirid(const wchar_t *src)
|
||||
char *iso_2_dirid(const char *src)
|
||||
{
|
||||
return iso_dirid(src, 31);
|
||||
}
|
||||
|
||||
char *iso_1_fileid(const wchar_t *wsrc)
|
||||
char *iso_1_fileid(const char *src_arg)
|
||||
{
|
||||
char *src = wcstoascii(wsrc);
|
||||
char *src = str2ascii(src_arg);
|
||||
char *dest;
|
||||
char *dot; /* Position of the last dot in the
|
||||
filename, will be used to calculate
|
||||
@ -214,9 +300,9 @@ char *iso_1_fileid(const wchar_t *wsrc)
|
||||
return dest;
|
||||
}
|
||||
|
||||
char *iso_2_fileid(const wchar_t *wsrc)
|
||||
char *iso_2_fileid(const char *src_arg)
|
||||
{
|
||||
char *src = wcstoascii(wsrc);
|
||||
char *src = str2ascii(src_arg);
|
||||
char *dest;
|
||||
char *dot;
|
||||
int lname, lext, lnname, lnext, pos, i;
|
||||
@ -274,9 +360,9 @@ char *iso_2_fileid(const wchar_t *wsrc)
|
||||
}
|
||||
|
||||
char *
|
||||
iso_p_fileid(const wchar_t *src)
|
||||
iso_p_fileid(const char *src)
|
||||
{
|
||||
char *ret = wcstoascii(src);
|
||||
char *ret = str2ascii(src);
|
||||
size_t i, len;
|
||||
|
||||
if (!ret)
|
||||
@ -291,9 +377,9 @@ iso_p_fileid(const wchar_t *src)
|
||||
}
|
||||
|
||||
uint16_t *
|
||||
iso_j_id(const wchar_t *src)
|
||||
iso_j_id(const char *src_arg)
|
||||
{
|
||||
uint16_t *j_str = wcstoucs(src);
|
||||
uint16_t *j_str = str2ucs(src_arg);
|
||||
size_t len = ucslen(j_str);
|
||||
size_t n;
|
||||
|
||||
@ -338,16 +424,11 @@ void iso_bb(uint8_t *buf, uint32_t num, int bytes)
|
||||
void iso_datetime_7(unsigned char *buf, time_t t)
|
||||
{
|
||||
static int tzsetup = 0;
|
||||
static int tzoffset;
|
||||
int tzoffset;
|
||||
struct tm tm;
|
||||
|
||||
if (!tzsetup) {
|
||||
tzset();
|
||||
|
||||
tzoffset = -timezone / 60 / 15;
|
||||
if (tzoffset < -48)
|
||||
tzoffset += 101;
|
||||
|
||||
tzsetup = 1;
|
||||
}
|
||||
|
||||
@ -359,6 +440,13 @@ void iso_datetime_7(unsigned char *buf, time_t t)
|
||||
buf[3] = tm.tm_hour;
|
||||
buf[4] = tm.tm_min;
|
||||
buf[5] = tm.tm_sec;
|
||||
#ifdef HAVE_TM_GMTOFF
|
||||
tzoffset = -tm.tm_gmtoff / 60 / 15;
|
||||
#else
|
||||
tzoffset = -timezone / 60 / 15;
|
||||
#endif
|
||||
if (tzoffset < -48)
|
||||
tzoffset += 101;
|
||||
buf[6] = tzoffset;
|
||||
}
|
||||
|
||||
@ -389,11 +477,6 @@ void iso_datetime_17(unsigned char *buf, time_t t)
|
||||
} else {
|
||||
if (!tzsetup) {
|
||||
tzset();
|
||||
|
||||
tzoffset = -timezone / 60 / 15;
|
||||
if (tzoffset < -48)
|
||||
tzoffset += 101;
|
||||
|
||||
tzsetup = 1;
|
||||
}
|
||||
|
||||
@ -406,6 +489,13 @@ void iso_datetime_17(unsigned char *buf, time_t t)
|
||||
sprintf((char*)&buf[10], "%02d", tm.tm_min);
|
||||
sprintf((char*)&buf[12], "%02d", MIN(59, tm.tm_sec));
|
||||
memcpy(&buf[14], "00", 2);
|
||||
#ifdef HAVE_TM_GMTOFF
|
||||
tzoffset = -tm.tm_gmtoff / 60 / 15;
|
||||
#else
|
||||
tzoffset = -timezone / 60 / 15;
|
||||
#endif
|
||||
if (tzoffset < -48)
|
||||
tzoffset += 101;
|
||||
buf[16] = tzoffset;
|
||||
}
|
||||
}
|
||||
|
@ -31,18 +31,18 @@ extern inline int round_up(int n, int mul)
|
||||
}
|
||||
|
||||
wchar_t *towcs(const char *);
|
||||
char *wcstoascii(const wchar_t *);
|
||||
uint16_t *wcstoucs(const wchar_t*);
|
||||
char *str2ascii(const char*);
|
||||
uint16_t *str2ucs(const char*);
|
||||
|
||||
/**
|
||||
* Create a level 1 directory identifier.
|
||||
*/
|
||||
char *iso_1_dirid(const wchar_t *src);
|
||||
char *iso_1_dirid(const char *src);
|
||||
|
||||
/**
|
||||
* Create a level 2 directory identifier.
|
||||
*/
|
||||
char *iso_2_dirid(const wchar_t *src);
|
||||
char *iso_2_dirid(const char *src);
|
||||
|
||||
/**
|
||||
* Create a level 1 file identifier that consists of a name, extension and
|
||||
@ -51,7 +51,7 @@ char *iso_2_dirid(const wchar_t *src);
|
||||
* length 3, followed by a separator (;) and a version number (digit 1).
|
||||
* @return NULL if the original name and extension both are of length 0.
|
||||
*/
|
||||
char *iso_1_fileid(const wchar_t *src);
|
||||
char *iso_1_fileid(const char *src);
|
||||
|
||||
/**
|
||||
* Create a level 2 file identifier that consists of a name, extension and
|
||||
@ -60,7 +60,7 @@ char *iso_1_fileid(const wchar_t *src);
|
||||
* followed by a separator (;) and a version number (digit 1).
|
||||
* @return NULL if the original name and extension both are of length 0.
|
||||
*/
|
||||
char *iso_2_fileid(const wchar_t *src);
|
||||
char *iso_2_fileid(const char *src);
|
||||
|
||||
/**
|
||||
* Create a Joliet file or directory identifier that consists of a name,
|
||||
@ -73,7 +73,7 @@ char *iso_2_fileid(const wchar_t *src);
|
||||
* @param size will be set to the size (in bytes) of the identifier.
|
||||
* @return NULL if the original name and extension both are of length 0 or the conversion from the current codeset to UCS-2BE is not available.
|
||||
*/
|
||||
uint16_t *iso_j_id(const wchar_t *src);
|
||||
uint16_t *iso_j_id(const char *src);
|
||||
|
||||
/**
|
||||
* FIXME: what are the requirements for these next two? Is this for RR?
|
||||
@ -82,14 +82,14 @@ uint16_t *iso_j_id(const wchar_t *src);
|
||||
* The resulting file name will not exceed 250 characters.
|
||||
* @return NULL if the original name and extension both are of length 0.
|
||||
*/
|
||||
char *iso_p_fileid(const wchar_t *src);
|
||||
char *iso_p_fileid(const char *src);
|
||||
|
||||
/**
|
||||
* Create a POSIX portable directory name.
|
||||
* The resulting directory name will not exceed 250 characters.
|
||||
* @return NULL if the original name is of length 0.
|
||||
*/
|
||||
char *iso_p_dirid(const wchar_t *src);
|
||||
char *iso_p_dirid(const char *src);
|
||||
|
||||
void iso_lsb(uint8_t *buf, uint32_t num, int bytes);
|
||||
void iso_msb(uint8_t *buf, uint32_t num, int bytes);
|
||||
|
@ -19,7 +19,7 @@ iso_volset_new(struct iso_volume *vol, const char *id)
|
||||
volset->refcount = 1;
|
||||
volset->volume = malloc(sizeof(void *));
|
||||
volset->volume[0] = vol;
|
||||
volset->volset_id = towcs(id);
|
||||
volset->volset_id = strdup(id);
|
||||
|
||||
vol->refcount++;
|
||||
return volset;
|
||||
@ -63,11 +63,11 @@ iso_volume_new_with_root(const char *volume_id,
|
||||
volume->root = root ? root : iso_tree_new_root(volume);
|
||||
|
||||
if (volume_id != NULL)
|
||||
volume->volume_id = towcs(volume_id);
|
||||
volume->volume_id = strdup(volume_id);
|
||||
if (publisher_id != NULL)
|
||||
volume->publisher_id = towcs(publisher_id);
|
||||
volume->publisher_id = strdup(publisher_id);
|
||||
if (data_preparer_id != NULL)
|
||||
volume->data_preparer_id = towcs(data_preparer_id);
|
||||
volume->data_preparer_id = strdup(data_preparer_id);
|
||||
return volume;
|
||||
}
|
||||
|
||||
|
@ -21,9 +21,9 @@ struct iso_volume
|
||||
struct iso_tree_node *root; /**< Root of the directory tree for the
|
||||
volume. */
|
||||
|
||||
wchar_t *volume_id; /**< Volume identifier. */
|
||||
wchar_t *publisher_id; /**< Volume publisher. */
|
||||
wchar_t *data_preparer_id; /**< Volume data preparer. */
|
||||
char *volume_id; /**< Volume identifier. */
|
||||
char *publisher_id; /**< Volume publisher. */
|
||||
char *data_preparer_id; /**< Volume data preparer. */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -38,7 +38,7 @@ struct iso_volset
|
||||
int volset_size; /**< The number of volumes in this
|
||||
volume set. */
|
||||
|
||||
wchar_t *volset_id; /**< The id of this volume set, encoded
|
||||
char *volset_id; /**< The id of this volume set, encoded
|
||||
in the current locale. */
|
||||
};
|
||||
|
||||
|
215
test/dewav.c
Normal file
215
test/dewav.c
Normal file
@ -0,0 +1,215 @@
|
||||
|
||||
/* dewav
|
||||
Demo of libburn extension libdax_audioxtr
|
||||
Audio track data extraction facility of libdax and libburn.
|
||||
Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net>, provided under GPL
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
/* libdax_audioxtr is quite independent of libburn. It only needs
|
||||
the messaging facility libdax_msgs. So we got two build variations:
|
||||
*/
|
||||
#ifdef Dewav_without_libburN
|
||||
|
||||
/* This build environment is standalone relying only on libdax components */
|
||||
#include "../libburn/libdax_msgs.h"
|
||||
struct libdax_msgs *libdax_messenger= NULL;
|
||||
|
||||
#else /* Dewav_without_libburN */
|
||||
|
||||
/* This build environment uses libdax_msgs via libburn */
|
||||
/* Thus the API header of libburn */
|
||||
#include "../libburn/libburn.h"
|
||||
|
||||
#endif /* ! Dewav_without_libburN */
|
||||
|
||||
|
||||
/* The API for .wav extraction */
|
||||
#include "../libburn/libdax_audioxtr.h"
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
/* This program acts as filter from in_path to out_path */
|
||||
char *in_path= "", *out_path= "-";
|
||||
|
||||
/* The read-and-extract object for use with in_path */
|
||||
struct libdax_audioxtr *xtr= NULL;
|
||||
/* The file descriptor eventually detached from xtr */
|
||||
int xtr_fd= -2;
|
||||
|
||||
/* Default output is stdout */
|
||||
int out_fd= 1;
|
||||
|
||||
/* Inquired source parameters */
|
||||
char *fmt, *fmt_info;
|
||||
int num_channels, sample_rate, bits_per_sample, msb_first;
|
||||
off_t data_size;
|
||||
|
||||
/* Auxiliary variables */
|
||||
int ret, i, be_strict= 1, buf_count, detach_fd= 0, extract_all= 0;
|
||||
char buf[2048];
|
||||
|
||||
if(argc < 2)
|
||||
goto help;
|
||||
for(i= 1; i<argc; i++) {
|
||||
if(strcmp(argv[i],"-o")==0) {
|
||||
if(i>=argc-1) {
|
||||
fprintf(stderr,"%s: option -o needs a file address as argument.\n",
|
||||
argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
i++;
|
||||
out_path= argv[i];
|
||||
} else if(strcmp(argv[i],"--lax")==0) {
|
||||
be_strict= 0;
|
||||
} else if(strcmp(argv[i],"--strict")==0) {
|
||||
be_strict= 1;
|
||||
} else if(strcmp(argv[i],"--detach_fd")==0) {
|
||||
/* Test the dirty detach method. Always --extract_all */
|
||||
detach_fd= 1;
|
||||
} else if(strcmp(argv[i],"--extract_all")==0) {
|
||||
/* Dirty : read all available bytes regardless of data_size */
|
||||
extract_all= 1;
|
||||
} else if(strcmp(argv[i],"--help")==0) {
|
||||
help:;
|
||||
fprintf(stderr,
|
||||
"usage: %s [-o output_path|\"-\"] [--lax|--strict] [source_path|\"-\"]\n",
|
||||
argv[0]);
|
||||
exit(0);
|
||||
} else {
|
||||
if(in_path[0]!=0) {
|
||||
fprintf(stderr,"%s: only one input file is allowed.\n", argv[0]);
|
||||
exit(2);
|
||||
}
|
||||
in_path= argv[i];
|
||||
}
|
||||
}
|
||||
if(in_path[0] == 0)
|
||||
in_path= "-";
|
||||
|
||||
|
||||
/* Depending on wether this was built standalone or with full libburn :
|
||||
*/
|
||||
#ifdef Dewav_without_libburN
|
||||
|
||||
/* Initialize and set up libdax messaging system */
|
||||
ret= libdax_msgs_new(&libdax_messenger,0);
|
||||
if(ret<=0) {
|
||||
fprintf(stderr,"Failed to create libdax_messenger object.\n");
|
||||
exit(3);
|
||||
}
|
||||
libdax_msgs_set_severities(libdax_messenger, LIBDAX_MSGS_SEV_NEVER,
|
||||
LIBDAX_MSGS_SEV_NOTE, "", 0);
|
||||
fprintf(stderr, "dewav on libdax\n");
|
||||
|
||||
#else /* Dewav_without_libburN */
|
||||
|
||||
/* Initialize libburn and set up its messaging system */
|
||||
if(burn_initialize() == 0) {
|
||||
fprintf(stderr,"Failed to initialize libburn.\n");
|
||||
exit(3);
|
||||
}
|
||||
/* Print messages of severity NOTE or more directly to stderr */
|
||||
burn_msgs_set_severities("NEVER", "NOTE", "");
|
||||
fprintf(stderr, "dewav on libburn\n");
|
||||
|
||||
#endif /* ! Dewav_without_libburN */
|
||||
|
||||
|
||||
/* Open audio source and create extractor object */
|
||||
ret= libdax_audioxtr_new(&xtr, in_path, 0);
|
||||
if(ret<=0)
|
||||
exit(4);
|
||||
if(strcmp(out_path,"-")!=0) {
|
||||
out_fd= open(out_path, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
if(out_fd == -1) {
|
||||
fprintf(stderr, "Cannot open file: %s\n", out_path);
|
||||
fprintf(stderr, "Error reported: '%s' (%d)\n",strerror(errno), errno);
|
||||
exit(5);
|
||||
}
|
||||
}
|
||||
/* Obtain and print parameters of audio source */
|
||||
libdax_audioxtr_get_id(xtr, &fmt, &fmt_info,
|
||||
&num_channels, &sample_rate, &bits_per_sample, &msb_first, 0);
|
||||
fprintf(stderr, "Detected format: %s\n", fmt_info);
|
||||
libdax_audioxtr_get_size(xtr, &data_size, 0);
|
||||
fprintf(stderr, "Data size : %.f bytes\n", (double) data_size);
|
||||
if((strcmp(fmt,".wav")!=0 && strcmp(fmt,".au")!=0) ||
|
||||
num_channels!=2 || sample_rate!=44100 || bits_per_sample!=16) {
|
||||
fprintf(stderr,
|
||||
"%sAudio source parameters do not comply to cdrskin/README specs\n",
|
||||
(be_strict ? "" : "WARNING: "));
|
||||
if(be_strict)
|
||||
exit(6);
|
||||
}
|
||||
if(msb_first==0)
|
||||
fprintf(stderr,
|
||||
"NOTE: Extracted data to be written with cdrskin option -swab\n");
|
||||
|
||||
if(detach_fd) {
|
||||
/* Take over fd from xtr */;
|
||||
ret= libdax_audioxtr_detach_fd(xtr, &xtr_fd, 0);
|
||||
if(ret<=0) {
|
||||
fprintf(stderr, "Cannot detach file descriptor from extractor\n");
|
||||
exit(8);
|
||||
}
|
||||
/* not needed any more */
|
||||
libdax_audioxtr_destroy(&xtr, 0);
|
||||
fprintf(stderr, "Note: detached fd and freed extractor object.\n");
|
||||
}
|
||||
|
||||
/* Extract and put out raw audio data */;
|
||||
while(1) {
|
||||
if(detach_fd) {
|
||||
buf_count= read(xtr_fd, buf, sizeof(buf));
|
||||
if(buf_count==-1)
|
||||
fprintf(stderr,"Error while reading from detached fd\n(%d) '%s'\n",
|
||||
errno, strerror(errno));
|
||||
} else {
|
||||
buf_count= libdax_audioxtr_read(xtr, buf, sizeof(buf), !!extract_all);
|
||||
}
|
||||
if(buf_count < 0)
|
||||
exit(7);
|
||||
if(buf_count == 0)
|
||||
break;
|
||||
|
||||
ret= write(out_fd, buf, buf_count);
|
||||
if(ret == -1) {
|
||||
fprintf(stderr, "Failed to write buffer of %d bytes to: %s\n",
|
||||
buf_count, out_path);
|
||||
fprintf(stderr, "Error reported: '%s' (%d)\n", strerror(errno), errno);
|
||||
exit(5);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Shutdown */
|
||||
if(out_fd>2)
|
||||
close(out_fd);
|
||||
/* ( It is permissible to do this with xtr==NULL ) */
|
||||
libdax_audioxtr_destroy(&xtr, 0);
|
||||
|
||||
#ifdef Dewav_without_libburN
|
||||
|
||||
libdax_msgs_destroy(&libdax_messenger,0);
|
||||
|
||||
#else /* Dewav_without_libburN */
|
||||
|
||||
burn_finish();
|
||||
|
||||
#endif /* ! Dewav_without_libburN */
|
||||
|
||||
exit(0);
|
||||
}
|
164
test/fake_au.c
Normal file
164
test/fake_au.c
Normal file
@ -0,0 +1,164 @@
|
||||
|
||||
/* fake_au
|
||||
Fakes a file in SUN .au format from a raw little-endian PCM audio file
|
||||
(e.g. a file extracted from .wav by test/dewav). The input data are assumed
|
||||
to be 16 bit, stereo, 44100 Hz.
|
||||
Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net>, provided under GPL
|
||||
|
||||
Info used: http://www.opengroup.org/public/pubs/external/auformat.html
|
||||
*/
|
||||
|
||||
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
int fake_write(unsigned char *buf, size_t size, FILE *fp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret= fwrite(buf,size,1,fp);
|
||||
if(ret==1)
|
||||
return(1);
|
||||
fprintf(stderr,"Error %d while writing: '%s'\n",errno,strerror(errno));
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret, i;
|
||||
unsigned data_size= 0,byte_count,exit_value= 0;
|
||||
FILE *fp_out= stdout,*fp_in= stdin;
|
||||
unsigned char buf[4];
|
||||
char out_path[4096],in_path[4096];
|
||||
struct stat stbuf;
|
||||
|
||||
strcpy(out_path,"-");
|
||||
strcpy(in_path,"");
|
||||
if(argc < 2) {
|
||||
exit_value= 1;
|
||||
goto help;
|
||||
}
|
||||
for(i= 1; i<argc; i++) {
|
||||
if(strcmp(argv[i],"-o")==0) {
|
||||
if(i>=argc-1) {
|
||||
fprintf(stderr,"%s: option -o needs a file address as argument.\n",
|
||||
argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
i++;
|
||||
strcpy(out_path, argv[i]);
|
||||
} else if(strcmp(argv[i],"--stdin_size")==0) {
|
||||
if(i>=argc-1) {
|
||||
fprintf(stderr,"%s: option --stdin_size needs a number as argument.\n",
|
||||
argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
i++;
|
||||
sscanf(argv[i],"%u",&data_size);
|
||||
} else if(strcmp(argv[i],"--help")==0) {
|
||||
exit_value= 0;
|
||||
help:;
|
||||
fprintf(stderr,"usage: %s \\\n", argv[0]);
|
||||
fprintf(stderr," [-o output_path|\"-\"] [source_path | --stdin_size size]\n");
|
||||
fprintf(stderr,
|
||||
"Disguises an extracted .wav stream as .au stereo, 16bit, 44100Hz\n");
|
||||
fprintf(stderr,
|
||||
"stdin gets byte-swapped and appended up to the announced data_size.\n");
|
||||
exit(exit_value);
|
||||
} else {
|
||||
if(in_path[0]!=0) {
|
||||
fprintf(stderr,"%s: only one input file is allowed.\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
strcpy(in_path, argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if(strcmp(in_path,"-")==0 || in_path[0]==0) {
|
||||
if(data_size==0) {
|
||||
fprintf(stderr,"%s: input from stdin needs option --stdin_size.\n",
|
||||
argv[0]);
|
||||
exit(6);
|
||||
}
|
||||
fp_in= stdin;
|
||||
} else {
|
||||
fp_in= fopen(in_path,"r");
|
||||
if(stat(in_path,&stbuf)!=-1)
|
||||
data_size= stbuf.st_size;
|
||||
}
|
||||
if(fp_in==NULL) {
|
||||
fprintf(stderr,"Error %d while fopen(\"%s\",\"r\") : '%s'\n",
|
||||
errno,in_path,strerror(errno));
|
||||
exit(2);
|
||||
}
|
||||
|
||||
if(strcmp(out_path,"-")==0) {
|
||||
fp_out= stdout;
|
||||
} else {
|
||||
if(stat(out_path,&stbuf)!=-1) {
|
||||
fprintf(stderr,"%s: file '%s' already existing\n",argv[0],out_path);
|
||||
exit(4);
|
||||
}
|
||||
fp_out= fopen(out_path,"w");
|
||||
}
|
||||
if(fp_out==NULL) {
|
||||
fprintf(stderr,"Error %d while fopen(\"%s\",\"w\") : '%s'\n",
|
||||
errno,out_path,strerror(errno));
|
||||
exit(2);
|
||||
}
|
||||
|
||||
fake_write((unsigned char *) ".snd",4,fp_out); /* magic number */
|
||||
buf[0]= buf[1]= buf[2]= 0;
|
||||
buf[3]= 32;
|
||||
fake_write(buf,4,fp_out); /* data_location */
|
||||
buf[0]= (data_size>>24)&0xff;
|
||||
buf[1]= (data_size>>16)&0xff;
|
||||
buf[2]= (data_size>>8)&0xff;
|
||||
buf[3]= (data_size)&0xff;
|
||||
fake_write(buf,4,fp_out); /* data_size */
|
||||
buf[0]= buf[1]= buf[2]= 0;
|
||||
buf[3]= 3;
|
||||
fake_write(buf,4,fp_out); /* encoding 16 Bit PCM */
|
||||
buf[0]= buf[1]= 0;
|
||||
buf[2]= 172;
|
||||
buf[3]= 68;
|
||||
fake_write(buf,4,fp_out); /* sample rate 44100 Hz */
|
||||
buf[0]= buf[1]= buf[2]= 0;
|
||||
buf[3]= 2;
|
||||
fake_write(buf,4,fp_out); /* number of channels */
|
||||
buf[0]= buf[1]= buf[2]= buf[3]= 0;
|
||||
fake_write(buf,4,fp_out); /* padding */
|
||||
fake_write(buf,4,fp_out); /* padding */
|
||||
|
||||
for(byte_count= 0; byte_count<data_size; byte_count+=2) {
|
||||
ret= fread(buf,2,1,fp_in);
|
||||
if(ret<=0) {
|
||||
fprintf(stderr,"Premature end end of input\n");
|
||||
exit_value= 5;
|
||||
break;
|
||||
}
|
||||
buf[3]= buf[0];
|
||||
buf[2]= buf[1];
|
||||
ret= fake_write(buf+2,2,fp_out);
|
||||
if(ret<=0) {
|
||||
exit_value= 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(fp_out!=stdout)
|
||||
fclose(fp_out);
|
||||
if(fp_in!=stdin)
|
||||
fclose(fp_in);
|
||||
fprintf(stderr, "Swapped and appended: %u stdin bytes\n",byte_count);
|
||||
exit(exit_value);
|
||||
}
|
||||
|
226
test/libburner.c
226
test/libburner.c
@ -16,6 +16,8 @@
|
||||
|
||||
Before you can do anything, you have to initialize libburn by
|
||||
burn_initialize()
|
||||
and provide some signal and abort handling, e.g. by the builtin handler, by
|
||||
burn_set_signal_handling()
|
||||
as it is done in main() at the end of this file. Then you aquire a
|
||||
drive in an appropriate way conforming to the API. The two main
|
||||
approaches are shown here in application functions:
|
||||
@ -74,13 +76,6 @@ static unsigned int drive_count;
|
||||
static int drive_is_grabbed = 0;
|
||||
|
||||
|
||||
/** Here you may enable simulated burn by default. This does not apply to
|
||||
blanking. Anyway, some CD recorders obey the request to simulate, some do
|
||||
not. Explicit options are: --burn_for_real and --try_to_simulate
|
||||
*/
|
||||
static int simulate_burn = 0;
|
||||
|
||||
|
||||
/* Some in-advance definitions to allow a more comprehensive ordering
|
||||
of the functions and their explanations in here */
|
||||
int libburner_aquire_by_adr(char *drive_adr);
|
||||
@ -248,17 +243,15 @@ int libburner_aquire_by_driveno(int *driveno)
|
||||
|
||||
To our knowledge it is hardly possible to abort an ongoing blank operation
|
||||
because after start it is entirely handled by the drive.
|
||||
So expect a blank run to survive the end of the blanking process and be
|
||||
patient for the usual timespan of a normal blank run. Only after that
|
||||
time has surely elapsed, only then you should start any rescue attempts
|
||||
with the drive. If necessary at all.
|
||||
So expect signal handling to wait the normal blanking timespan until it
|
||||
can allow the process to end. External kill -9 will not help the drive.
|
||||
*/
|
||||
int libburner_blank_disc(struct burn_drive *drive, int blank_fast)
|
||||
{
|
||||
enum burn_disc_status disc_state;
|
||||
struct burn_progress progress;
|
||||
|
||||
while (burn_drive_get_status(drive, NULL))
|
||||
while (burn_drive_get_status(drive, NULL) != BURN_DRIVE_IDLE)
|
||||
usleep(1001);
|
||||
|
||||
while ((disc_state = burn_disc_get_status(drive)) == BURN_DISC_UNREADY)
|
||||
@ -291,7 +284,7 @@ int libburner_blank_disc(struct burn_drive *drive, int blank_fast)
|
||||
printf(
|
||||
"Expect some garbage sector numbers and some zeros at first.\n");
|
||||
burn_disc_erase(drive, blank_fast);
|
||||
while (burn_drive_get_status(drive, &progress)) {
|
||||
while (burn_drive_get_status(drive, &progress) != BURN_DRIVE_IDLE) {
|
||||
printf("Blanking sector %d\n", progress.sector);
|
||||
sleep(1);
|
||||
}
|
||||
@ -321,76 +314,74 @@ int libburner_regrab(struct burn_drive *drive) {
|
||||
}
|
||||
|
||||
|
||||
/** Brings the preformatted image (ISO 9660, afio, ext2, whatever) onto media.
|
||||
/** 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.
|
||||
Audio tracks get padded to complete their last sector.
|
||||
|
||||
To make sure your image is fully readable on any Linux machine, this
|
||||
function adds 300 kB of padding to the track.
|
||||
|
||||
Without a signal handler it is quite dangerous to abort the process
|
||||
while this function is active. See cdrskin/cdrskin.c and its usage
|
||||
of cdrskin/cleanup.[ch] for an example of application provided
|
||||
abort handling. It must cope with 2 of 3 threads reporting for
|
||||
being handled.
|
||||
|
||||
Without signal handler have ready a command line
|
||||
cdrecord dev=... -reset
|
||||
with a dev= previously inquired by cdrecord [dev=ATA] -scanbus
|
||||
in order to get your drive out of shock state after raw abort.
|
||||
Thanks to Joerg Schilling for helping out unquestioned. :)
|
||||
|
||||
In general, libburn is less prone to system problems than cdrecord,
|
||||
i believe. But cdrecord had long years of time to complete itself.
|
||||
We are still practicing. Help us with that. :))
|
||||
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.
|
||||
*/
|
||||
int libburner_payload(struct burn_drive *drive, const char *source_adr,
|
||||
off_t size)
|
||||
int libburner_payload(struct burn_drive *drive,
|
||||
char source_adr[][4096], int source_adr_count,
|
||||
off_t stdin_size, int simulate_burn, int all_tracks_type)
|
||||
{
|
||||
struct burn_source *data_src;
|
||||
struct burn_disc *target_disc;
|
||||
struct burn_session *session;
|
||||
struct burn_write_opts *burn_options;
|
||||
enum burn_disc_status disc_state;
|
||||
struct burn_track *track;
|
||||
struct burn_track *track, *tracklist[99];
|
||||
struct burn_progress progress;
|
||||
time_t start_time;
|
||||
int last_sector = 0;
|
||||
int last_sector = 0, padding = 0, trackno;
|
||||
char *adr;
|
||||
|
||||
if (all_tracks_type != BURN_AUDIO) {
|
||||
all_tracks_type = BURN_MODE1;
|
||||
/* a padding of 300 kB helps to avoid the read-ahead bug */
|
||||
padding = 300*1024;
|
||||
}
|
||||
|
||||
target_disc = burn_disc_create();
|
||||
session = burn_session_create();
|
||||
burn_disc_add_session(target_disc, session, BURN_POS_END);
|
||||
track = burn_track_create();
|
||||
|
||||
/* a padding of 300 kB is helpful to avoid the read-ahead bug */
|
||||
burn_track_define_data(track, 0, 300*1024, 1, BURN_MODE1);
|
||||
for (trackno = 0 ; trackno < source_adr_count; trackno++) {
|
||||
tracklist[trackno] = track = burn_track_create();
|
||||
burn_track_define_data(track, 0, padding, 1, all_tracks_type);
|
||||
|
||||
if (source_adr[0] == '-' && source_adr[1] == 0) {
|
||||
data_src = burn_fd_source_new(0, -1, size);
|
||||
adr = source_adr[trackno];
|
||||
if (adr[0] == '-' && adr[1] == 0) {
|
||||
data_src = burn_fd_source_new(0, -1, stdin_size);
|
||||
printf("Note: using standard input as source with %.f bytes\n",
|
||||
(double) size);
|
||||
} else
|
||||
data_src = burn_file_source_new(source_adr, NULL);
|
||||
if (data_src == NULL) {
|
||||
(double) stdin_size);
|
||||
} else
|
||||
data_src = burn_file_source_new(adr, NULL);
|
||||
if (data_src == NULL) {
|
||||
fprintf(stderr,
|
||||
"FATAL: Could not open data source '%s'.\n",source_adr);
|
||||
"FATAL: Could not open data source '%s'.\n",adr);
|
||||
if(errno!=0)
|
||||
fprintf(stderr,"(Most recent system error: %s )\n",
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (burn_track_set_source(track, data_src) != BURN_SOURCE_OK) {
|
||||
}
|
||||
if (burn_track_set_source(track, data_src) != BURN_SOURCE_OK) {
|
||||
printf("FATAL: Cannot attach source object to track object\n");
|
||||
return 0;
|
||||
}
|
||||
burn_session_add_track(session, track, BURN_POS_END);
|
||||
burn_source_free(data_src);
|
||||
}
|
||||
|
||||
while (burn_drive_get_status(drive, NULL))
|
||||
usleep(1001);
|
||||
burn_session_add_track(session, track, BURN_POS_END);
|
||||
printf("Track %d : source is '%s'\n", trackno, adr);
|
||||
burn_source_free(data_src);
|
||||
} /* trackno loop end */
|
||||
|
||||
while (burn_drive_get_status(drive, NULL) != BURN_DRIVE_IDLE)
|
||||
usleep(100001);
|
||||
|
||||
/* Evaluate drive and media */
|
||||
while ((disc_state = burn_disc_get_status(drive)) == BURN_DISC_UNREADY)
|
||||
usleep(1001);
|
||||
usleep(100001);
|
||||
if (disc_state != BURN_DISC_BLANK) {
|
||||
if (disc_state == BURN_DISC_FULL ||
|
||||
disc_state == BURN_DISC_APPENDABLE) {
|
||||
@ -438,19 +429,21 @@ int libburner_payload(struct burn_drive *drive, const char *source_adr,
|
||||
burn_write_opts_free(burn_options);
|
||||
while (burn_drive_get_status(drive, NULL) == BURN_DRIVE_SPAWNING)
|
||||
usleep(1002);
|
||||
while (burn_drive_get_status(drive, &progress)) {
|
||||
while (burn_drive_get_status(drive, &progress) != BURN_DRIVE_IDLE) {
|
||||
if( progress.sectors <= 0 || progress.sector == last_sector)
|
||||
printf(
|
||||
"Thank you for being patient since %d seconds.\n",
|
||||
(int) (time(0) - start_time));
|
||||
else
|
||||
printf("Burning sector %d of %d\n",
|
||||
printf("Track %d : sector %d of %d\n", progress.track,
|
||||
progress.sector, progress.sectors);
|
||||
last_sector = progress.sector;
|
||||
sleep(1);
|
||||
}
|
||||
printf("\n");
|
||||
burn_track_free(track);
|
||||
|
||||
for (trackno = 0 ; trackno < source_adr_count; trackno++)
|
||||
burn_track_free(tracklist[trackno]);
|
||||
burn_session_free(session);
|
||||
burn_disc_free(target_disc);
|
||||
if(simulate_burn)
|
||||
@ -459,28 +452,34 @@ int libburner_payload(struct burn_drive *drive, const char *source_adr,
|
||||
}
|
||||
|
||||
|
||||
/** Converts command line arguments into a few program parameters.
|
||||
/** The setup parameters of libburn */
|
||||
static char drive_adr[BURN_DRIVE_ADR_LEN]= {""};
|
||||
static int driveno= 0;
|
||||
static int do_blank= 0;
|
||||
static char source_adr[99][4096];
|
||||
static int source_adr_count= 0;
|
||||
static off_t stdin_size= 650*1024*1024;
|
||||
static int simulate_burn = 0;
|
||||
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, char drive_adr[], int *driveno,
|
||||
int *do_blank, char source_adr[], off_t *size)
|
||||
int libburner_setup(int argc, char **argv)
|
||||
{
|
||||
int i, insuffient_parameters = 0;
|
||||
int print_help = 0;
|
||||
|
||||
drive_adr[0] = 0;
|
||||
*driveno = 0;
|
||||
*do_blank = 0;
|
||||
source_adr[0] = 0;
|
||||
*size = 650*1024*1024;
|
||||
int i, insuffient_parameters = 0, print_help = 0;
|
||||
|
||||
for (i = 1; i < argc; ++i) {
|
||||
if (!strcmp(argv[i], "--blank_fast")) {
|
||||
*do_blank = 1;
|
||||
if (!strcmp(argv[i], "--audio")) {
|
||||
all_tracks_type = BURN_AUDIO;
|
||||
|
||||
} else if (!strcmp(argv[i], "--blank_fast")) {
|
||||
do_blank = 1;
|
||||
|
||||
} else if (!strcmp(argv[i], "--blank_full")) {
|
||||
*do_blank = 2;
|
||||
do_blank = 2;
|
||||
|
||||
} else if (!strcmp(argv[i], "--burn_for_real")) {
|
||||
simulate_burn = 0;
|
||||
@ -492,10 +491,10 @@ int libburner_setup(int argc, char **argv, char drive_adr[], int *driveno,
|
||||
return 1;
|
||||
} else if (strcmp(argv[i], "-") == 0) {
|
||||
drive_adr[0] = 0;
|
||||
*driveno = -1;
|
||||
driveno = -1;
|
||||
} else if (isdigit(argv[i][0])) {
|
||||
drive_adr[0] = 0;
|
||||
*driveno = atoi(argv[i]);
|
||||
driveno = atoi(argv[i]);
|
||||
} else {
|
||||
if(strlen(argv[i]) >= BURN_DRIVE_ADR_LEN) {
|
||||
fprintf(stderr,"--drive address too long (max. %d)\n",
|
||||
@ -510,58 +509,62 @@ int libburner_setup(int argc, char **argv, char drive_adr[], int *driveno,
|
||||
fprintf(stderr,"--stdin_size requires an argument\n");
|
||||
return 3;
|
||||
} else
|
||||
*size = atoi(argv[i]);
|
||||
if (*size < 600*1024) /* seems to be minimum readable track size */
|
||||
*size = 600*1024;
|
||||
stdin_size = atoi(argv[i]);
|
||||
if (stdin_size < 600*1024) /* minimum readable track size */
|
||||
stdin_size = 600*1024;
|
||||
} else if (!strcmp(argv[i], "--try_to_simulate")) {
|
||||
simulate_burn = 1;
|
||||
|
||||
} else if (!strcmp(argv[i], "--verbose")) {
|
||||
++i;
|
||||
if (i >= argc) {
|
||||
fprintf(stderr,"--verbose requires an argument\n");
|
||||
return 4;
|
||||
} else
|
||||
burn_set_verbosity(atoi(argv[i]));
|
||||
} else if (!strcmp(argv[i], "--help")) {
|
||||
print_help = 1;
|
||||
|
||||
} else if (!strncmp(argv[i], "--",2)) {
|
||||
fprintf(stderr, "Unidentified option: %s\n", argv[i]);
|
||||
return 7;
|
||||
} else {
|
||||
if(strlen(argv[i]) >= 4096) {
|
||||
fprintf(stderr, "Source address too long (max. %d)\n", 4096-1);
|
||||
return 5;
|
||||
}
|
||||
strcpy(source_adr, argv[i]);
|
||||
if(source_adr_count >= 99) {
|
||||
fprintf(stderr, "Too many tracks (max. 99)\n");
|
||||
return 6;
|
||||
}
|
||||
strcpy(source_adr[source_adr_count], argv[i]);
|
||||
source_adr_count++;
|
||||
}
|
||||
}
|
||||
insuffient_parameters = 1;
|
||||
if (*driveno < 0)
|
||||
if (driveno < 0)
|
||||
insuffient_parameters = 0;
|
||||
if (source_adr[0] != 0)
|
||||
if (source_adr_count > 0)
|
||||
insuffient_parameters = 0;
|
||||
if (*do_blank)
|
||||
if (do_blank)
|
||||
insuffient_parameters = 0;
|
||||
if (print_help || insuffient_parameters ) {
|
||||
printf("Usage: %s\n", argv[0]);
|
||||
printf(" [--drive <address>|<driveno>|\"-\"]\n");
|
||||
printf(" [--verbose <level>] [--blank_fast|--blank_full]\n");
|
||||
printf(" [--burn_for_real|--try_to_simulate] [--stdin_size <bytes>]\n");
|
||||
printf(" [<imagefile>|\"-\"]\n");
|
||||
printf(" [--blank_fast|--blank_full] [--audio]\n");
|
||||
printf(" [--try_to_simulate] [--stdin_size <bytes>]\n");
|
||||
printf(" [<one or more imagefiles>|\"-\"]\n");
|
||||
printf("Examples\n");
|
||||
printf("A bus scan (needs rw-permissions to see a drive):\n");
|
||||
printf(" %s --drive -\n",argv[0]);
|
||||
printf("Burn a file to drive chosen by number:\n");
|
||||
printf(" %s --drive 0 --burn_for_real my_image_file\n",
|
||||
printf(" %s --drive 0 my_image_file\n",
|
||||
argv[0]);
|
||||
printf("Burn a file to drive chosen by persistent address:\n");
|
||||
printf(" %s --drive /dev/hdc --burn_for_real my_image_file\n", argv[0]);
|
||||
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 0 --blank_fast\n",argv[0]);
|
||||
printf(" %s --drive /dev/hdc --blank_fast\n",argv[0]);
|
||||
printf("Burn two audio tracks\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]);
|
||||
printf("Burn a compressed afio archive on-the-fly, pad up to 700 MB:\n");
|
||||
printf(" ( cd my_directory ; find . -print | afio -oZ - ) | \\\n");
|
||||
printf(" %s --drive /dev/hdc --burn_for_real --stdin_size 734003200 -\n", argv[0]);
|
||||
printf("To be read from *not mounted* CD via:\n");
|
||||
printf(" afio -tvZ /dev/hdc\n");
|
||||
printf(" %s --drive /dev/hdc --stdin_size 734003200 -\n", argv[0]);
|
||||
printf("To be read from *not mounted* CD via: afio -tvZ /dev/hdc\n");
|
||||
printf("Program tar would need a clean EOF which our padded CD cannot deliver.\n");
|
||||
if (insuffient_parameters)
|
||||
return 6;
|
||||
@ -572,24 +575,28 @@ int libburner_setup(int argc, char **argv, char drive_adr[], int *driveno,
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int driveno, ret, do_blank;
|
||||
char source_adr[4096], drive_adr[BURN_DRIVE_ADR_LEN];
|
||||
off_t stdin_size;
|
||||
int ret;
|
||||
|
||||
ret = libburner_setup(argc, argv, drive_adr, &driveno, &do_blank,
|
||||
source_adr, &stdin_size);
|
||||
ret = libburner_setup(argc, argv);
|
||||
if (ret)
|
||||
exit(ret);
|
||||
|
||||
printf("Initializing library ...\n");
|
||||
printf("Initializing libburn.pykix.org ...\n");
|
||||
if (burn_initialize())
|
||||
printf("Done\n");
|
||||
else {
|
||||
printf("FAILED\n");
|
||||
fprintf(stderr,"\nFATAL: Failed to initialize libburn.\n");
|
||||
fprintf(stderr,"\nFATAL: Failed to initialize.\n");
|
||||
exit(33);
|
||||
}
|
||||
|
||||
/* Print messages of severity SORRY or more directly to stderr */
|
||||
burn_msgs_set_severities("NEVER", "SORRY", "libburner : ");
|
||||
|
||||
/* Activate the default signal handler which eventually will try to
|
||||
properly shutdown drive and library on aborting events. */
|
||||
burn_set_signal_handling("libburner : ", NULL, 0);
|
||||
|
||||
/** Note: driveno might change its value in this call */
|
||||
ret = libburner_aquire_drive(drive_adr, &driveno);
|
||||
if (ret<=0) {
|
||||
@ -603,7 +610,7 @@ int main(int argc, char **argv)
|
||||
do_blank == 1);
|
||||
if (ret<=0)
|
||||
{ ret = 36; goto release_drive; }
|
||||
if (ret != 2 && source_adr[0] != 0)
|
||||
if (ret != 2 && source_adr_count > 0)
|
||||
ret = libburner_regrab(drive_list[driveno].drive);
|
||||
if (ret<=0) {
|
||||
fprintf(stderr,
|
||||
@ -611,9 +618,10 @@ int main(int argc, char **argv)
|
||||
{ ret = 37; goto finish_libburn; }
|
||||
}
|
||||
}
|
||||
if (source_adr[0] != 0) {
|
||||
ret = libburner_payload(drive_list[driveno].drive, source_adr,
|
||||
stdin_size);
|
||||
if (source_adr_count > 0) {
|
||||
ret = libburner_payload(drive_list[driveno].drive,
|
||||
source_adr, source_adr_count, stdin_size,
|
||||
simulate_burn, all_tracks_type);
|
||||
if (ret<=0)
|
||||
{ ret = 38; goto release_drive; }
|
||||
}
|
||||
@ -628,7 +636,7 @@ finish_libburn:;
|
||||
/* burn_drive_info_free(drive_list); */
|
||||
|
||||
burn_finish();
|
||||
return ret;
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,2 +0,0 @@
|
||||
Note: this is a libburn-0.2.2 release candidate
|
||||
|
Reference in New Issue
Block a user