xref: /dflybsd-src/usr.sbin/burncd/burncd.c (revision fe08e20ddf9efaf51ce4fbe089d786a1989e1262)
19d0b6240SSascha Wildner /*-
2f6e8a0a1SImre Vadasz  * Copyright (c) 2000,2001,2002 Søren Schmidt <sos@freebsd.org>
39d0b6240SSascha Wildner  * All rights reserved.
49d0b6240SSascha Wildner  *
59d0b6240SSascha Wildner  * Redistribution and use in source and binary forms, with or without
69d0b6240SSascha Wildner  * modification, are permitted provided that the following conditions
79d0b6240SSascha Wildner  * are met:
89d0b6240SSascha Wildner  * 1. Redistributions of source code must retain the above copyright
99d0b6240SSascha Wildner  *    notice, this list of conditions and the following disclaimer,
109d0b6240SSascha Wildner  *    without modification, immediately at the beginning of the file.
119d0b6240SSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
129d0b6240SSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
139d0b6240SSascha Wildner  *    documentation and/or other materials provided with the distribution.
149d0b6240SSascha Wildner  * 3. The name of the author may not be used to endorse or promote products
159d0b6240SSascha Wildner  *    derived from this software without specific prior written permission.
169d0b6240SSascha Wildner  *
179d0b6240SSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
189d0b6240SSascha Wildner  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
199d0b6240SSascha Wildner  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
209d0b6240SSascha Wildner  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
219d0b6240SSascha Wildner  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
229d0b6240SSascha Wildner  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
239d0b6240SSascha Wildner  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
249d0b6240SSascha Wildner  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
259d0b6240SSascha Wildner  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
269d0b6240SSascha Wildner  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
279d0b6240SSascha Wildner  *
289d0b6240SSascha Wildner  * $FreeBSD: src/usr.sbin/burncd/burncd.c,v 1.10.2.6 2002/11/20 00:26:18 njl Exp $
299d0b6240SSascha Wildner  */
309d0b6240SSascha Wildner 
319d0b6240SSascha Wildner #include <unistd.h>
329d0b6240SSascha Wildner #include <stdio.h>
339d0b6240SSascha Wildner #include <stdlib.h>
349d0b6240SSascha Wildner #include <string.h>
359d0b6240SSascha Wildner #include <err.h>
369d0b6240SSascha Wildner #include <sysexits.h>
379d0b6240SSascha Wildner #include <fcntl.h>
389d0b6240SSascha Wildner #include <sys/errno.h>
399d0b6240SSascha Wildner #include <sys/ioctl.h>
409d0b6240SSascha Wildner #include <sys/stat.h>
419d0b6240SSascha Wildner #include <sys/cdio.h>
429d0b6240SSascha Wildner #include <sys/cdrio.h>
439d0b6240SSascha Wildner #include <sys/param.h>
449d0b6240SSascha Wildner 
459d0b6240SSascha Wildner #define BLOCKS	16
469d0b6240SSascha Wildner 
479d0b6240SSascha Wildner struct track_info {
489d0b6240SSascha Wildner 	int	file;
499d0b6240SSascha Wildner 	char	*file_name;
509d0b6240SSascha Wildner 	u_int	file_size;
519d0b6240SSascha Wildner 	int	block_size;
529d0b6240SSascha Wildner 	int	block_type;
539d0b6240SSascha Wildner 	int	pregap;
549d0b6240SSascha Wildner 	int	addr;
559d0b6240SSascha Wildner };
569d0b6240SSascha Wildner static struct track_info tracks[100];
579d0b6240SSascha Wildner static int fd, quiet, verbose, saved_block_size, notracks;
589d0b6240SSascha Wildner 
5925809140SSascha Wildner static void add_track(char *, int, int, int);
6025809140SSascha Wildner static void do_DAO(int, int);
6125809140SSascha Wildner static void do_TAO(int, int);
6225809140SSascha Wildner static int write_file(struct track_info *);
6325809140SSascha Wildner static int roundup_blocks(struct track_info *);
6425809140SSascha Wildner static void cue_ent(struct cdr_cue_entry *, int, int, int, int, int, int, int);
6525809140SSascha Wildner static void cleanup(int);
66*fe08e20dSSascha Wildner static void usage(void) __dead2;
679d0b6240SSascha Wildner 
689d0b6240SSascha Wildner int
main(int argc,char ** argv)699d0b6240SSascha Wildner main(int argc, char **argv)
709d0b6240SSascha Wildner {
719d0b6240SSascha Wildner 	int ch, arg, addr;
729d0b6240SSascha Wildner 	int dao = 0, eject = 0, fixate = 0, list = 0, multi = 0, preemp = 0;
739d0b6240SSascha Wildner 	int nogap = 0, speed = 4 * 177, test_write = 0;
749d0b6240SSascha Wildner 	int block_size = 0, block_type = 0, cdopen = 0;
759d0b6240SSascha Wildner 	const char *dev = "/dev/acd0c";
769d0b6240SSascha Wildner 
779d0b6240SSascha Wildner 	while ((ch = getopt(argc, argv, "def:lmnpqs:tv")) != -1) {
789d0b6240SSascha Wildner 		switch (ch) {
799d0b6240SSascha Wildner 		case 'd':
809d0b6240SSascha Wildner 			dao = 1;
819d0b6240SSascha Wildner 			break;
829d0b6240SSascha Wildner 
839d0b6240SSascha Wildner 		case 'e':
849d0b6240SSascha Wildner 			eject = 1;
859d0b6240SSascha Wildner 			break;
869d0b6240SSascha Wildner 
879d0b6240SSascha Wildner 		case 'f':
889d0b6240SSascha Wildner 			dev = optarg;
899d0b6240SSascha Wildner 			break;
909d0b6240SSascha Wildner 
919d0b6240SSascha Wildner 		case 'l':
929d0b6240SSascha Wildner 			list = 1;
939d0b6240SSascha Wildner 			break;
949d0b6240SSascha Wildner 
959d0b6240SSascha Wildner 		case 'm':
969d0b6240SSascha Wildner 			multi = 1;
979d0b6240SSascha Wildner 			break;
989d0b6240SSascha Wildner 
999d0b6240SSascha Wildner 		case 'n':
1009d0b6240SSascha Wildner 			nogap = 1;
1019d0b6240SSascha Wildner 			break;
1029d0b6240SSascha Wildner 
1039d0b6240SSascha Wildner 		case 'p':
1049d0b6240SSascha Wildner 			preemp = 1;
1059d0b6240SSascha Wildner 			break;
1069d0b6240SSascha Wildner 
1079d0b6240SSascha Wildner 		case 'q':
1089d0b6240SSascha Wildner 			quiet = 1;
1099d0b6240SSascha Wildner 			break;
1109d0b6240SSascha Wildner 
1119d0b6240SSascha Wildner 		case 's':
1129d0b6240SSascha Wildner 			if (strcasecmp("max", optarg) == 0)
1139d0b6240SSascha Wildner 				speed = CDR_MAX_SPEED;
1149d0b6240SSascha Wildner 			else
1159d0b6240SSascha Wildner 				speed = atoi(optarg) * 177;
1169d0b6240SSascha Wildner 			if (speed <= 0)
1179d0b6240SSascha Wildner 				errx(EX_USAGE, "Invalid speed: %s", optarg);
1189d0b6240SSascha Wildner 			break;
1199d0b6240SSascha Wildner 
1209d0b6240SSascha Wildner 		case 't':
1219d0b6240SSascha Wildner 			test_write = 1;
1229d0b6240SSascha Wildner 			break;
1239d0b6240SSascha Wildner 
1249d0b6240SSascha Wildner 		case 'v':
1259d0b6240SSascha Wildner 			verbose = 1;
1269d0b6240SSascha Wildner 			break;
1279d0b6240SSascha Wildner 
1289d0b6240SSascha Wildner 		default:
1299d0b6240SSascha Wildner 			usage();
1309d0b6240SSascha Wildner 		}
1319d0b6240SSascha Wildner 	}
1329d0b6240SSascha Wildner 	argc -= optind;
1339d0b6240SSascha Wildner 	argv += optind;
1349d0b6240SSascha Wildner 
1359d0b6240SSascha Wildner 	if (argc == 0)
1369d0b6240SSascha Wildner 		usage();
1379d0b6240SSascha Wildner 
1389d0b6240SSascha Wildner 	if ((fd = open(dev, O_RDWR, 0)) < 0)
1399d0b6240SSascha Wildner 		err(EX_NOINPUT, "open(%s)", dev);
1409d0b6240SSascha Wildner 
1419d0b6240SSascha Wildner 	if (ioctl(fd, CDRIOCGETBLOCKSIZE, &saved_block_size) < 0)
1429d0b6240SSascha Wildner        		err(EX_IOERR, "ioctl(CDRIOCGETBLOCKSIZE)");
1439d0b6240SSascha Wildner 
1449d0b6240SSascha Wildner 	if (ioctl(fd, CDRIOCWRITESPEED, &speed) < 0)
1459d0b6240SSascha Wildner        		err(EX_IOERR, "ioctl(CDRIOCWRITESPEED)");
1469d0b6240SSascha Wildner 
1479d0b6240SSascha Wildner 	err_set_exit(cleanup);
1489d0b6240SSascha Wildner 
1499d0b6240SSascha Wildner 	for (arg = 0; arg < argc; arg++) {
1509d0b6240SSascha Wildner 		if (!strcasecmp(argv[arg], "fixate")) {
1519d0b6240SSascha Wildner 			fixate = 1;
1529d0b6240SSascha Wildner 			break;
1539d0b6240SSascha Wildner 		}
1549d0b6240SSascha Wildner 		if (!strcasecmp(argv[arg], "msinfo")) {
1559d0b6240SSascha Wildner 		        struct ioc_read_toc_single_entry entry;
1569d0b6240SSascha Wildner 			struct ioc_toc_header header;
1579d0b6240SSascha Wildner 
1589d0b6240SSascha Wildner 			if (ioctl(fd, CDIOREADTOCHEADER, &header) < 0)
1599d0b6240SSascha Wildner 				err(EX_IOERR, "ioctl(CDIOREADTOCHEADER)");
1609d0b6240SSascha Wildner 			bzero(&entry, sizeof(struct ioc_read_toc_single_entry));
1619d0b6240SSascha Wildner 			entry.address_format = CD_LBA_FORMAT;
1629d0b6240SSascha Wildner 			entry.track = header.ending_track;
1639d0b6240SSascha Wildner 			if (ioctl(fd, CDIOREADTOCENTRY, &entry) < 0)
1649d0b6240SSascha Wildner 				err(EX_IOERR, "ioctl(CDIOREADTOCENTRY)");
1659d0b6240SSascha Wildner 			if (ioctl(fd, CDRIOCNEXTWRITEABLEADDR, &addr) < 0)
1669d0b6240SSascha Wildner 				err(EX_IOERR, "ioctl(CDRIOCNEXTWRITEABLEADDR)");
1679d0b6240SSascha Wildner 			fprintf(stdout, "%d,%d\n",
1689d0b6240SSascha Wildner 				ntohl(entry.entry.addr.lba), addr);
1699d0b6240SSascha Wildner 
1709d0b6240SSascha Wildner 			break;
1719d0b6240SSascha Wildner 		}
1729d0b6240SSascha Wildner 		if (!strcasecmp(argv[arg], "erase") || !strcasecmp(argv[arg], "blank")){
1739d0b6240SSascha Wildner 		    	int error, blank, percent;
1749d0b6240SSascha Wildner 
1759d0b6240SSascha Wildner 			if (!strcasecmp(argv[arg], "erase"))
1769d0b6240SSascha Wildner 				blank = CDR_B_ALL;
1779d0b6240SSascha Wildner 			else
1789d0b6240SSascha Wildner 				blank = CDR_B_MIN;
1799d0b6240SSascha Wildner 			if (!quiet)
1809d0b6240SSascha Wildner 				fprintf(stderr, "%sing CD, please wait..\r",
1819d0b6240SSascha Wildner 					blank == CDR_B_ALL ? "eras" : "blank");
1829d0b6240SSascha Wildner 
1839d0b6240SSascha Wildner 			if (ioctl(fd, CDRIOCBLANK, &blank) < 0)
1849d0b6240SSascha Wildner         			err(EX_IOERR, "ioctl(CDRIOCBLANK)");
1859d0b6240SSascha Wildner 			while (1) {
1869d0b6240SSascha Wildner 				sleep(1);
1879d0b6240SSascha Wildner 				error = ioctl(fd, CDRIOCGETPROGRESS, &percent);
1889d0b6240SSascha Wildner 				if (percent > 0 && !quiet)
1899d0b6240SSascha Wildner 					fprintf(stderr,
1909d0b6240SSascha Wildner 						"%sing CD - %d %% done     \r",
1919d0b6240SSascha Wildner 						blank == CDR_B_ALL ?
1929d0b6240SSascha Wildner 						"eras" : "blank", percent);
1939d0b6240SSascha Wildner 				if (error || percent == 100)
1949d0b6240SSascha Wildner 					break;
1959d0b6240SSascha Wildner 			}
1969d0b6240SSascha Wildner 			if (!quiet)
1979d0b6240SSascha Wildner 				printf("\n");
1989d0b6240SSascha Wildner 			continue;
1999d0b6240SSascha Wildner 		}
2009d0b6240SSascha Wildner 		if (!strcasecmp(argv[arg], "audio") || !strcasecmp(argv[arg], "raw")) {
2019d0b6240SSascha Wildner 			block_type = CDR_DB_RAW;
2029d0b6240SSascha Wildner 			block_size = 2352;
2039d0b6240SSascha Wildner 			continue;
2049d0b6240SSascha Wildner 		}
2059d0b6240SSascha Wildner 		if (!strcasecmp(argv[arg], "data") || !strcasecmp(argv[arg], "mode1")) {
2069d0b6240SSascha Wildner 			block_type = CDR_DB_ROM_MODE1;
2079d0b6240SSascha Wildner 			block_size = 2048;
2089d0b6240SSascha Wildner 			continue;
2099d0b6240SSascha Wildner 		}
2109d0b6240SSascha Wildner 		if (!strcasecmp(argv[arg], "mode2")) {
2119d0b6240SSascha Wildner 			block_type = CDR_DB_ROM_MODE2;
2129d0b6240SSascha Wildner 			block_size = 2336;
2139d0b6240SSascha Wildner 			continue;
2149d0b6240SSascha Wildner 		}
2159d0b6240SSascha Wildner 		if (!strcasecmp(argv[arg], "xamode1")) {
2169d0b6240SSascha Wildner 			block_type = CDR_DB_XA_MODE1;
2179d0b6240SSascha Wildner 			block_size = 2048;
2189d0b6240SSascha Wildner 			continue;
2199d0b6240SSascha Wildner 		}
2209d0b6240SSascha Wildner 		if (!strcasecmp(argv[arg], "xamode2")) {
2219d0b6240SSascha Wildner 			block_type = CDR_DB_XA_MODE2_F2;
2229d0b6240SSascha Wildner 			block_size = 2324;
2239d0b6240SSascha Wildner 			continue;
2249d0b6240SSascha Wildner 		}
2259d0b6240SSascha Wildner 		if (!strcasecmp(argv[arg], "vcd")) {
2269d0b6240SSascha Wildner 			block_type = CDR_DB_XA_MODE2_F2;
2279d0b6240SSascha Wildner 			block_size = 2352;
2289d0b6240SSascha Wildner 			dao = 1;
2299d0b6240SSascha Wildner 			nogap = 1;
2309d0b6240SSascha Wildner 			continue;
2319d0b6240SSascha Wildner 		}
2329d0b6240SSascha Wildner 		if (!block_size)
2339d0b6240SSascha Wildner 			errx(EX_NOINPUT, "no data format selected");
2349d0b6240SSascha Wildner 		if (list) {
2359d0b6240SSascha Wildner 			char file_buf[MAXPATHLEN + 1], *eol;
2369d0b6240SSascha Wildner 			FILE *fp;
2379d0b6240SSascha Wildner 
2389d0b6240SSascha Wildner 			if ((fp = fopen(argv[arg], "r")) == NULL)
2399d0b6240SSascha Wildner 	 			err(EX_NOINPUT, "fopen(%s)", argv[arg]);
2409d0b6240SSascha Wildner 
2419d0b6240SSascha Wildner 			while (fgets(file_buf, sizeof(file_buf), fp) != NULL) {
2429d0b6240SSascha Wildner 				if (*file_buf == '#' || *file_buf == '\n')
2439d0b6240SSascha Wildner 					continue;
2449d0b6240SSascha Wildner 				if ((eol = strchr(file_buf, '\n')))
2459d0b6240SSascha Wildner 					*eol = 0;
2469d0b6240SSascha Wildner 				add_track(file_buf, block_size, block_type, nogap);
2479d0b6240SSascha Wildner 			}
2489d0b6240SSascha Wildner 			if (feof(fp))
2499d0b6240SSascha Wildner 				fclose(fp);
2509d0b6240SSascha Wildner 			else
2519d0b6240SSascha Wildner 				err(EX_IOERR, "fgets(%s)", file_buf);
2529d0b6240SSascha Wildner 		}
2539d0b6240SSascha Wildner 		else
2549d0b6240SSascha Wildner 			add_track(argv[arg], block_size, block_type, nogap);
2559d0b6240SSascha Wildner 	}
2569d0b6240SSascha Wildner 	if (notracks) {
2579d0b6240SSascha Wildner 		if (ioctl(fd, CDIOCSTART, 0) < 0)
2589d0b6240SSascha Wildner 			err(EX_IOERR, "ioctl(CDIOCSTART)");
2599d0b6240SSascha Wildner 		if (!cdopen) {
2609d0b6240SSascha Wildner 			if (ioctl(fd, CDRIOCINITWRITER, &test_write) < 0)
2619d0b6240SSascha Wildner 				err(EX_IOERR, "ioctl(CDRIOCINITWRITER)");
2629d0b6240SSascha Wildner 			cdopen = 1;
2639d0b6240SSascha Wildner 		}
2649d0b6240SSascha Wildner 		if (dao)
2659d0b6240SSascha Wildner 			do_DAO(test_write, multi);
2669d0b6240SSascha Wildner 		else
2679d0b6240SSascha Wildner 			do_TAO(test_write, preemp);
2689d0b6240SSascha Wildner 	}
2699d0b6240SSascha Wildner 	if (fixate && !dao) {
2709d0b6240SSascha Wildner 		if (!quiet)
2719d0b6240SSascha Wildner 			fprintf(stderr, "fixating CD, please wait..\n");
2729d0b6240SSascha Wildner 		if (ioctl(fd, CDRIOCFIXATE, &multi) < 0)
2739d0b6240SSascha Wildner         		err(EX_IOERR, "ioctl(CDRIOCFIXATE)");
2749d0b6240SSascha Wildner 	}
2759d0b6240SSascha Wildner 
2769d0b6240SSascha Wildner 	if (ioctl(fd, CDRIOCSETBLOCKSIZE, &saved_block_size) < 0) {
2779d0b6240SSascha Wildner 		err_set_exit(NULL);
2789d0b6240SSascha Wildner 		err(EX_IOERR, "ioctl(CDRIOCSETBLOCKSIZE)");
2799d0b6240SSascha Wildner 	}
2809d0b6240SSascha Wildner 
2819d0b6240SSascha Wildner 	if (eject)
2829d0b6240SSascha Wildner 		if (ioctl(fd, CDIOCEJECT) < 0)
2839d0b6240SSascha Wildner 			err(EX_IOERR, "ioctl(CDIOCEJECT)");
2849d0b6240SSascha Wildner 	close(fd);
2859d0b6240SSascha Wildner 	exit(EX_OK);
2869d0b6240SSascha Wildner }
2879d0b6240SSascha Wildner 
28825809140SSascha Wildner static void
add_track(char * name,int block_size,int block_type,int nogap)2899d0b6240SSascha Wildner add_track(char *name, int block_size, int block_type, int nogap)
2909d0b6240SSascha Wildner {
2919d0b6240SSascha Wildner 	struct stat sb;
2929d0b6240SSascha Wildner 	int file;
2939d0b6240SSascha Wildner 	static int done_stdin = 0;
2949d0b6240SSascha Wildner 
2959d0b6240SSascha Wildner 	if (!strcmp(name, "-")) {
2969d0b6240SSascha Wildner 		if (done_stdin) {
2979d0b6240SSascha Wildner 			warn("skipping multiple usages of stdin");
2989d0b6240SSascha Wildner 			return;
2999d0b6240SSascha Wildner 		}
3009d0b6240SSascha Wildner 		file = STDIN_FILENO;
3019d0b6240SSascha Wildner 		done_stdin = 1;
3029d0b6240SSascha Wildner 	}
3039d0b6240SSascha Wildner 	else if ((file = open(name, O_RDONLY, 0)) < 0)
3049d0b6240SSascha Wildner 		err(EX_NOINPUT, "open(%s)", name);
3059d0b6240SSascha Wildner 	if (fstat(file, &sb) < 0)
3069d0b6240SSascha Wildner 		err(EX_IOERR, "fstat(%s)", name);
3079d0b6240SSascha Wildner 	tracks[notracks].file = file;
3089d0b6240SSascha Wildner 	tracks[notracks].file_name = name;
3099d0b6240SSascha Wildner 	if (file == STDIN_FILENO)
3109d0b6240SSascha Wildner 		tracks[notracks].file_size = -1;
3119d0b6240SSascha Wildner 	else
3129d0b6240SSascha Wildner 		tracks[notracks].file_size = sb.st_size;
3139d0b6240SSascha Wildner 	tracks[notracks].block_size = block_size;
3149d0b6240SSascha Wildner 	tracks[notracks].block_type = block_type;
3159d0b6240SSascha Wildner 
3169d0b6240SSascha Wildner 	if (nogap && notracks)
3179d0b6240SSascha Wildner 		tracks[notracks].pregap = 0;
3189d0b6240SSascha Wildner 	else {
3199d0b6240SSascha Wildner 		if (tracks[notracks - (notracks > 0)].block_type == block_type)
3209d0b6240SSascha Wildner 			tracks[notracks].pregap = 150;
3219d0b6240SSascha Wildner 		else
3229d0b6240SSascha Wildner 			tracks[notracks].pregap = 255;
3239d0b6240SSascha Wildner 	}
3249d0b6240SSascha Wildner 
3259d0b6240SSascha Wildner 	if (verbose) {
3269d0b6240SSascha Wildner 		int pad = 0;
3279d0b6240SSascha Wildner 
3289d0b6240SSascha Wildner 		if (tracks[notracks].file_size / tracks[notracks].block_size !=
3299d0b6240SSascha Wildner 		    roundup_blocks(&tracks[notracks]))
3309d0b6240SSascha Wildner 			pad = 1;
3319d0b6240SSascha Wildner 		fprintf(stderr,
3329d0b6240SSascha Wildner 			"adding type 0x%02x file %s size %d KB %d blocks %s\n",
3339d0b6240SSascha Wildner 			tracks[notracks].block_type, name, (int)sb.st_size/1024,
3349d0b6240SSascha Wildner 			roundup_blocks(&tracks[notracks]),
3359d0b6240SSascha Wildner 			pad ? "(0 padded)" : "");
3369d0b6240SSascha Wildner 	}
3379d0b6240SSascha Wildner 	notracks++;
3389d0b6240SSascha Wildner }
3399d0b6240SSascha Wildner 
34025809140SSascha Wildner static void
do_DAO(int test_write,int multi)3419d0b6240SSascha Wildner do_DAO(int test_write, int multi)
3429d0b6240SSascha Wildner {
3439d0b6240SSascha Wildner 	struct cdr_cuesheet sheet;
3449d0b6240SSascha Wildner 	struct cdr_cue_entry cue[100];
3459d0b6240SSascha Wildner 	int format = CDR_SESS_CDROM;
3469d0b6240SSascha Wildner 	int addr, i, j = 0;
3479d0b6240SSascha Wildner 
3489d0b6240SSascha Wildner 	int bt2ctl[16] = { 0x0,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
3499d0b6240SSascha Wildner 			   0x4, 0x4, 0x4, 0x4, 0x4, 0x4,  -1,  -1 };
3509d0b6240SSascha Wildner 
3519d0b6240SSascha Wildner 	int bt2df[16] = { 0x0,    -1,   -1,   -1,   -1,   -1,   -1,   -1,
3529d0b6240SSascha Wildner 			  0x10, 0x30, 0x20,   -1, 0x21,   -1,   -1,   -1 };
3539d0b6240SSascha Wildner 
3549d0b6240SSascha Wildner 	if (ioctl(fd, CDRIOCNEXTWRITEABLEADDR, &addr) < 0)
3559d0b6240SSascha Wildner 		err(EX_IOERR, "ioctl(CDRIOCNEXTWRITEABLEADDR)");
3569d0b6240SSascha Wildner 	if (verbose)
3579d0b6240SSascha Wildner 		fprintf(stderr, "next writeable LBA %d\n", addr);
3589d0b6240SSascha Wildner 
3599d0b6240SSascha Wildner 	cue_ent(&cue[j++], bt2ctl[tracks[0].block_type], 0x01, 0x00, 0x0,
3609d0b6240SSascha Wildner 		(bt2df[tracks[0].block_type] & 0xf0) |
3619d0b6240SSascha Wildner 		(tracks[0].block_type < 8 ? 0x01 : 0x04), 0x00, addr);
3629d0b6240SSascha Wildner 
3639d0b6240SSascha Wildner 	for (i = 0; i < notracks; i++) {
3649d0b6240SSascha Wildner 		if (bt2ctl[tracks[i].block_type] < 0 ||
3659d0b6240SSascha Wildner 		    bt2df[tracks[i].block_type] < 0)
3669d0b6240SSascha Wildner 			err(EX_IOERR, "track type not supported in DAO mode");
3679d0b6240SSascha Wildner 
3689d0b6240SSascha Wildner 		if (tracks[i].block_type >= CDR_DB_XA_MODE1)
3699d0b6240SSascha Wildner 			format = CDR_SESS_CDROM_XA;
3709d0b6240SSascha Wildner 
3719d0b6240SSascha Wildner 		if (i == 0) {
3729d0b6240SSascha Wildner 			addr += tracks[i].pregap;
3739d0b6240SSascha Wildner 			tracks[i].addr = addr;
3749d0b6240SSascha Wildner 
3759d0b6240SSascha Wildner 			cue_ent(&cue[j++], bt2ctl[tracks[i].block_type],
3769d0b6240SSascha Wildner 				0x01, i+1, 0x1, bt2df[tracks[i].block_type],
3779d0b6240SSascha Wildner 				0x00, addr);
3789d0b6240SSascha Wildner 
3799d0b6240SSascha Wildner 		}
3809d0b6240SSascha Wildner 		else {
3819d0b6240SSascha Wildner 			if (tracks[i].pregap) {
3829d0b6240SSascha Wildner 				if (tracks[i].block_type > 0x7) {
3839d0b6240SSascha Wildner 					cue_ent(&cue[j++],bt2ctl[tracks[i].block_type],
3849d0b6240SSascha Wildner 						0x01, i+1, 0x0,
3859d0b6240SSascha Wildner 						(bt2df[tracks[i].block_type] & 0xf0) |
3869d0b6240SSascha Wildner 						(tracks[i].block_type < 8 ? 0x01 :0x04),
3879d0b6240SSascha Wildner 						0x00, addr);
3889d0b6240SSascha Wildner 				}
3899d0b6240SSascha Wildner 				else
3909d0b6240SSascha Wildner 					cue_ent(&cue[j++],bt2ctl[tracks[i].block_type],
3919d0b6240SSascha Wildner 						0x01, i+1, 0x0,
3929d0b6240SSascha Wildner 						bt2df[tracks[i].block_type],
3939d0b6240SSascha Wildner 						0x00, addr);
3949d0b6240SSascha Wildner 			}
3959d0b6240SSascha Wildner 			tracks[i].addr = tracks[i - 1].addr +
3969d0b6240SSascha Wildner 				roundup_blocks(&tracks[i - 1]);
3979d0b6240SSascha Wildner 
3989d0b6240SSascha Wildner 			cue_ent(&cue[j++], bt2ctl[tracks[i].block_type],
3999d0b6240SSascha Wildner 				0x01, i+1, 0x1, bt2df[tracks[i].block_type],
4009d0b6240SSascha Wildner 				0x00, addr + tracks[i].pregap);
4019d0b6240SSascha Wildner 
4029d0b6240SSascha Wildner 			if (tracks[i].block_type > 0x7)
4039d0b6240SSascha Wildner 				addr += tracks[i].pregap;
4049d0b6240SSascha Wildner 		}
4059d0b6240SSascha Wildner 		addr += roundup_blocks(&tracks[i]);
4069d0b6240SSascha Wildner 	}
4079d0b6240SSascha Wildner 
4089d0b6240SSascha Wildner 	cue_ent(&cue[j++], bt2ctl[tracks[i - 1].block_type], 0x01, 0xaa, 0x01,
4099d0b6240SSascha Wildner 		(bt2df[tracks[i - 1].block_type] & 0xf0) |
4109d0b6240SSascha Wildner 		(tracks[i - 1].block_type < 8 ? 0x01 : 0x04), 0x00, addr);
4119d0b6240SSascha Wildner 
4129d0b6240SSascha Wildner 	sheet.len = j * 8;
4139d0b6240SSascha Wildner 	sheet.entries = cue;
4149d0b6240SSascha Wildner 	sheet.test_write = test_write;
4159d0b6240SSascha Wildner 	sheet.session_type = multi ? CDR_SESS_MULTI : CDR_SESS_NONE;
4169d0b6240SSascha Wildner 	sheet.session_format = format;
4179d0b6240SSascha Wildner 	if (verbose) {
4189d0b6240SSascha Wildner 		u_int8_t *ptr = (u_int8_t *)sheet.entries;
4199d0b6240SSascha Wildner 
4209d0b6240SSascha Wildner 		fprintf(stderr,"CUE sheet:");
4219d0b6240SSascha Wildner 		for (i = 0; i < sheet.len; i++)
4229d0b6240SSascha Wildner 			if (i % 8)
4239d0b6240SSascha Wildner 				fprintf(stderr," %02x", ptr[i]);
4249d0b6240SSascha Wildner 			else
4259d0b6240SSascha Wildner 				fprintf(stderr,"\n%02x", ptr[i]);
4269d0b6240SSascha Wildner 		fprintf(stderr,"\n");
4279d0b6240SSascha Wildner 	}
4289d0b6240SSascha Wildner 
4299d0b6240SSascha Wildner 	if (ioctl(fd, CDRIOCSENDCUE, &sheet) < 0)
4309d0b6240SSascha Wildner 		err(EX_IOERR, "ioctl(CDRIOCSENDCUE)");
4319d0b6240SSascha Wildner 
4329d0b6240SSascha Wildner 	for (i = 0; i < notracks; i++) {
4339d0b6240SSascha Wildner 		if (write_file(&tracks[i]))
4349d0b6240SSascha Wildner 			err(EX_IOERR, "write_file");
4359d0b6240SSascha Wildner 	}
4369d0b6240SSascha Wildner 
4379d0b6240SSascha Wildner 	ioctl(fd, CDRIOCFLUSH);
4389d0b6240SSascha Wildner }
4399d0b6240SSascha Wildner 
44025809140SSascha Wildner static void
do_TAO(int test_write,int preemp)4419d0b6240SSascha Wildner do_TAO(int test_write, int preemp)
4429d0b6240SSascha Wildner {
4439d0b6240SSascha Wildner 	struct cdr_track track;
4449d0b6240SSascha Wildner 	int i;
4459d0b6240SSascha Wildner 
4469d0b6240SSascha Wildner 	for (i = 0; i < notracks; i++) {
4479d0b6240SSascha Wildner 		track.test_write = test_write;
4489d0b6240SSascha Wildner 		track.datablock_type = tracks[i].block_type;
4499d0b6240SSascha Wildner 		track.preemp = preemp;
4509d0b6240SSascha Wildner 		if (ioctl(fd, CDRIOCINITTRACK, &track) < 0)
4519d0b6240SSascha Wildner 			err(EX_IOERR, "ioctl(CDRIOCINITTRACK)");
4529d0b6240SSascha Wildner 
4539d0b6240SSascha Wildner 		if (ioctl(fd, CDRIOCNEXTWRITEABLEADDR, &tracks[i].addr) < 0)
4549d0b6240SSascha Wildner 			err(EX_IOERR, "ioctl(CDRIOCNEXTWRITEABLEADDR)");
4559d0b6240SSascha Wildner 		if (!quiet)
4569d0b6240SSascha Wildner 			fprintf(stderr, "next writeable LBA %d\n",
4579d0b6240SSascha Wildner 				tracks[i].addr);
4589d0b6240SSascha Wildner 		if (write_file(&tracks[i]))
4599d0b6240SSascha Wildner 			err(EX_IOERR, "write_file");
4609d0b6240SSascha Wildner 		if (ioctl(fd, CDRIOCFLUSH) < 0)
4619d0b6240SSascha Wildner 			err(EX_IOERR, "ioctl(CDRIOCFLUSH)");
4629d0b6240SSascha Wildner 	}
4639d0b6240SSascha Wildner }
4649d0b6240SSascha Wildner 
46525809140SSascha Wildner static int
write_file(struct track_info * track_info)4669d0b6240SSascha Wildner write_file(struct track_info *track_info)
4679d0b6240SSascha Wildner {
4689d0b6240SSascha Wildner 	int size, count, filesize;
4699d0b6240SSascha Wildner 	char buf[2352*BLOCKS];
4709d0b6240SSascha Wildner 	static int tot_size = 0;
4719d0b6240SSascha Wildner 
4729d0b6240SSascha Wildner 	filesize = track_info->file_size / 1024;
4739d0b6240SSascha Wildner 
4749d0b6240SSascha Wildner 	if (ioctl(fd, CDRIOCSETBLOCKSIZE, &track_info->block_size) < 0)
4759d0b6240SSascha Wildner 		err(EX_IOERR, "ioctl(CDRIOCSETBLOCKSIZE)");
4769d0b6240SSascha Wildner 
4779d0b6240SSascha Wildner 	if (track_info->addr >= 0)
4789d0b6240SSascha Wildner 		lseek(fd, track_info->addr * track_info->block_size, SEEK_SET);
4799d0b6240SSascha Wildner 
4809d0b6240SSascha Wildner 	if (verbose)
4819d0b6240SSascha Wildner 		fprintf(stderr, "addr = %d size = %d blocks = %d\n",
4829d0b6240SSascha Wildner 			track_info->addr, track_info->file_size,
4839d0b6240SSascha Wildner 			roundup_blocks(track_info));
4849d0b6240SSascha Wildner 
4859d0b6240SSascha Wildner 	if (!quiet) {
4869d0b6240SSascha Wildner 		if (track_info->file == STDIN_FILENO)
4879d0b6240SSascha Wildner 			fprintf(stderr, "writing from stdin\n");
4889d0b6240SSascha Wildner 		else
4899d0b6240SSascha Wildner 			fprintf(stderr,
4909d0b6240SSascha Wildner 				"writing from file %s size %d KB\n",
4919d0b6240SSascha Wildner 				track_info->file_name, filesize);
4929d0b6240SSascha Wildner 	}
4939d0b6240SSascha Wildner 	size = 0;
4949d0b6240SSascha Wildner 
4959d0b6240SSascha Wildner 	while ((count = read(track_info->file, buf,
4969d0b6240SSascha Wildner 			     MIN((track_info->file_size - size),
4979d0b6240SSascha Wildner 				 track_info->block_size * BLOCKS))) > 0) {
4989d0b6240SSascha Wildner 		int res;
4999d0b6240SSascha Wildner 
5009d0b6240SSascha Wildner 		if (count % track_info->block_size) {
5019d0b6240SSascha Wildner 			/* pad file to % block_size */
5029d0b6240SSascha Wildner 			bzero(&buf[count],
5039d0b6240SSascha Wildner 			      (track_info->block_size * BLOCKS) - count);
5049d0b6240SSascha Wildner 			count = ((count / track_info->block_size) + 1) *
5059d0b6240SSascha Wildner 				track_info->block_size;
5069d0b6240SSascha Wildner 		}
5079d0b6240SSascha Wildner 		if ((res = write(fd, buf, count)) != count) {
5089d0b6240SSascha Wildner 			fprintf(stderr, "\nonly wrote %d of %d bytes err=%d\n",
5099d0b6240SSascha Wildner 				res, count, errno);
5109d0b6240SSascha Wildner 			break;
5119d0b6240SSascha Wildner 		}
5129d0b6240SSascha Wildner 		size += count;
5139d0b6240SSascha Wildner 		tot_size += count;
5149d0b6240SSascha Wildner 		if (!quiet) {
5159d0b6240SSascha Wildner 			int pct;
5169d0b6240SSascha Wildner 
5179d0b6240SSascha Wildner 			fprintf(stderr, "written this track %d KB", size/1024);
5189d0b6240SSascha Wildner 			if (track_info->file != STDIN_FILENO && filesize) {
5199d0b6240SSascha Wildner 				pct = (size / 1024) * 100 / filesize;
5209d0b6240SSascha Wildner 				fprintf(stderr, " (%d%%)", pct);
5219d0b6240SSascha Wildner 			}
5229d0b6240SSascha Wildner 			fprintf(stderr, " total %d KB\r", tot_size/1024);
5239d0b6240SSascha Wildner 		}
5249d0b6240SSascha Wildner 		if (size >= track_info->file_size)
5259d0b6240SSascha Wildner 			break;
5269d0b6240SSascha Wildner 	}
5279d0b6240SSascha Wildner 
5289d0b6240SSascha Wildner 	if (!quiet)
5299d0b6240SSascha Wildner 		fprintf(stderr, "\n");
5309d0b6240SSascha Wildner 	close(track_info->file);
5319d0b6240SSascha Wildner 	return 0;
5329d0b6240SSascha Wildner }
5339d0b6240SSascha Wildner 
53425809140SSascha Wildner static int
roundup_blocks(struct track_info * track)5359d0b6240SSascha Wildner roundup_blocks(struct track_info *track)
5369d0b6240SSascha Wildner {
5379d0b6240SSascha Wildner 	return ((track->file_size + track->block_size - 1) / track->block_size);
5389d0b6240SSascha Wildner }
5399d0b6240SSascha Wildner 
54025809140SSascha Wildner static void
cue_ent(struct cdr_cue_entry * cue,int ctl,int adr,int track,int idx,int dataform,int scms,int lba)5419d0b6240SSascha Wildner cue_ent(struct cdr_cue_entry *cue, int ctl, int adr, int track, int idx,
5429d0b6240SSascha Wildner 	int dataform, int scms, int lba)
5439d0b6240SSascha Wildner {
5449d0b6240SSascha Wildner 	cue->adr = adr;
5459d0b6240SSascha Wildner 	cue->ctl = ctl;
5469d0b6240SSascha Wildner 	cue->track = track;
5479d0b6240SSascha Wildner 	cue->index = idx;
5489d0b6240SSascha Wildner 	cue->dataform = dataform;
5499d0b6240SSascha Wildner 	cue->scms = scms;
5509d0b6240SSascha Wildner 	lba += 150;
5519d0b6240SSascha Wildner 	cue->min = lba / (60*75);
5529d0b6240SSascha Wildner 	cue->sec = (lba % (60*75)) / 75;
5539d0b6240SSascha Wildner 	cue->frame = (lba % (60*75)) % 75;
5549d0b6240SSascha Wildner }
5559d0b6240SSascha Wildner 
55625809140SSascha Wildner static void
cleanup(int dummy __unused)5579d0b6240SSascha Wildner cleanup(int dummy __unused)
5589d0b6240SSascha Wildner {
5599d0b6240SSascha Wildner 	if (ioctl(fd, CDRIOCSETBLOCKSIZE, &saved_block_size) < 0)
5609d0b6240SSascha Wildner 		err(EX_IOERR, "ioctl(CDRIOCSETBLOCKSIZE)");
5619d0b6240SSascha Wildner }
5629d0b6240SSascha Wildner 
56325809140SSascha Wildner static void
usage(void)5649d0b6240SSascha Wildner usage(void)
5659d0b6240SSascha Wildner {
5669d0b6240SSascha Wildner 	fprintf(stderr,
5679d0b6240SSascha Wildner 	    "Usage: %s [-delmnpqtv] [-f device] [-s speed] [command]"
5689d0b6240SSascha Wildner 	    " [command file ...]\n", getprogname());
5699d0b6240SSascha Wildner 	exit(EX_USAGE);
5709d0b6240SSascha Wildner }
571