diff options
author | Erwan Le Blond <erwan.LEBLOND@eurogiciel.fr> | 2013-03-05 18:28:09 +0100 |
---|---|---|
committer | Erwan Le Blond <erwan.LEBLOND@eurogiciel.fr> | 2013-03-05 18:28:09 +0100 |
commit | c5085a83721004cd76e3b76069e2b1d4ebb7e230 (patch) | |
tree | 041894110a4733c8ce76ccc5f7dcd6cdc9840936 | |
parent | b1795d0b77de3ba5bd68faa440d1c78ff42d6f55 (diff) | |
download | cdrkit-c5085a83721004cd76e3b76069e2b1d4ebb7e230.tar.gz cdrkit-c5085a83721004cd76e3b76069e2b1d4ebb7e230.tar.bz2 cdrkit-c5085a83721004cd76e3b76069e2b1d4ebb7e230.zip |
add cdinfo.c
-rw-r--r-- | packaging/cdinfo.c | 692 |
1 files changed, 692 insertions, 0 deletions
diff --git a/packaging/cdinfo.c b/packaging/cdinfo.c new file mode 100644 index 0000000..43e3a62 --- /dev/null +++ b/packaging/cdinfo.c @@ -0,0 +1,692 @@ +/* + * CD Info 1.1 - prints various information about a CD, + * detects the type of the CD. + * + * (c) 1996,1997,1998 Gerd Knorr <kraxel@goldbach.in-berlin.de> + * and Heiko Eissfeldt <heiko@colossus.escape.de> + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/ioctl.h> +#ifdef __linux__ +# include <linux/version.h> +# include <linux/cdrom.h> +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,50) +# include <linux/ucdrom.h> +# endif +#endif + +#ifndef CDROM_LEADOUT +#define CDROM_LEADOUT (0xAA) +#endif + + +/* +Subject: -65- How can I read an IRIX (EFS) CD-ROM on a machine which + doesn't use EFS? +Date: 18 Jun 1995 00:00:01 EST + + You want 'efslook', at + ftp://viz.tamu.edu/pub/sgi/software/efslook.tar.gz. + +and +! Robert E. Seastrom <rs@access4.digex.net>'s software (with source +! code) for using an SGI CD-ROM on a Macintosh is at +! ftp://bifrost.seastrom.com/pub/mac/CDROM-Jumpstart.sit151.hqx. + +*/ + +#define FS_NO_DATA 0 /* audio only */ +#define FS_HIGH_SIERRA 1 +#define FS_ISO_9660 2 +#define FS_INTERACTIVE 3 +#define FS_HFS 4 +#define FS_UFS 5 +#define FS_EXT2 6 +#define FS_ISO_HFS 7 /* both hfs & isofs filesystem */ +#define FS_ISO_9660_INTERACTIVE 8 /* both CD-RTOS and isofs filesystem */ +#define FS_3DO 9 +#define FS_UNKNOWN 15 +#define FS_MASK 15 + +#define XA 16 +#define MULTISESSION 32 +#define PHOTO_CD 64 +#define HIDDEN_TRACK 128 +#define CDTV 256 +#define BOOTABLE 512 +#define VIDEOCDI 1024 +#define ROCKRIDGE 2048 +#define JOLIET 4096 + +#if 0 +#define STRONG "\033[1m" +#define NORMAL "\033[0m" +#else +#define STRONG "__________________________________\n" +#define NORMAL "" +#endif + +int filehandle; /* Handle of /dev/>cdrom< */ +int rc; /* return code */ +int i,j; /* index */ +int isofs_size = 0; /* size of session */ +int start_track; /* first sector of track */ +int ms_offset; /* multisession offset found by track-walking */ +int data_start; /* start of data area */ +int joliet_level = 0; + +char buffer[2048]; /* for CD-Data */ +char buffer2[2048]; /* for CD-Data */ +char buffer3[2048]; /* for CD-Data */ +char buffer4[2048]; /* for CD-Data */ +char buffer5[2048]; /* for CD-Data */ + +char toc_header[2]; /* first/last Track */ +struct cdrom_tocentry *toc[CDROM_LEADOUT+1]; /* TOC-entries */ +struct cdrom_mcn mcn; +struct cdrom_multisession ms; +struct cdrom_subchnl sub; +int first_data = -1; /* # of first data track */ +int num_data = 0; /* # of data tracks */ +int first_audio = -1; /* # of first audio track */ +int num_audio = 0; /* # of audio tracks */ + +/* ------------------------------------------------------------------------ */ +/* some iso9660 fiddling */ + +#define DEBUG 0 +int read_super(int offset) +{ + /* sector 16, super block */ + memset(buffer,0,2048); + if (0 > lseek(filehandle,2048*(offset+16),SEEK_SET)) + return -1; +#if DEBUG + printf("about to read sector %u\n", offset + 16); +#endif + if (0 > read(filehandle,buffer,2048)) + return -1; + return 0; +} + +int read_super2(int offset) +{ + /* sector 0, for photocd check */ + memset(buffer2,0,2048); + if (0 > lseek(filehandle,2048*(offset+0),SEEK_SET)) + return -1; +#if DEBUG + printf("about to read sector %u\n", offset + 0); +#endif + if (0 > read(filehandle,buffer2,2048)) + return -1; + return 0; +} + +int read_super3(int offset) +{ + /* sector 4, for ufs check */ + memset(buffer3,0,2048); + if (0 > lseek(filehandle,2048*(offset+4),SEEK_SET)) + return -1; +#if DEBUG + printf("about to read sector %u\n", offset + 4); +#endif + if (0 > read(filehandle,buffer3,2048)) + return -1; + return 0; +} + +int read_super4(int offset) +{ + /* sector 17, for bootable CD check */ + memset(buffer4,0,2048); + if (0 > lseek(filehandle,2048*(offset+17),SEEK_SET)) + return -1; +#if DEBUG + printf("about to read sector %u\n", offset + 17); +#endif + if (0 > read(filehandle,buffer4,2048)) + return -1; + return 0; +} + +int read_super5(int offset) +{ + /* sector 150, for Video CD check */ + memset(buffer5,0,2048); + if (0 > lseek(filehandle,2048*(offset+150),SEEK_SET)) + return -1; +#if DEBUG + printf("about to read sector %u\n", offset + 150); +#endif + if (0 > read(filehandle,buffer5,2048)) + return -1; + return 0; +} + +int is_isofs(void) +{ + return 0 == memcmp(&buffer[1],"CD001",5); +} + +int is_hs(void) +{ + return 0 == memcmp(&buffer[9],"CDROM",5); +} + +int is_cdi(void) +{ + return (0 == memcmp(&buffer[1],"CD-I",4)); +} + +int is_cd_rtos(void) +{ + return (0 == memcmp(&buffer[8],"CD-RTOS",7)); +} + +int is_bridge(void) +{ + return (0 == memcmp(&buffer[16],"CD-BRIDGE",9)); +} + +int is_xa(void) +{ + return 0 == memcmp(&buffer[1024],"CD-XA001",8); +} + +int is_cdtv(void) +{ + return (0 == memcmp(&buffer[8],"CDTV",4)); +} + +int is_photocd(void) +{ + return 0 == memcmp(&buffer2[64], "PPPPHHHHOOOOTTTTOOOO____CCCCDDDD", 24); +} + +int is_hfs(void) +{ + return (0 == memcmp(&buffer2[512],"PM",2)) || + (0 == memcmp(&buffer2[512],"TS",2)) || + (0 == memcmp(&buffer2[1024], "BD",2)); +} + +int is_ext2(void) +{ + return 0 == memcmp(&buffer2[0x438],"\x53\xef",2); +} + +int is_3do(void) +{ + return (0 == memcmp(&buffer2[0],"\x01\x5a\x5a\x5a\x5a\x5a\x01", 7)) && + (0 == memcmp(&buffer2[40], "CD-ROM", 6)); +} + +int is_ufs(void) +{ + return 0 == memcmp(&buffer3[1372],"\x54\x19\x01\x0" ,4); +} + +int is_bootable(void) +{ + return 0 == memcmp(&buffer4[7],"EL TORITO",9); +} + +int is_joliet(void) +{ + return 2 == buffer4[0] && buffer4[88] == 0x25 && buffer4[89] == 0x2f; +} + +int is_video_cdi(void) +{ + return 0 == memcmp(&buffer5[0],"VIDEO_CD",8); +} + +int get_size(void) /* iso9660 volume space in 2048 byte units */ +{ + return ((buffer[80] & 0xff) | + ((buffer[81] & 0xff) << 8) | + ((buffer[82] & 0xff) << 16) | + ((buffer[83] & 0xff) << 24)); +} + +int get_joliet_level( void ) +{ + switch (buffer4[90]) { + case 0x40: return 1; + case 0x43: return 2; + case 0x45: return 3; + } + return 0; +} + +int guess_filesystem(int start_session) +{ + int ret = 0; + + if (read_super(start_session) < 0) + return ret; + +#define _DEBUG 0 +#if _DEBUG + /* buffer is defined */ + if (is_cdi()) printf("CD-I, "); + if (is_cd_rtos()) printf("CD-RTOS, "); + if (is_isofs()) printf("ISOFS, "); + if (is_hs()) printf("HS, "); + if (is_bridge()) printf("BRIDGE, "); + if (is_xa()) printf("XA, "); + if (is_cdtv()) printf("CDTV, "); + puts(""); +#endif + + /* filesystem */ + if (is_cdi() && is_cd_rtos() && !is_bridge() && !is_xa()) { + return FS_INTERACTIVE; + } else { /* read sector 0 ONLY, when NO greenbook CD-I !!!! */ + + if (read_super2(start_session) < 0) + return ret; + +#if _DEBUG + /* buffer2 is defined */ + if (is_photocd()) printf("PHOTO CD, "); + if (is_hfs()) printf("HFS, "); + if (is_ext2()) printf("EXT2 FS, "); + if (is_3do()) printf("3DO, "); + puts(""); +#endif + if (is_hs()) + ret |= FS_HIGH_SIERRA; + else if (is_isofs()) { + if (is_cd_rtos() && is_bridge()) + ret = FS_ISO_9660_INTERACTIVE; + else if (is_hfs()) + ret = FS_ISO_HFS; + else + ret = FS_ISO_9660; + isofs_size = get_size(); +#if 0 + if (is_rockridge()) + ret |= ROCKRIDGE; +#endif + if (read_super4(start_session) < 0) + return ret; + +#if _DEBUG + /* buffer4 is defined */ + if (is_joliet()) printf("JOLIET, "); + puts(""); + if (is_bootable()) printf("BOOTABLE, "); + puts(""); +#endif + if (is_joliet()) { + joliet_level = get_joliet_level(); + ret |= JOLIET; + } + if (is_bootable()) + ret |= BOOTABLE; + + if (is_bridge() && is_xa() && is_isofs() && is_cd_rtos() && + !is_photocd()) { + if (read_super5(start_session) < 0) + return ret; + +#if _DEBUG + /* buffer5 is defined */ + if (is_video_cdi()) printf("VIDEO-CDI, "); + puts(""); +#endif + if (is_video_cdi()) + ret |= VIDEOCDI; + } + } else if (is_hfs()) + ret |= FS_HFS; + else if (is_ext2()) + ret |= FS_EXT2; + else if (is_3do()) + ret |= FS_3DO; + else { + + if (read_super3(start_session) < 0) + return ret; + +#if _DEBUG + /* buffer3 is defined */ + if (is_ufs()) printf("UFS, "); + puts(""); +#endif + if (is_ufs()) + ret |= FS_UFS; + else + ret |= FS_UNKNOWN; + } + } + /* other checks */ + if (is_xa()) + ret |= XA; + if (is_photocd()) + ret |= PHOTO_CD; + if (is_cdtv()) + ret |= CDTV; + return ret; +} + +/* ------------------------------------------------------------------------ */ +/* cddb */ + +int +cddb_sum(int n) +{ + int ret=0; + + for (;;) { + ret += n%10; + n = n/10; + if (!n) + return ret; + } +} + +unsigned long +cddb_discid() +{ + int i,t,n=0; + + for (i = 1; i <= toc_header[1]; i++) { + n += cddb_sum(toc[i]->cdte_addr.msf.minute * 60 + + toc[i]->cdte_addr.msf.second); + } + + t = + toc[CDROM_LEADOUT]->cdte_addr.msf.minute * 60 + + toc[CDROM_LEADOUT]->cdte_addr.msf.second + - toc[1]->cdte_addr.msf.minute * 60 + - toc[1]->cdte_addr.msf.second; + + return ((n % 0xff) << 24 | t << 8 | toc_header[1]); +} + +/* ------------------------------------------------------------------------ */ + +char *devname = "/dev/cdrom"; +char *progname; + +int +main(int argc, char *argv[]) +{ + int fs=0; + int need_lf; + progname = strrchr(argv[0],'/'); + progname = progname ? progname+1 : argv[0]; + + if (argc > 1) { + if (0 == strncmp(argv[1],"/dev/",5)) + devname = argv[1]; + else { + devname=malloc(6+strlen(argv[1])); + sprintf(devname,"/dev/%s",argv[1]); + } + } + + printf("CD Info 1.1 | (c) 1996-98 Gerd Knorr & Heiko Eißfeldt\n"); + + /* open device */ + filehandle = open(devname,O_RDONLY); + if (filehandle == -1) { + fprintf(stderr,"%s: %s: %s\n",progname, devname, strerror(errno)); + exit(1); + } + +#ifdef CDROMREADTOCHDR + /* read the number of tracks from CD*/ + if (ioctl(filehandle,CDROMREADTOCHDR,&toc_header)) { + fprintf(stderr,"%s: read TOC ioctl failed, give up\n",progname); + return(0); + } + + printf(STRONG "track list (%i - %i)\n" NORMAL, + toc_header[0],toc_header[1]); + + /* read toc */ + printf(" nr: msf lba ctrl adr type\n"); + for (i = toc_header[0]; i <= CDROM_LEADOUT; i++) { + toc[i] = malloc(sizeof(struct cdrom_tocentry)); + if (toc[i] == NULL) { + fprintf(stderr, "out of memory\n"); + exit(1); + } + memset(toc[i],0,sizeof(struct cdrom_tocentry)); + toc[i]->cdte_track = i; + toc[i]->cdte_format = CDROM_MSF; + if (ioctl(filehandle,CDROMREADTOCENTRY,toc[i])) { + fprintf(stderr, + "%s: read TOC entry ioctl failed for track %i, give up\n", + progname,toc[i]->cdte_track); + exit(1); + } + printf("%3d: %02d:%02d:%02d (%06d) 0x%x 0x%x %s%s\n", + (int)toc[i]->cdte_track, + (int)toc[i]->cdte_addr.msf.minute, + (int)toc[i]->cdte_addr.msf.second, + (int)toc[i]->cdte_addr.msf.frame, + (int)toc[i]->cdte_addr.msf.frame + + (int)toc[i]->cdte_addr.msf.second*75 + + (int)toc[i]->cdte_addr.msf.minute*75*60 - 150, + (int)toc[i]->cdte_ctrl, + (int)toc[i]->cdte_adr, + (toc[i]->cdte_ctrl & CDROM_DATA_TRACK) ? "data ":"audio", + CDROM_LEADOUT == i ? " (leadout)" : ""); + if (i == CDROM_LEADOUT) + break; + if (toc[i]->cdte_ctrl & CDROM_DATA_TRACK) { + num_data++; + if (-1 == first_data) + first_data = toc[i]->cdte_track; + } else { + num_audio++; + if (-1 == first_audio) + first_audio = toc[i]->cdte_track; + } + /* skip to leadout */ + if (i == (int)(toc_header[1])) + i = CDROM_LEADOUT-1; + } +#endif + printf(STRONG "what ioctl's report\n" NORMAL); + +#ifdef CDROM_GET_MCN + /* get mcn */ + printf("get mcn : "); fflush(stdout); + if (ioctl(filehandle,CDROM_GET_MCN,&mcn)) + printf("FAILED\n"); + else + printf("%s\n",mcn.medium_catalog_number); +#endif + +#ifdef CDROM_DISC_STATUS + /* get disk status */ + printf("disc status : "); fflush(stdout); + switch (ioctl(filehandle,CDROM_DISC_STATUS,0)) { + case CDS_NO_INFO: printf("no info\n"); break; + case CDS_NO_DISC: printf("no disc\n"); break; + case CDS_AUDIO: printf("audio\n"); break; + case CDS_DATA_1: printf("data mode 1\n"); break; + case CDS_DATA_2: printf("data mode 2\n"); break; + case CDS_XA_2_1: printf("XA mode 1\n"); break; + case CDS_XA_2_2: printf("XA mode 2\n"); break; + default: printf("unknown (failed?)\n"); + } +#endif + +#ifdef CDROMMULTISESSION + /* get multisession */ + printf("multisession: "); fflush(stdout); + ms.addr_format = CDROM_LBA; + if (ioctl(filehandle,CDROMMULTISESSION,&ms)) + printf("FAILED\n"); + else + printf("%d%s\n",ms.addr.lba,ms.xa_flag?" XA":""); +#endif + +#ifdef CDROMSUBCHNL + /* get audio status from subchnl */ + printf("audio status: "); fflush(stdout); + sub.cdsc_format = CDROM_MSF; + if (ioctl(filehandle,CDROMSUBCHNL,&sub)) + printf("FAILED\n"); + else { + switch (sub.cdsc_audiostatus) { + case CDROM_AUDIO_INVALID: printf("invalid\n"); break; + case CDROM_AUDIO_PLAY: printf("playing"); break; + case CDROM_AUDIO_PAUSED: printf("paused"); break; + case CDROM_AUDIO_COMPLETED: printf("completed\n"); break; + case CDROM_AUDIO_ERROR: printf("error\n"); break; + case CDROM_AUDIO_NO_STATUS: printf("no status\n"); break; + default: printf("Oops: unknown\n"); + } + if (sub.cdsc_audiostatus == CDROM_AUDIO_PLAY || + sub.cdsc_audiostatus == CDROM_AUDIO_PAUSED) { + printf(" at: %02d:%02d abs / %02d:%02d track %d\n", + sub.cdsc_absaddr.msf.minute, + sub.cdsc_absaddr.msf.second, + sub.cdsc_reladdr.msf.minute, + sub.cdsc_reladdr.msf.second, + sub.cdsc_trk); + } + } +#endif + printf(STRONG "try to find out what sort of CD this is\n" NORMAL); + + /* try to find out what sort of CD we have */ + if (0 == num_data) { + /* no data track, may be a "real" audio CD or hidden track CD */ + start_track = (int)toc[1]->cdte_addr.msf.frame + + (int)toc[1]->cdte_addr.msf.second*75 + + (int)toc[1]->cdte_addr.msf.minute*75*60 - 150; + /* CD-I/Ready says start_track <= 30*75 then CDDA */ + if (start_track > 100 /* 100 is just a guess */) { + fs = guess_filesystem(0); + if ((fs & FS_MASK) != FS_UNKNOWN) + fs |= HIDDEN_TRACK; + else { + fs &= ~FS_MASK; /* del filesystem info */ + printf("Oops: %i unused sectors at start, but hidden track check failed.\n",start_track); + } + } + } else { + /* we have data track(s) */ + for (j = 2, i = first_data; i <= toc_header[1]; i++) { + if (!(toc[i]->cdte_ctrl & CDROM_DATA_TRACK)) + break; + start_track = (i == 1) ? 0 : + (int)toc[i]->cdte_addr.msf.frame + + (int)toc[i]->cdte_addr.msf.second*75 + + (int)toc[i]->cdte_addr.msf.minute*75*60 + -150; + /* save the start of the data area */ + if (i == first_data) + data_start = start_track; + + /* skip tracks which belong to the current walked session */ + if (start_track < data_start + isofs_size) + continue; + + fs = guess_filesystem(start_track); + if (!(((fs & FS_MASK) == FS_ISO_9660 || + (fs & FS_MASK) == FS_ISO_HFS || + /* (fs & FS_MASK) == FS_ISO_9660_INTERACTIVE) && (fs & XA))) */ + (fs & FS_MASK) == FS_ISO_9660_INTERACTIVE))) + break; /* no method for non-iso9660 multisessions */ + + if (i > 1) { + /* track is beyond last session -> new session found */ + ms_offset = start_track; + printf("session #%d starts at track %2i, offset %6i, isofs size %6i\n", + j++,toc[i]->cdte_track,start_track,isofs_size); + printf("iso9660: %i MB size, label `%.32s'\n", + isofs_size/512,buffer+40); + fs |= MULTISESSION; + } + } + } + + switch(fs & FS_MASK) { + case FS_NO_DATA: + if (num_audio > 0) + printf("Audio CD, cddb disc ID is %08lx\n",cddb_discid()); + break; + case FS_ISO_9660: + printf("CD-ROM with iso9660 fs"); + if (fs & JOLIET) + printf(" and joliet extension level %d", joliet_level); + if (fs & ROCKRIDGE) + printf(" and rockridge extensions"); + printf("\n"); + break; + case FS_ISO_9660_INTERACTIVE: + printf("CD-ROM with CD-RTOS and iso9660 fs\n"); + break; + case FS_HIGH_SIERRA: + printf("CD-ROM with high sierra fs\n"); + break; + case FS_INTERACTIVE: + printf("CD-Interactive%s\n", num_audio > 0 ? "/Ready" : ""); + break; + case FS_HFS: + printf("CD-ROM with Macintosh HFS\n"); + break; + case FS_ISO_HFS: + printf("CD-ROM with both Macintosh HFS and iso9660 fs\n"); + break; + case FS_UFS: + printf("CD-ROM with Unix UFS\n"); + break; + case FS_EXT2: + printf("CD-ROM with Linux second extended filesystem\n"); + break; + case FS_3DO: + printf("CD-ROM with Panasonic 3DO filesystem\n"); + break; + case FS_UNKNOWN: + printf("CD-ROM with unknown filesystem\n"); + break; + } + switch(fs & FS_MASK) { + case FS_ISO_9660: + case FS_ISO_9660_INTERACTIVE: + case FS_ISO_HFS: + printf("iso9660: %i MB size, label `%.32s'\n", + isofs_size/512,buffer+40); + break; + } + need_lf = 0; + if (first_data == 1 && num_audio > 0) + need_lf += printf("mixed mode CD "); + if (fs & XA) + need_lf += printf("XA sectors "); + if (fs & MULTISESSION) + need_lf += printf("Multisession, offset = %i ",ms_offset); + if (fs & HIDDEN_TRACK) + need_lf += printf("Hidden Track "); + if (fs & PHOTO_CD) + need_lf += printf("%sPhoto CD ", num_audio > 0 ? " Portfolio " : ""); + if (fs & CDTV) + need_lf += printf("Commodore CDTV "); + if (first_data > 1) + need_lf += printf("CD-Plus/Extra "); + if (fs & BOOTABLE) + need_lf += printf("bootable CD "); + if (fs & VIDEOCDI && num_audio == 0) + need_lf += printf("Video CD "); + if (need_lf) puts(""); + + exit(0); +} |