From: Sascha Wildner Date: Sat, 8 Jan 2011 12:47:55 +0000 (+0100) Subject: Revert "Remove the broken burncd(8)." X-Git-Tag: v2.10.0~380 X-Git-Url: http://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/9d0b624075d46ed6169fca67f99eb0918f5b92a1 Revert "Remove the broken burncd(8)." This reverts commit fd6f482a63584f75b8a119c8815ad384815c990a. A number of people disagreed with this commit, so I'm reverting it. The reason I removed burncd(8) was that it didn't work here at all and that others (on IRC) had reported the same. So bring it back for now so we can re-evaluate. --- diff --git a/Makefile_upgrade.inc b/Makefile_upgrade.inc index 616fa76..d3de12b 100644 --- a/Makefile_upgrade.inc +++ b/Makefile_upgrade.inc @@ -1552,9 +1552,6 @@ TO_REMOVE+=/boot/kernel/ahc_eisa.ko TO_REMOVE+=/boot/kernel/ahc_isa.ko TO_REMOVE+=/usr/include/netproto/ns TO_REMOVE+=/usr/include/netns -TO_REMOVE+=/usr/sbin/burncd -TO_REMOVE+=/usr/share/man/cat8/burncd.8.gz -TO_REMOVE+=/usr/share/man/man8/burncd.8.gz # XXX Remove when pfsync(4) has been fixed TO_REMOVE+=/usr/share/man/cat4/pfsync.4.gz diff --git a/share/man/man4/ata.4 b/share/man/man4/ata.4 index cff75fa..414f9ce 100644 --- a/share/man/man4/ata.4 +++ b/share/man/man4/ata.4 @@ -239,9 +239,9 @@ unless they are run at the non-UDMA4 device's lower speed. The driver has been designed to handle that kind of setup but lots of older devices do not like this. .Sh SEE ALSO -.Xr cdrecord 1 Pq Pa pkgsrc/sysutils/cdrtools , .Xr nata 4 , -.Xr atacontrol 8 +.Xr atacontrol 8 , +.Xr burncd 8 .Sh HISTORY The .Nm diff --git a/share/man/man4/nata.4 b/share/man/man4/nata.4 index 1466cc1..9ea605e 100644 --- a/share/man/man4/nata.4 +++ b/share/man/man4/nata.4 @@ -206,11 +206,11 @@ as the same numbered device, and not depend on attach order. .Pp Native Command Queuing (NCQ) on SATA drives is not yet supported. .Sh SEE ALSO -.Xr cdrecord 1 Pq Pa pkgsrc/sysutils/cdrtools , .Xr ahci 4 , .Xr ata 4 , .Xr nataraid 4 , .Xr sili 4 , +.Xr burncd 8 , .Xr natacontrol 8 .Sh HISTORY The diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index 1000e38..0bfa0fa 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -19,6 +19,7 @@ SUBDIR= 802_11 \ bootparamd \ btconfig \ bthcid \ + burncd \ cdcontrol \ chkgrp \ chown \ diff --git a/usr.sbin/burncd/Makefile b/usr.sbin/burncd/Makefile new file mode 100644 index 0000000..1451dfc --- /dev/null +++ b/usr.sbin/burncd/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD: src/usr.sbin/burncd/Makefile,v 1.2.2.1 2001/04/25 12:09:21 ru Exp $ +# $DragonFly: src/usr.sbin/burncd/Makefile,v 1.2 2003/06/17 04:29:52 dillon Exp $ + +PROG= burncd +MAN= burncd.8 +WARNS?= 2 + +.include diff --git a/usr.sbin/burncd/burncd.8 b/usr.sbin/burncd/burncd.8 new file mode 100644 index 0000000..d9ab503 --- /dev/null +++ b/usr.sbin/burncd/burncd.8 @@ -0,0 +1,187 @@ +.\" +.\" Copyright (c) 2000,2001,2002 Søren Schmidt +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer, +.\" without modification, immediately at the beginning of the file. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD: src/usr.sbin/burncd/burncd.8,v 1.6.2.8 2003/03/12 22:08:13 trhodes Exp $ +.\" $DragonFly: src/usr.sbin/burncd/burncd.8,v 1.8 2008/05/02 02:05:07 swildner Exp $ +.\" +.Dd December 4, 2001 +.Os +.Dt BURNCD 8 +.Sh NAME +.Nm burncd +.Nd control the ATAPI CD-R/RW driver +.Sh SYNOPSIS +.Nm +.Op Fl delmnpqtv +.Op Fl f Ar device +.Op Fl s Ar speed +.Op Ar command +.Op Ar command Ar +.Sh DESCRIPTION +The +.Nm +utility is used to burn CD-R/RW media using the ATAPI cd driver. +.Pp +Available options and operands: +.Bl -tag -width XXXXXXXXXXXX +.It Fl d +burn the CD-R/RW in DAO (disk at once) mode. +.It Fl e +eject the media when done. +.It Fl f Ar device +set the device to use for the burning process. +.It Fl l +read a list of image files from filename. +.It Fl m +close disk in multisession mode (otherwise disk is closed as singlesession). +.It Fl n +do not write gaps between data tracks in DAO mode. +.It Fl p +use preemphasis on audio tracks. +.It Fl q +quiet, do not print progress messages. +.It Fl s Ar speed +set the speed of the burner device. +Defaults to 1. +Specify +.Dq Li max +to use the drive's fastest speed. +.It Fl t +test write, do not actually write on the media. +.It Fl v +verbose, print extra progress messages. +.El +.Pp +.Ar command +may be one of: +.Bl -tag -width XXXXXXXXXXXX +.It Cm msinfo +Show the first LBA of the last track on the media +and the next writeable address on the media for use with the +.Xr mkisofs 8 Ns 's +.Fl C +switch when adding additional data to ISO file systems with extra sessions. +.It Cm blank +Blank a CD-RW medium. +This uses the fast blanking method, so data are not physically overwritten, +only those areas that make the media appear blank for further usage are erased. +.It Cm erase +Erase a CD-RW medium. +This erases the entire media. +Can take up to 1 hour to finish. +.It Cm fixate +Fixate the medium so that the TOC is generated and the media can be used +in an ordinary CD drive. +The driver defaults to creating singlesession media (see +.Fl m +option). +Should be the last command to +.Nm +as the program exits when this has been done. +Ignored in DAO mode (see +.Fl d +option). +.It Cm raw | audio +Set the write mode to produce audio (raw mode) tracks for the following +images on the command line. +.It Cm data | mode1 +Set the write mode to produce data (mode1) tracks for the following +image files +on the command line. +.It Cm mode2 +Set the write mode to produce data (mode2) tracks for the following +image files +on the command line. +.It Cm XAmode1 +Set the write mode to produce data (XAmode1) tracks for the following image +files on the command line. +.It Cm XAmode2 +Set the write mode to produce data (XAmode2) tracks for the following image +files on the command line. +.It Cm vcd +Set the write mode to produce VCD/SVCD tracks for the following image files +on the command line. +This automatically sets DAO +.Pq Fl d +and +.Dq "no gaps" +.Pq Fl n +modes. +.It Ar file +All other arguments are treated as filenames of images to write to the media, +or in case the +.Fl l +option is used as files containing lists of images. +.El +.Pp +Files whose length are not a multiple of the current media blocksize are +quietly zero padded to fit the blocksize requirement. +The conventional filename +.Fl +refers to stdin, and can only be used once. +.Sh EXAMPLES +The typical usage for burning a data CD-R: +.Pp +.Dl "burncd -f /dev/acd0c data file1 fixate" +.Pp +The typical usage for burning an audio CD-R: +.Pp +.Dl "burncd -f /dev/acd0c audio file1 file2 file3 fixate" +.Pp +The typical usage for burning an audio CD-R in DAO mode: +.Pp +.Dl "burncd -f /dev/acd0c -d audio file1 file2 file3" +.Pp +The typical usage for burning a mixed mode CD-R: +.Pp +.Dl "burncd -f /dev/acd0c data file1 audio file2 file3 fixate" +.Pp +The typical usage for burning from a compressed image file on stdin: +.Pp +.Dl "gunzip -c file.iso.gz | burncd -f /dev/acd0c data - fixate" +.Pp +In the examples above, the files burned to data CD-Rs are assumed to +be ISO9660 file systems. +.Xr mkisofs 8 , +available in the +.Xr pkgsrc 7 +collection, is commonly used to create ISO9660 file system images +from a given directory tree. +.Sh HISTORY +The +.Nm +utility appeared in +.Fx 4.0 . +.Sh AUTHORS +The +.Nm +utility and this manpage was contributed by +.An S\(/oren Schmidt , +Denmark +.Aq sos@FreeBSD.org . +.Sh BUGS +Probably, please report when found. diff --git a/usr.sbin/burncd/burncd.c b/usr.sbin/burncd/burncd.c new file mode 100644 index 0000000..d164d05 --- /dev/null +++ b/usr.sbin/burncd/burncd.c @@ -0,0 +1,571 @@ +/*- + * Copyright (c) 2000,2001,2002 Søren Schmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/usr.sbin/burncd/burncd.c,v 1.10.2.6 2002/11/20 00:26:18 njl Exp $ + * $DragonFly: src/usr.sbin/burncd/burncd.c,v 1.4 2008/06/05 18:06:33 swildner Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BLOCKS 16 + +struct track_info { + int file; + char *file_name; + u_int file_size; + int block_size; + int block_type; + int pregap; + int addr; +}; +static struct track_info tracks[100]; +static int fd, quiet, verbose, saved_block_size, notracks; + +void add_track(char *, int, int, int); +void do_DAO(int, int); +void do_TAO(int, int); +int write_file(struct track_info *); +int roundup_blocks(struct track_info *); +void cue_ent(struct cdr_cue_entry *, int, int, int, int, int, int, int); +void cleanup(int); +void usage(void); + +int +main(int argc, char **argv) +{ + int ch, arg, addr; + int dao = 0, eject = 0, fixate = 0, list = 0, multi = 0, preemp = 0; + int nogap = 0, speed = 4 * 177, test_write = 0; + int block_size = 0, block_type = 0, cdopen = 0; + const char *dev = "/dev/acd0c"; + + while ((ch = getopt(argc, argv, "def:lmnpqs:tv")) != -1) { + switch (ch) { + case 'd': + dao = 1; + break; + + case 'e': + eject = 1; + break; + + case 'f': + dev = optarg; + break; + + case 'l': + list = 1; + break; + + case 'm': + multi = 1; + break; + + case 'n': + nogap = 1; + break; + + case 'p': + preemp = 1; + break; + + case 'q': + quiet = 1; + break; + + case 's': + if (strcasecmp("max", optarg) == 0) + speed = CDR_MAX_SPEED; + else + speed = atoi(optarg) * 177; + if (speed <= 0) + errx(EX_USAGE, "Invalid speed: %s", optarg); + break; + + case 't': + test_write = 1; + break; + + case 'v': + verbose = 1; + break; + + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (argc == 0) + usage(); + + if ((fd = open(dev, O_RDWR, 0)) < 0) + err(EX_NOINPUT, "open(%s)", dev); + + if (ioctl(fd, CDRIOCGETBLOCKSIZE, &saved_block_size) < 0) + err(EX_IOERR, "ioctl(CDRIOCGETBLOCKSIZE)"); + + if (ioctl(fd, CDRIOCWRITESPEED, &speed) < 0) + err(EX_IOERR, "ioctl(CDRIOCWRITESPEED)"); + + err_set_exit(cleanup); + + for (arg = 0; arg < argc; arg++) { + if (!strcasecmp(argv[arg], "fixate")) { + fixate = 1; + break; + } + if (!strcasecmp(argv[arg], "msinfo")) { + struct ioc_read_toc_single_entry entry; + struct ioc_toc_header header; + + if (ioctl(fd, CDIOREADTOCHEADER, &header) < 0) + err(EX_IOERR, "ioctl(CDIOREADTOCHEADER)"); + bzero(&entry, sizeof(struct ioc_read_toc_single_entry)); + entry.address_format = CD_LBA_FORMAT; + entry.track = header.ending_track; + if (ioctl(fd, CDIOREADTOCENTRY, &entry) < 0) + err(EX_IOERR, "ioctl(CDIOREADTOCENTRY)"); + if (ioctl(fd, CDRIOCNEXTWRITEABLEADDR, &addr) < 0) + err(EX_IOERR, "ioctl(CDRIOCNEXTWRITEABLEADDR)"); + fprintf(stdout, "%d,%d\n", + ntohl(entry.entry.addr.lba), addr); + + break; + } + if (!strcasecmp(argv[arg], "erase") || !strcasecmp(argv[arg], "blank")){ + int error, blank, percent; + + if (!strcasecmp(argv[arg], "erase")) + blank = CDR_B_ALL; + else + blank = CDR_B_MIN; + if (!quiet) + fprintf(stderr, "%sing CD, please wait..\r", + blank == CDR_B_ALL ? "eras" : "blank"); + + if (ioctl(fd, CDRIOCBLANK, &blank) < 0) + err(EX_IOERR, "ioctl(CDRIOCBLANK)"); + while (1) { + sleep(1); + error = ioctl(fd, CDRIOCGETPROGRESS, &percent); + if (percent > 0 && !quiet) + fprintf(stderr, + "%sing CD - %d %% done \r", + blank == CDR_B_ALL ? + "eras" : "blank", percent); + if (error || percent == 100) + break; + } + if (!quiet) + printf("\n"); + continue; + } + if (!strcasecmp(argv[arg], "audio") || !strcasecmp(argv[arg], "raw")) { + block_type = CDR_DB_RAW; + block_size = 2352; + continue; + } + if (!strcasecmp(argv[arg], "data") || !strcasecmp(argv[arg], "mode1")) { + block_type = CDR_DB_ROM_MODE1; + block_size = 2048; + continue; + } + if (!strcasecmp(argv[arg], "mode2")) { + block_type = CDR_DB_ROM_MODE2; + block_size = 2336; + continue; + } + if (!strcasecmp(argv[arg], "xamode1")) { + block_type = CDR_DB_XA_MODE1; + block_size = 2048; + continue; + } + if (!strcasecmp(argv[arg], "xamode2")) { + block_type = CDR_DB_XA_MODE2_F2; + block_size = 2324; + continue; + } + if (!strcasecmp(argv[arg], "vcd")) { + block_type = CDR_DB_XA_MODE2_F2; + block_size = 2352; + dao = 1; + nogap = 1; + continue; + } + if (!block_size) + errx(EX_NOINPUT, "no data format selected"); + if (list) { + char file_buf[MAXPATHLEN + 1], *eol; + FILE *fp; + + if ((fp = fopen(argv[arg], "r")) == NULL) + err(EX_NOINPUT, "fopen(%s)", argv[arg]); + + while (fgets(file_buf, sizeof(file_buf), fp) != NULL) { + if (*file_buf == '#' || *file_buf == '\n') + continue; + if ((eol = strchr(file_buf, '\n'))) + *eol = 0; + add_track(file_buf, block_size, block_type, nogap); + } + if (feof(fp)) + fclose(fp); + else + err(EX_IOERR, "fgets(%s)", file_buf); + } + else + add_track(argv[arg], block_size, block_type, nogap); + } + if (notracks) { + if (ioctl(fd, CDIOCSTART, 0) < 0) + err(EX_IOERR, "ioctl(CDIOCSTART)"); + if (!cdopen) { + if (ioctl(fd, CDRIOCINITWRITER, &test_write) < 0) + err(EX_IOERR, "ioctl(CDRIOCINITWRITER)"); + cdopen = 1; + } + if (dao) + do_DAO(test_write, multi); + else + do_TAO(test_write, preemp); + } + if (fixate && !dao) { + if (!quiet) + fprintf(stderr, "fixating CD, please wait..\n"); + if (ioctl(fd, CDRIOCFIXATE, &multi) < 0) + err(EX_IOERR, "ioctl(CDRIOCFIXATE)"); + } + + if (ioctl(fd, CDRIOCSETBLOCKSIZE, &saved_block_size) < 0) { + err_set_exit(NULL); + err(EX_IOERR, "ioctl(CDRIOCSETBLOCKSIZE)"); + } + + if (eject) + if (ioctl(fd, CDIOCEJECT) < 0) + err(EX_IOERR, "ioctl(CDIOCEJECT)"); + close(fd); + exit(EX_OK); +} + +void +add_track(char *name, int block_size, int block_type, int nogap) +{ + struct stat sb; + int file; + static int done_stdin = 0; + + if (!strcmp(name, "-")) { + if (done_stdin) { + warn("skipping multiple usages of stdin"); + return; + } + file = STDIN_FILENO; + done_stdin = 1; + } + else if ((file = open(name, O_RDONLY, 0)) < 0) + err(EX_NOINPUT, "open(%s)", name); + if (fstat(file, &sb) < 0) + err(EX_IOERR, "fstat(%s)", name); + tracks[notracks].file = file; + tracks[notracks].file_name = name; + if (file == STDIN_FILENO) + tracks[notracks].file_size = -1; + else + tracks[notracks].file_size = sb.st_size; + tracks[notracks].block_size = block_size; + tracks[notracks].block_type = block_type; + + if (nogap && notracks) + tracks[notracks].pregap = 0; + else { + if (tracks[notracks - (notracks > 0)].block_type == block_type) + tracks[notracks].pregap = 150; + else + tracks[notracks].pregap = 255; + } + + if (verbose) { + int pad = 0; + + if (tracks[notracks].file_size / tracks[notracks].block_size != + roundup_blocks(&tracks[notracks])) + pad = 1; + fprintf(stderr, + "adding type 0x%02x file %s size %d KB %d blocks %s\n", + tracks[notracks].block_type, name, (int)sb.st_size/1024, + roundup_blocks(&tracks[notracks]), + pad ? "(0 padded)" : ""); + } + notracks++; +} + +void +do_DAO(int test_write, int multi) +{ + struct cdr_cuesheet sheet; + struct cdr_cue_entry cue[100]; + int format = CDR_SESS_CDROM; + int addr, i, j = 0; + + int bt2ctl[16] = { 0x0, -1, -1, -1, -1, -1, -1, -1, + 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, -1, -1 }; + + int bt2df[16] = { 0x0, -1, -1, -1, -1, -1, -1, -1, + 0x10, 0x30, 0x20, -1, 0x21, -1, -1, -1 }; + + if (ioctl(fd, CDRIOCNEXTWRITEABLEADDR, &addr) < 0) + err(EX_IOERR, "ioctl(CDRIOCNEXTWRITEABLEADDR)"); + if (verbose) + fprintf(stderr, "next writeable LBA %d\n", addr); + + cue_ent(&cue[j++], bt2ctl[tracks[0].block_type], 0x01, 0x00, 0x0, + (bt2df[tracks[0].block_type] & 0xf0) | + (tracks[0].block_type < 8 ? 0x01 : 0x04), 0x00, addr); + + for (i = 0; i < notracks; i++) { + if (bt2ctl[tracks[i].block_type] < 0 || + bt2df[tracks[i].block_type] < 0) + err(EX_IOERR, "track type not supported in DAO mode"); + + if (tracks[i].block_type >= CDR_DB_XA_MODE1) + format = CDR_SESS_CDROM_XA; + + if (i == 0) { + addr += tracks[i].pregap; + tracks[i].addr = addr; + + cue_ent(&cue[j++], bt2ctl[tracks[i].block_type], + 0x01, i+1, 0x1, bt2df[tracks[i].block_type], + 0x00, addr); + + } + else { + if (tracks[i].pregap) { + if (tracks[i].block_type > 0x7) { + cue_ent(&cue[j++],bt2ctl[tracks[i].block_type], + 0x01, i+1, 0x0, + (bt2df[tracks[i].block_type] & 0xf0) | + (tracks[i].block_type < 8 ? 0x01 :0x04), + 0x00, addr); + } + else + cue_ent(&cue[j++],bt2ctl[tracks[i].block_type], + 0x01, i+1, 0x0, + bt2df[tracks[i].block_type], + 0x00, addr); + } + tracks[i].addr = tracks[i - 1].addr + + roundup_blocks(&tracks[i - 1]); + + cue_ent(&cue[j++], bt2ctl[tracks[i].block_type], + 0x01, i+1, 0x1, bt2df[tracks[i].block_type], + 0x00, addr + tracks[i].pregap); + + if (tracks[i].block_type > 0x7) + addr += tracks[i].pregap; + } + addr += roundup_blocks(&tracks[i]); + } + + cue_ent(&cue[j++], bt2ctl[tracks[i - 1].block_type], 0x01, 0xaa, 0x01, + (bt2df[tracks[i - 1].block_type] & 0xf0) | + (tracks[i - 1].block_type < 8 ? 0x01 : 0x04), 0x00, addr); + + sheet.len = j * 8; + sheet.entries = cue; + sheet.test_write = test_write; + sheet.session_type = multi ? CDR_SESS_MULTI : CDR_SESS_NONE; + sheet.session_format = format; + if (verbose) { + u_int8_t *ptr = (u_int8_t *)sheet.entries; + + fprintf(stderr,"CUE sheet:"); + for (i = 0; i < sheet.len; i++) + if (i % 8) + fprintf(stderr," %02x", ptr[i]); + else + fprintf(stderr,"\n%02x", ptr[i]); + fprintf(stderr,"\n"); + } + + if (ioctl(fd, CDRIOCSENDCUE, &sheet) < 0) + err(EX_IOERR, "ioctl(CDRIOCSENDCUE)"); + + for (i = 0; i < notracks; i++) { + if (write_file(&tracks[i])) + err(EX_IOERR, "write_file"); + } + + ioctl(fd, CDRIOCFLUSH); +} + +void +do_TAO(int test_write, int preemp) +{ + struct cdr_track track; + int i; + + for (i = 0; i < notracks; i++) { + track.test_write = test_write; + track.datablock_type = tracks[i].block_type; + track.preemp = preemp; + if (ioctl(fd, CDRIOCINITTRACK, &track) < 0) + err(EX_IOERR, "ioctl(CDRIOCINITTRACK)"); + + if (ioctl(fd, CDRIOCNEXTWRITEABLEADDR, &tracks[i].addr) < 0) + err(EX_IOERR, "ioctl(CDRIOCNEXTWRITEABLEADDR)"); + if (!quiet) + fprintf(stderr, "next writeable LBA %d\n", + tracks[i].addr); + if (write_file(&tracks[i])) + err(EX_IOERR, "write_file"); + if (ioctl(fd, CDRIOCFLUSH) < 0) + err(EX_IOERR, "ioctl(CDRIOCFLUSH)"); + } +} + +int +write_file(struct track_info *track_info) +{ + int size, count, filesize; + char buf[2352*BLOCKS]; + static int tot_size = 0; + + filesize = track_info->file_size / 1024; + + if (ioctl(fd, CDRIOCSETBLOCKSIZE, &track_info->block_size) < 0) + err(EX_IOERR, "ioctl(CDRIOCSETBLOCKSIZE)"); + + if (track_info->addr >= 0) + lseek(fd, track_info->addr * track_info->block_size, SEEK_SET); + + if (verbose) + fprintf(stderr, "addr = %d size = %d blocks = %d\n", + track_info->addr, track_info->file_size, + roundup_blocks(track_info)); + + if (!quiet) { + if (track_info->file == STDIN_FILENO) + fprintf(stderr, "writing from stdin\n"); + else + fprintf(stderr, + "writing from file %s size %d KB\n", + track_info->file_name, filesize); + } + size = 0; + + while ((count = read(track_info->file, buf, + MIN((track_info->file_size - size), + track_info->block_size * BLOCKS))) > 0) { + int res; + + if (count % track_info->block_size) { + /* pad file to % block_size */ + bzero(&buf[count], + (track_info->block_size * BLOCKS) - count); + count = ((count / track_info->block_size) + 1) * + track_info->block_size; + } + if ((res = write(fd, buf, count)) != count) { + fprintf(stderr, "\nonly wrote %d of %d bytes err=%d\n", + res, count, errno); + break; + } + size += count; + tot_size += count; + if (!quiet) { + int pct; + + fprintf(stderr, "written this track %d KB", size/1024); + if (track_info->file != STDIN_FILENO && filesize) { + pct = (size / 1024) * 100 / filesize; + fprintf(stderr, " (%d%%)", pct); + } + fprintf(stderr, " total %d KB\r", tot_size/1024); + } + if (size >= track_info->file_size) + break; + } + + if (!quiet) + fprintf(stderr, "\n"); + close(track_info->file); + return 0; +} + +int +roundup_blocks(struct track_info *track) +{ + return ((track->file_size + track->block_size - 1) / track->block_size); +} + +void +cue_ent(struct cdr_cue_entry *cue, int ctl, int adr, int track, int idx, + int dataform, int scms, int lba) +{ + cue->adr = adr; + cue->ctl = ctl; + cue->track = track; + cue->index = idx; + cue->dataform = dataform; + cue->scms = scms; + lba += 150; + cue->min = lba / (60*75); + cue->sec = (lba % (60*75)) / 75; + cue->frame = (lba % (60*75)) % 75; +} + +void +cleanup(int dummy __unused) +{ + if (ioctl(fd, CDRIOCSETBLOCKSIZE, &saved_block_size) < 0) + err(EX_IOERR, "ioctl(CDRIOCSETBLOCKSIZE)"); +} + +void +usage(void) +{ + fprintf(stderr, + "Usage: %s [-delmnpqtv] [-f device] [-s speed] [command]" + " [command file ...]\n", getprogname()); + exit(EX_USAGE); +}