📄 cdrecord.c
字号:
/* @(#)cdrecord.c 1.94 00/01/28 Copyright 1995-2000 J. Schilling */#ifndef lintstatic char sccsid[] = "@(#)cdrecord.c 1.94 00/01/28 Copyright 1995-2000 J. Schilling";#endif/* * Record data on a CD/CVD-Recorder * * Copyright (c) 1995-2000 J. Schilling *//* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */#include <mconfig.h>#include <stdio.h>#include <standard.h>#include <stdxlib.h>#include <fctldefs.h>#include <errno.h>#include <sys/types.h>#include <sys/time.h>#ifdef HAVE_SYS_RESOURCE_H#include <sys/resource.h> /* for rlimit */#endif#include <sys/stat.h>#include <statdefs.h>#include <unixstd.h>#ifdef HAVE_SYS_MMAN_H#include <sys/mman.h>#endif#include <strdefs.h>#include <utypes.h>#include <intcvt.h>#include <signal.h>#include <scg/scsireg.h> /* XXX wegen SC_NOT_READY */#include <scg/scsitransp.h>#include <scg/scgcmd.h> /* XXX fuer read_buffer */#include "scsi_scan.h"#include "auheader.h"#include "cdrecord.h"char cdr_version[] = "1.8";/* * Map toc/track types into names. */char *toc2name[] = { "CD-DA", "CD-ROM", "CD-ROM XA mode 1", "CD-ROM XA mode 2", "CD-I", "Illegal toc type 5", "Illegal toc type 6", "Illegal toc type 7",};/* * Map sector types into names. */char *st2name[] = { "Illegal sector type 0", "CD-ROM mode 1", "CD-ROM mode 2", "Illegal sector type 3", "CD-DA without preemphasis", "CD-DA with preemphasis", "Illegal sector type 6", "Illegal sector type 7",};/* * Map data block types into names. */char *db2name[] = { "Raw (audio)", "Raw (audio) with P/Q sub channel", "Raw (audio) with P/W sub channel", "Raw (audio) with P/W raw sub channel", "Reserved mode 4", "Reserved mode 5", "Reserved mode 6", "Vendor unique mode 7", "CD-ROM mode 1", "CD-ROM mode 2", "CD-ROM XA mode 1", "CD-ROM XA mode 2 form 1", "CD-ROM XA mode 2 form 2", "CD-ROM XA mode 2 form 1/2/mix", "Reserved mode 14", "Vendor unique mode 15",};int debug; /* print debug messages */LOCAL int scsi_verbose; /* SCSI verbose flag */int lverbose; /* local verbose flag *//* * NOTICE: You should not make BUF_SIZE more than * the buffer size of the CD-Recorder. * * Do not set BUF_SIZE to be more than 126 KBytes * if you are running cdrecord on a sun4c machine. * * WARNING: Philips CDD 521 dies if BUF_SIZE is to big. *//*#define BUF_SIZE (126*1024)*//*#define BUF_SIZE (100*1024)*/#define BUF_SIZE (63*1024)/*#define BUF_SIZE (56*1024)*/char *buf; /* The transfer buffer */long bufsize; /* The size of the transfer buffer */int data_secs_per_tr; /* # of data secs per transfer */int audio_secs_per_tr; /* # of audio secs per transfer */BOOL isgui;int didintr;struct timeval starttime;struct timeval stoptime;struct timeval fixtime;static long fs = -1L; /* fifo (ring buffer) size */EXPORT int main __PR((int ac, char **av));LOCAL void usage __PR((int));LOCAL void blusage __PR((int));LOCAL void intr __PR((int sig));LOCAL void intfifo __PR((int sig));LOCAL void exscsi __PR((int excode, void *arg));LOCAL void excdr __PR((int excode, void *arg));EXPORT int read_buf __PR((int f, char *bp, int size));EXPORT int get_buf __PR((int f, char **bpp, int size));LOCAL int write_track_data __PR((SCSI *scgp, cdr_t *, int , track_t *));EXPORT int pad_track __PR((SCSI *scgp, cdr_t *dp, int track, track_t *trackp, long startsec, long amt, BOOL dolast, long *bytesp));EXPORT int write_buf __PR((SCSI *scgp, cdr_t *dp, int track, track_t *trackp, char *bp, long startsec, long amt, int secsize, BOOL dolast, long *bytesp));LOCAL void printdata __PR((int, track_t *));LOCAL void printaudio __PR((int, track_t *));LOCAL void checkfile __PR((int, track_t *));LOCAL int checkfiles __PR((int, track_t *));LOCAL void setpregaps __PR((int, track_t *));LOCAL long checktsize __PR((int, track_t *));LOCAL void checksize __PR((track_t *));LOCAL BOOL checkdsize __PR((SCSI *scgp, cdr_t *dp, dstat_t *dsp, long tsize));LOCAL void raise_fdlim __PR((void));LOCAL void gargs __PR((int, char **, int *, track_t *, char **, int *, cdr_t **, int *, long *, int *, int *));LOCAL void set_trsizes __PR((cdr_t *, int, track_t *));EXPORT void load_media __PR((SCSI *scgp, cdr_t *, BOOL));EXPORT void unload_media __PR((SCSI *scgp, cdr_t *, int));EXPORT void set_secsize __PR((SCSI *scgp, int secsize));LOCAL void check_recovery __PR((SCSI *scgp, cdr_t *, int)); void audioread __PR((SCSI *scgp, cdr_t *, int));LOCAL void print_msinfo __PR((SCSI *scgp, cdr_t *));LOCAL void print_toc __PR((SCSI *scgp, cdr_t *));LOCAL void print_track __PR((int, long, struct msf *, int, int, int));LOCAL void prtimediff __PR((const char *fmt, struct timeval *start, struct timeval *stop));#if !defined(HAVE_SYS_PRIOCNTL_H)LOCAL int rt_raisepri __PR((int));#endifEXPORT void raisepri __PR((int));LOCAL void checkgui __PR((void));LOCAL char * astoll __PR((const char *s, Llong *ll));LOCAL Llong number __PR((char* arg, int* retp));EXPORT int getnum __PR((char* arg, long* valp));EXPORT int getllnum __PR((char *arg, Llong* lvalp));LOCAL int getbltype __PR((char* optstr, long *typep));struct exargs { SCSI *scgp; cdr_t *dp; int old_secsize; int flags; int exflags;} exargs;EXPORT int main(ac, av) int ac; char *av[];{ char *dev = NULL; int timeout = 40; /* Set default timeout to 40s CW-7502 is slow*/ int speed = 1; long flags = 0L; int toctype = -1; int blanktype = 0; int i; int tracks = 0; int trackno; long tsize; track_t track[MAX_TRACK+2]; /* Max tracks + track 0 + track AA */ cdr_t *dp = (cdr_t *)0; dstat_t ds; long startsec = 0L; int errs = 0; SCSI *scgp; char errstr[80];#ifdef __EMX__ /* This gives wildcard expansion with Non-Posix shells with EMX */ _wildcard(&ac, &av); #endif save_args(ac, av); fillbytes(track, sizeof(track), '\0'); raise_fdlim(); gargs(ac, av, &tracks, track, &dev, &timeout, &dp, &speed, &flags, &toctype, &blanktype); if (toctype < 0) comerrno(EX_BAD, "Internal error: Bad TOC type.\n"); /* * Warning: you are not allowed to modify or to remove this * version printing code! */#ifdef DRV_DVD i = set_cdrcmds("mmc_dvd", (cdr_t **)NULL);#endif if ((flags & F_MSINFO) == 0 || lverbose || flags & F_VERSION) printf("Cdrecord%s %s (%s-%s-%s) Copyright (C) 1995-2000 J鰎g Schilling\n",#ifdef DRV_DVD i?"-ProDVD":"",#else "",#endif cdr_version, HOST_CPU, HOST_VENDOR, HOST_OS); if (flags & F_VERSION) exit(0); checkgui(); if (debug || lverbose) { printf("TOC Type: %d = %s\n", toctype, toc2name[toctype & TOC_MASK]); } if ((flags & (F_MSINFO|F_TOC|F_PRATIP|F_FIX|F_VERSION|F_CHECKDRIVE|F_INQUIRY|F_SCANBUS|F_RESET)) == 0) { /* * Try to lock us im memory (will only work for root) * but you need access to root anyway to use /dev/scg? */#if defined(HAVE_MLOCKALL) || defined(_POSIX_MEMLOCK) if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0) { errmsg("WARNING: Cannot do mlockall(2).\n"); errmsgno(EX_BAD, "WARNING: This causes a high risk for buffer underruns.\n"); }#endif raisepri(0); /* max priority */ init_fifo(fs); } if ((scgp = open_scsi(dev, errstr, sizeof(errstr), debug, (flags & F_MSINFO) == 0 || lverbose)) == (SCSI *)0) { errmsg("%s%sCannot open SCSI driver.\n", errstr, errstr[0]?". ":""); comerrno(EX_BAD, "For possible targets try 'cdrecord -scanbus'. Make sure you are root.\n"); } scsi_settimeout(scgp, timeout); scgp->verbose = scsi_verbose; scgp->debug = debug; scgp->cap->c_bsize = 2048; if ((flags & F_MSINFO) == 0 || lverbose) { char *vers; char *auth; /* * Warning: you are not allowed to modify or to remove this * version checking code! */ vers = scg_version(0, SCG_VERSION); auth = scg_version(0, SCG_AUTHOR); printf("Using libscg version '%s-%s'\n", auth, vers); if (auth == 0 || strcmp("schily", auth) != 0) { errmsgno(EX_BAD, "Warning: using inofficial version of libscg (%s-%s '%s').\n", auth, vers, scg_version(0, SCG_SCCS_ID)); } vers = scg_version(scgp, SCG_VERSION); auth = scg_version(scgp, SCG_AUTHOR); if (lverbose > 1) error("Using libscg transport code version '%s-%s'\n", auth, vers); if (auth == 0 || strcmp("schily", auth) != 0) { errmsgno(EX_BAD, "Warning: using inofficial libscg transport code version (%s-%s '%s').\n", auth, vers, scg_version(scgp, SCG_SCCS_ID)); } } bufsize = scsi_bufsize(scgp, BUF_SIZE); if ((buf = scsi_getbuf(scgp, bufsize)) == NULL) comerr("Cannot get SCSI I/O buffer.\n"); if ((flags & F_SCANBUS) != 0) { select_target(scgp); exit(0); } if ((flags & F_RESET) != 0) { scsireset(scgp); exit(0); } /* * First try to check which type of SCSI device we * have. */ if (debug || lverbose) printf("atapi: %d\n", scsi_isatapi(scgp)); scgp->silent++; test_unit_ready(scgp); /* eat up unit attention */ scgp->silent--; if (!do_inquiry(scgp, (flags & F_MSINFO) == 0 || lverbose)) { errmsgno(EX_BAD, "Cannot do inquiry for CD/DVD-Recorder.\n"); if (unit_ready(scgp)) errmsgno(EX_BAD, "The unit seems to be hung and needs power cycling.\n"); exit(EX_BAD); } if ((flags & F_PRCAP) != 0) { print_capabilities(scgp); exit(0); } if ((flags & F_INQUIRY) != 0) exit(0); if (dp == (cdr_t *)NULL) { /* No driver= option specified */ dp = get_cdrcmds(scgp); } else if (!is_unknown_dev(scgp) && dp != get_cdrcmds(scgp)) { errmsgno(EX_BAD, "WARNING: Trying to use other driver on known device.\n"); } if (!is_cddrive(scgp)) comerrno(EX_BAD, "Sorry, no CD/DVD-Drive found on this target.\n"); if (dp == (cdr_t *)0) comerrno(EX_BAD, "Sorry, no supported CD/DVD-Recorder found on this target.\n"); if (((flags & (F_MSINFO|F_TOC|F_LOAD|F_EJECT)) == 0 || tracks > 0) && (dp->cdr_flags & CDR_ISREADER) != 0) { comerrno(EX_BAD, "Sorry, no CD/DVD-Recorder or unsupported CD/DVD-Recorder found on this target.\n"); } if ((*dp->cdr_attach)(scgp, dp) != 0) comerrno(EX_BAD, "Cannot attach driver for CD/DVD-Recorder.\n"); exargs.scgp = scgp; exargs.dp = dp; exargs.old_secsize = -1; exargs.flags = flags; if ((flags & F_MSINFO) == 0 || lverbose) { printf("Using %s (%s).\n", dp->cdr_drtext, dp->cdr_drname); printf("Driver flags : "); if ((dp->cdr_flags & CDR_SWABAUDIO) != 0) printf("SWABAUDIO"); printf("\n"); } scgp->silent++; if ((debug || lverbose)) { tsize = -1; if ((*dp->cdr_buffer_cap)(scgp, &tsize, (long *)0) < 0 || tsize <= 0) { if (read_buffer(scgp, buf, 4, 0) >= 0) tsize = a_to_u_4_byte(buf); } if (tsize > 0) { printf("Drive buf size : %lu = %lu KB\n", tsize, tsize >> 10); } } scgp->silent--; if (tracks > 0 && (debug || lverbose)) printf("FIFO size : %lu = %lu KB\n", fs, fs >> 10); if ((flags & F_CHECKDRIVE) != 0) exit(0); if (tracks == 0 && (flags & (F_FIX|F_BLANK)) == 0 && (flags & F_EJECT) != 0) { /* * Do not check if the unit is ready here to allow to open * an empty unit too. */ unload_media(scgp, dp, flags); exit(0); } flush(); if (tracks > 1) sleep(2); /* Let the user watch the inquiry messages */ set_trsizes(dp, tracks, track); setpregaps(tracks, track); checkfiles(tracks, track); tsize = checktsize(tracks, track);do_cue(tracks, track, 0); /* * Is this the right place to do this ? */ check_recovery(scgp, dp, flags); if ((flags & F_FORCE) == 0) load_media(scgp, dp, TRUE); if ((flags & F_LOAD) != 0) { scgp->silent++; /* silently */ scsi_prevent_removal(scgp, 0); /* allow manual open */ scgp->silent--; /* if load failed... */ exit(0); } exargs.old_secsize = sense_secsize(scgp, 1); if (exargs.old_secsize < 0) exargs.old_secsize = sense_secsize(scgp, 0); on_comerr(exscsi, &exargs); if (lverbose) printf("Current Secsize: %d\n", exargs.old_secsize); if (exargs.old_secsize > 0 && exargs.old_secsize != 2048) { /* * Some drives (e.g. Plextor) don't like to write correctly * in DAO mode if the sector size is set to 512 bytes. * In addition, cdrecord -msinfo will not work properly * if the sector size is not 2048 bytes. */ set_secsize(scgp, 2048); }/*audioread(dp, flags);*//*unload_media(scgp, dp, flags);*//*return 0;*/ fillbytes(&ds, sizeof(ds), '\0'); if (flags & F_WRITE) ds.ds_cdrflags = RF_WRITE; if (flags & F_PRATIP) { lverbose++; /* XXX Hack */ } if ((*dp->cdr_getdisktype)(scgp, dp, &ds) < 0) { errmsgno(EX_BAD, "Cannot get disk type.\n"); exscsi(EX_BAD, &exargs); if ((flags & F_FORCE) == 0) exit(EX_BAD); } if (flags & F_PRATIP) { lverbose--; /* XXX Hack */ exscsi(0, &exargs); exit(0); } /* * The next actions should depend on the disk type. */ /* * Dirty hack! * At least MMC drives will not return the next writable * address we expect when the drive's write mode is set * tp DAO/SAO. We need this address for mkisofs and thus * it must be the first user accessible sector and not the * first sector of the pregap. Set_speed_dummy() witha a * 'speedp' f 0 sets the write mode to TAO on MMC drives. * * We set TAO unconditionally to make checkdsize() work * currectly in DAO mode too. */ scgp->silent++; (*dp->cdr_set_speed_dummy)(scgp, 0, TRUE); scgp->silent--; if (flags & F_MSINFO) { print_msinfo(scgp, dp); exscsi(0, &exargs); exit(0); } if (flags & F_TOC) { print_toc(scgp, dp); exscsi(0, &exargs); exit(0); }#ifdef XXX if ((*dp->cdr_check_session)() < 0) { exscsi(EX_BAD, &exargs); exit(EX_BAD);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -