diff --git a/usr.sbin/burncd/burncd.8 b/usr.sbin/burncd/burncd.8 index 44bec39f04c4..010d6eff6443 100644 --- a/usr.sbin/burncd/burncd.8 +++ b/usr.sbin/burncd/burncd.8 @@ -1,209 +1,214 @@ .\" .\" 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$ .\" -.Dd October 18, 2002 +.Dd September 15, 2004 .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: .Pp .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. +eject the medium when done. .It Fl f Ar device set the device to use for the burning process. .It Fl F force operation regardless of warnings. .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 4. 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: .Pp .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 eject +Eject the medium when done. +This is equivalent to the +.Fl e +option. .It Cm erase Erase a CD-RW medium. This erases the entire media. Can take up to 1 hour to finish. .It Cm format Brq Cm dvd+rw | dvd-rw Formats a DVD+RW or DVD-RW media to the default max size and 2048 byte blocks. This operation can take a long time to finish. Progress reporting is done during the process. .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 Cm dvdrw Set the write mode to write a DVD+RW from the following image. DVDs only have one track. .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/acd0 data file1 fixate" .Pp The typical usage for burning an audio CD-R: .Pp .Dl "burncd -f /dev/acd0 audio file1 file2 file3 fixate" .Pp The typical usage for burning an audio CD-R in DAO mode: .Pp .Dl "burncd -f /dev/acd0 -d audio file1 file2 file3" .Pp The typical usage for burning a mixed mode CD-R: .Pp .Dl "burncd -f /dev/acd0 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/acd0 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 .Fx Ports Collection, as part of the .Pa sysutils/cdrtools port, is commonly used to create ISO9660 file system images from a given directory tree. .Sh ENVIRONMENT The following environment variables affect the execution of .Nm : .Bl -tag -width ".Ev CDROM" .It Ev CDROM The CD device to use if one is not specified with the .Fl f flag. .El .Sh BUGS Probably, please report when found. .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 . diff --git a/usr.sbin/burncd/burncd.c b/usr.sbin/burncd/burncd.c index 75596091c944..e6eb51609d4a 100644 --- a/usr.sbin/burncd/burncd.c +++ b/usr.sbin/burncd/burncd.c @@ -1,695 +1,699 @@ /*- * 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$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define BLOCKS 16 struct track_info { int file; char file_name[MAXPATHLEN + 1]; off_t file_size; int block_size; int block_type; int pregap; int addr; }; static struct track_info tracks[100]; static int global_fd_for_cleanup, quiet, verbose, saved_block_size, notracks; void add_track(char *, int, int, int); void do_DAO(int fd, int, int); void do_TAO(int fd, int, int, int); void do_format(int, int, char *); int write_file(int fd, 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 arg, addr, ch, fd; int dao = 0, eject = 0, fixate = 0, list = 0, multi = 0, preemp = 0; int nogap = 0, speed = 4 * 177, test_write = 0, force = 0; int block_size = 0, block_type = 0, cdopen = 0, dvdrw = 0; const char *dev; if ((dev = getenv("CDROM")) == NULL) dev = "/dev/acd0"; while ((ch = getopt(argc, argv, "def:Flmnpqs:tv")) != -1) { switch (ch) { case 'd': dao = 1; break; case 'e': eject = 1; break; case 'f': dev = optarg; break; case 'F': force = 1; 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)"); global_fd_for_cleanup = fd; err_set_exit(cleanup); for (arg = 0; arg < argc; arg++) { if (!strcasecmp(argv[arg], "fixate")) { fixate = 1; break; } + if (!strcasecmp(argv[arg], "eject")) { + eject = 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")) && !test_write) { int blank, pct, last = 0; 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); if (ioctl(fd, CDRIOCGETPROGRESS, &pct) == -1) err(EX_IOERR,"ioctl(CDRIOGETPROGRESS)"); if (pct > 0 && !quiet) fprintf(stderr, "%sing CD - %d %% done \r", blank == CDR_B_ALL ? "eras" : "blank", pct); if (pct == 100 || (pct == 0 && last > 90)) break; last = pct; } if (!quiet) printf("\n"); continue; } if (!strcasecmp(argv[arg], "format") && !test_write) { if (arg + 1 < argc && (!strcasecmp(argv[arg + 1], "dvd+rw") || !strcasecmp(argv[arg + 1], "dvd-rw"))) do_format(fd, force, argv[arg + 1]); else err(EX_NOINPUT, "format media type invalid"); arg++; 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 (!strcasecmp(argv[arg], "dvdrw")) { block_type = CDR_DB_ROM_MODE1; block_size = 2048; dvdrw = 1; continue; } if (!block_size) err(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 (dvdrw && notracks > 1) err(EX_USAGE, "DVD's only have 1 track"); 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(fd, test_write, multi); else do_TAO(fd, test_write, preemp, dvdrw); } if (!test_write && fixate && !dao && !dvdrw) { 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; strncpy(tracks[notracks].file_name, name, MAXPATHLEN); 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 %jd KB %d blocks %s\n", tracks[notracks].block_type, name, (intmax_t)sb.st_size/1024, roundup_blocks(&tracks[notracks]), pad ? "(0 padded)" : ""); } notracks++; } void do_DAO(int fd, 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(fd, &tracks[i])) err(EX_IOERR, "write_file"); } ioctl(fd, CDRIOCFLUSH); } void do_TAO(int fd, int test_write, int preemp, int dvdrw) { 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 (dvdrw) tracks[i].addr = 0; else 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(fd, &tracks[i])) err(EX_IOERR, "write_file"); if (ioctl(fd, CDRIOCFLUSH) < 0) err(EX_IOERR, "ioctl(CDRIOCFLUSH)"); } } #define NTOH3B(x) ((x&0x0000ff)<<16) | (x&0x00ff00) | ((x&0xff0000)>>16) void do_format(int the_fd, int force, char *type) { struct cdr_format_capacities capacities; struct cdr_format_params format_params; int count, i, pct, last = 0; if (ioctl(the_fd, CDRIOCREADFORMATCAPS, &capacities) == -1) err(EX_IOERR, "ioctl(CDRIOCREADFORMATCAPS)"); if (verbose) { fprintf(stderr, "format list entries=%zd\n", capacities.length / sizeof(struct cdr_format_capacity)); fprintf(stderr, "current format: blocks=%u type=0x%x block_size=%u\n", ntohl(capacities.blocks), capacities.type, NTOH3B(capacities.block_size)); } count = capacities.length / sizeof(struct cdr_format_capacity); if (verbose) { for (i = 0; i < count; ++i) fprintf(stderr, "format %d: blocks=%u type=0x%x param=%u\n", i, ntohl(capacities.format[i].blocks), capacities.format[i].type, NTOH3B(capacities.format[i].param)); } for (i = 0; i < count; ++i) { if (!strcasecmp(type, "dvd+rw")) { if (capacities.format[i].type == 0x26) { break; } } if (!strcasecmp(type, "dvd-rw")) { if (capacities.format[i].type == 0x0) { break; } } } if (i == count) err(EX_IOERR, "could not find a valid format capacity"); if (!quiet) fprintf(stderr,"formatting with blocks=%u type=0x%x param=%u\n", ntohl(capacities.format[i].blocks), capacities.format[i].type, NTOH3B(capacities.format[i].param)); if (!force && capacities.type == 2) err(EX_IOERR, "media already formatted (use -F to override)"); memset(&format_params, 0, sizeof(struct cdr_format_params)); format_params.fov = 1; format_params.immed = 1; format_params.length = ntohs(sizeof(struct cdr_format_capacity)); memcpy(&format_params.format, &capacities.format[i], sizeof(struct cdr_format_capacity)); if(ioctl(the_fd, CDRIOCFORMAT, &format_params) == -1) err(EX_IOERR, "ioctl(CDRIOCFORMAT)"); while (1) { sleep(1); if (ioctl(the_fd, CDRIOCGETPROGRESS, &pct) == -1) err(EX_IOERR, "ioctl(CDRIOGETPROGRESS)"); if (pct > 0 && !quiet) fprintf(stderr, "formatting DVD - %d %% done \r", pct); if (pct == 100 || (pct == 0 && last > 90)) break; last = pct; } if (!quiet) fprintf(stderr, "\n"); } int write_file(int fd, struct track_info *track_info) { off_t size, count, filesize; char buf[2352*BLOCKS]; static off_t 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 = %jd blocks = %d\n", track_info->addr, (intmax_t)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 %jd KB\n", track_info->file_name, (intmax_t)filesize); } size = 0; while ((count = read(track_info->file, buf, track_info->file_size == -1 ? track_info->block_size * BLOCKS : 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 %jd bytes: %s\n", res, (intmax_t)count, strerror(errno)); break; } size += count; tot_size += count; if (!quiet) { int pct; fprintf(stderr, "written this track %jd KB", (intmax_t)size/1024); if (track_info->file != STDIN_FILENO && filesize) { pct = (size / 1024) * 100 / filesize; fprintf(stderr, " (%d%%)", pct); } fprintf(stderr, " total %jd KB\r", (intmax_t)tot_size / 1024); } if (track_info->file_size != -1 && 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(global_fd_for_cleanup, 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); }