]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/burncd/burncd.c
Change to spell erasing right.
[FreeBSD/FreeBSD.git] / usr.sbin / burncd / burncd.c
1 /*-
2  * Copyright (c) 2000,2001 Søren Schmidt
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification, immediately at the beginning of the file.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30
31 #include <unistd.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <err.h>
36 #include <sysexits.h>
37 #include <fcntl.h>
38 #include <sys/errno.h>
39 #include <sys/ioctl.h>
40 #include <sys/stat.h>
41 #include <sys/cdio.h>
42 #include <sys/cdrio.h>
43 #include <sys/param.h>
44
45 #define BLOCKS  16
46
47 void cleanup(int);
48 void write_file(const char *, int);
49 void usage(const char *);
50
51 static int fd, quiet, saved_block_size;
52 static struct cdr_track track;
53
54 int
55 main(int argc, char **argv)
56 {
57         int ch, arg, addr;
58         int eject=0, list=0, multi=0, preemp=0, speed=1, test_write=0;
59         char *devname = "/dev/acd0c", *prog_name;
60         int block_size = 0;
61
62         prog_name = argv[0];
63         while ((ch = getopt(argc, argv, "ef:lmpqs:t")) != -1) {
64                 switch (ch) {
65                 case 'e':
66                         eject = 1;
67                         break;
68
69                 case 'f':
70                         devname = optarg;
71                         break;
72
73                 case 'l':
74                         list = 1;
75                         break;
76
77                 case 'm':
78                         multi = 1;
79                         break;
80
81                 case 'p':
82                         preemp = 1;
83                         break;
84
85                 case 'q':
86                         quiet = 1;
87                         break;
88
89                 case 's':
90                         speed = atoi(optarg);
91                         if (speed <= 0)
92                                 errx(EX_USAGE, "Invalid speed: %s", optarg);
93                         break;
94
95                 case 't':
96                         test_write = 1;
97                         break;
98
99                 default: 
100                         usage(prog_name);
101                 }
102         }
103         argc -= optind;
104         argv += optind;
105
106         if (argc == 0)
107                 usage(prog_name);
108
109         if ((fd = open(devname, O_RDWR, 0)) < 0)
110                 err(EX_NOINPUT, "open(%s)", devname);
111
112         if (ioctl(fd, CDRIOCWRITESPEED, &speed) < 0) 
113                 err(EX_IOERR, "ioctl(CDRIOCWRITESPEED)");
114
115         if (ioctl(fd, CDRIOCGETBLOCKSIZE, &saved_block_size) < 0) 
116                 err(EX_IOERR, "ioctl(CDRIOCGETBLOCKSIZE)");
117
118         err_set_exit(cleanup);
119
120         for (arg = 0; arg < argc; arg++) {
121                 if (!strcmp(argv[arg], "fixate")) {
122                         if (!quiet)
123                                 fprintf(stderr, "fixating CD, please wait..\n");
124                         if (ioctl(fd, CDRIOCCLOSEDISK, &multi) < 0)
125                                 err(EX_IOERR, "ioctl(CDRIOCCLOSEDISK)");
126                         break;
127                 }
128                 if (!strcmp(argv[arg], "msinfo")) {
129                         struct ioc_read_toc_single_entry entry;
130
131                         bzero(&entry, sizeof(struct ioc_read_toc_single_entry));
132                         entry.address_format = CD_LBA_FORMAT;
133                         if (ioctl(fd, CDIOREADTOCENTRY, &entry) < 0) 
134                                 err(EX_IOERR, "ioctl(CDIOREADTOCENTRY)");
135                         if (ioctl(fd, CDRIOCNEXTWRITEABLEADDR, &addr) < 0) 
136                                 err(EX_IOERR, "ioctl(CDRIOCNEXTWRITEABLEADDR)");
137                         fprintf(stderr, "%d, %d\n", 
138                                 ntohl(entry.entry.addr.lba), addr);
139
140                         break;
141                 }
142                 if (!strcmp(argv[arg], "erase") || !strcmp(argv[arg], "blank")){
143                         int error, blank, percent;
144
145                         if (!strcmp(argv[arg], "erase"))
146                                 blank = CDR_B_ALL;
147                         else
148                                 blank = CDR_B_MIN;
149                         if (!quiet)
150                                 fprintf(stderr, "%sing CD, please wait..\r",
151                                         blank == CDR_B_ALL ? "eras" : "blank");
152
153                         if (ioctl(fd, CDRIOCBLANK, &blank) < 0)
154                                 err(EX_IOERR, "ioctl(CDRIOCBLANK)");
155                         while (1) {
156                                 sleep(1);
157                                 error = ioctl(fd, CDRIOCGETPROGRESS, &percent);
158                                 if (percent > 0 && !quiet)
159                                         fprintf(stderr, 
160                                                 "%sing CD - %d %% done     \r",
161                                                 blank == CDR_B_ALL ? 
162                                                 "eras" : "blank", percent);
163                                 if (error || percent == 100)
164                                         break;
165                         }
166                         if (!quiet)
167                                 printf("\n");
168                         continue;
169                 }
170                 if (!strcmp(argv[arg], "audio") || !strcmp(argv[arg], "raw")) {
171                         track.test_write = test_write;
172                         track.datablock_type = CDR_DB_RAW;
173                         track.preemp = preemp;
174                         block_size = 2352;
175                         continue;
176                 }
177                 if (!strcmp(argv[arg], "data") || !strcmp(argv[arg], "mode1")) {
178                         track.test_write = test_write;
179                         track.datablock_type = CDR_DB_ROM_MODE1;
180                         track.preemp = 0;
181                         block_size = 2048;
182                         continue;
183                 }
184                 if (!strcmp(argv[arg], "mode2")) {
185                         track.test_write = test_write;
186                         track.datablock_type = CDR_DB_ROM_MODE2;
187                         track.preemp = 0;
188                         block_size = 2336;
189                         continue;
190                 }
191                 if (!strcmp(argv[arg], "XAmode1")) {
192                         track.test_write = test_write;
193                         track.datablock_type = CDR_DB_XA_MODE1;
194                         track.preemp = 0;
195                         block_size = 2048;
196                         continue;
197                 }
198                 if (!block_size)
199                         err(EX_NOINPUT, "no data format selected");
200                 if (list) {
201                         char file_buf[MAXPATHLEN + 1], *eol;
202                         FILE *fp;
203
204                         if ((fp = fopen(argv[arg], "r")) == NULL)
205                                 err(EX_NOINPUT, "fopen(%s)", argv[arg]);
206
207                         while (fgets(file_buf, sizeof(file_buf), fp) != NULL) {
208                                 if (*file_buf == '#' || *file_buf == '\n')
209                                         continue;
210                                 if (eol = strchr(file_buf, '\n'))
211                                         *eol = NULL;
212                                 write_file(file_buf, block_size);
213                         }
214                         if (feof(fp))
215                                 fclose(fp);
216                         else
217                                 err(EX_IOERR, "fgets(%s)", file_buf);
218                 }
219                 else
220                         write_file(argv[arg], block_size);
221         }
222
223         if (ioctl(fd, CDRIOCSETBLOCKSIZE, &saved_block_size) < 0) {
224                 err_set_exit(NULL);
225                 err(EX_IOERR, "ioctl(CDRIOCSETBLOCKSIZE)");
226         }
227
228         if (eject)
229                 if (ioctl(fd, CDIOCEJECT) < 0)
230                         err(EX_IOERR, "ioctl(CDIOCEJECT)");
231         close(fd);
232         exit(EX_OK);
233 }
234
235 void
236 cleanup(int dummy)
237 {
238         if (ioctl(fd, CDRIOCSETBLOCKSIZE, &saved_block_size) < 0) 
239                 err(EX_IOERR, "ioctl(CDRIOCSETBLOCKSIZE)");
240 }
241
242 void
243 usage(const char *prog_name)
244 {
245         fprintf(stderr, "Usage: %s [-f device] [-s speed] [-e] [-l] [-m] [-p]\n"
246                 "\t[-q] [command] [command filename...]\n", prog_name);
247         exit(EX_USAGE);
248 }
249
250 void
251 write_file(const char *name, int block_size)
252 {
253         int addr, count, file, filesize, size;
254         char buf[2352*BLOCKS];
255         struct stat stat;
256         static int cdopen, done_stdin, tot_size = 0;
257
258         if (!strcmp(name, "-")) {
259                 if (done_stdin) {
260                         warn("skipping multiple usages of stdin");
261                         return;
262                 }
263                 file = STDIN_FILENO;
264                 done_stdin = 1;
265         }
266         else if ((file = open(name, O_RDONLY, 0)) < 0)
267                 err(EX_NOINPUT, "open(%s)", name);
268
269         if (!cdopen) {
270                 if (ioctl(fd, CDRIOCOPENDISK) < 0)
271                         err(EX_IOERR, "ioctl(CDRIOCOPENDISK)");
272                 cdopen = 1;
273         }
274
275         if (ioctl(fd, CDRIOCOPENTRACK, &track) < 0)
276                 err(EX_IOERR, "ioctl(CDRIOCOPENTRACK)");
277
278         if (ioctl(fd, CDRIOCNEXTWRITEABLEADDR, &addr) < 0) 
279                 err(EX_IOERR, "ioctl(CDRIOCNEXTWRITEABLEADDR)");
280
281         if (fstat(file, &stat) < 0)
282                 err(EX_IOERR, "fstat(%s)", name);
283         filesize = stat.st_size / 1024;
284
285         if (!quiet) {
286                 fprintf(stderr, "next writeable LBA %d\n", addr);
287                 if (file == STDIN_FILENO)
288                         fprintf(stderr, "writing from stdin\n");
289                 else
290                         fprintf(stderr, 
291                                 "writing from file %s size %d KB\n",
292                                 name, filesize);
293         }
294
295         lseek(fd, addr * block_size, SEEK_SET);
296         size = 0;
297         if (filesize == 0)
298                 filesize++;     /* cheat, avoid divide by zero */
299
300         while ((count = read(file, buf, block_size * BLOCKS)) > 0) {    
301                 int res;
302                 if (count % block_size) {
303                         /* pad file to % block_size */
304                         bzero(&buf[count], block_size * BLOCKS - count);
305                         count = ((count / block_size) + 1) * block_size;
306                 }
307                 if ((res = write(fd, buf, count)) != count) {
308                         fprintf(stderr, "\nonly wrote %d of %d bytes\n",
309                                 res, count);
310                         break;
311                 }
312                 size += count;
313                 tot_size += count;
314                 if (!quiet) {
315                         int pct;
316
317                         fprintf(stderr, "written this track %d KB", size/1024);
318                         if (file != STDIN_FILENO) {
319                                 pct = (size / 1024) * 100 / filesize;
320                                 fprintf(stderr, " (%d%%)", pct);
321                         }
322                         fprintf(stderr, " total %d KB\r", tot_size/1024);
323                 }
324         }
325
326         if (!quiet)
327                 fprintf(stderr, "\n");
328
329         close(file);
330         if (ioctl(fd, CDRIOCCLOSETRACK) < 0)
331                 err(EX_IOERR, "ioctl(CDRIOCCLOSETRACK)");
332 }