/* 10 November 2006. SMS. Make an image file from a CD-ROM. P1 = CD-ROM device name. P2 = Output file name. For accurate byte counts on DVDs, compile with large-file support: CC /DEFINE = _LARGEFILE=1 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Use if available. Otherwise declare IOSB here. */ #if !defined( __VAX) && (__CRTL_VER >= 70000000) #include #else /* !defined( __VAX) && (__CRTL_VER >= 70000000) */ typedef struct _iosb { unsigned short int iosb$w_status; /* Final I/O status. */ unsigned int iosb$l_bcnt; /* 32-bit byte count. */ unsigned int iosb$w_dev_depend_high; /* 16-bit dev depend. */ } IOSB; #endif /* !defined( __VAX) && (__CRTL_VER >= 70000000) */ /* Serious C complaint reduction. */ #define printf (void)printf /* CD-ROM block size and buffer size parameters. */ #define BLOCK_BYTES_HD 512 /* Disk block size. */ #define BLOCK_BYTES_CD (4* BLOCK_BYTES_HD) /* CD-ROM block size. */ /* MAX_READ_BYTES must be a power-of-two times BLOCK_BYTES_CD. It may be halved repeatedly near the end of the CD-ROM, and it must remain a multiple of BLOCK_BYTES_CD. */ #define MAX_READ_BYTES (32* BLOCK_BYTES_CD) /* Max CD-ROM read size. */ #define MIN_READ_BYTES BLOCK_BYTES_CD /* Min CD-ROM read size. */ /* sysmsg_text(). VMS system message look-up. */ char *sysmsg_text( unsigned int sts) { static char sysmsg[ 257]; unsigned short int sysmsg_len; $DESCRIPTOR( sysmsg_dsc, sysmsg); (void) sys$getmsg( sts, &sysmsg_len, &sysmsg_dsc, 0xF, 0); sysmsg[ (int)sysmsg_len] = '\0'; /* NUL-terminate the message. */ return sysmsg; } /* assign_dev(). Assign a device. */ unsigned int assign_dev( struct dsc$descriptor_s *name_dsc, unsigned short *chan) { int sts; sts = sys$assign( name_dsc, chan, 0, 0, 0); if ((sts & STS$M_SEVERITY) != STS$M_SUCCESS) { printf( " Error in assign of %s. sts = %%x%08x.\n", (*name_dsc).dsc$a_pointer, sts); printf( " %s.\n", sysmsg_text( sts)); } return sts; } /* Main. */ int main( int argc, char ** argv) { /* Miscellaneous storage. */ int sts; /* System service status. */ unsigned short int chan_in; /* CD-ROM device channel. */ struct _iosb iosb_in; /* I/O status block. */ unsigned int lbn; /* Logical block number. */ int req_bytes; /* Read request bytes. */ $DESCRIPTOR( name_in_dsc, ""); /* CD-ROM name descriptor. */ static char name_in_phy[ 65]; /* CD-ROM physical device */ $DESCRIPTOR( name_in_phy_dsc, /* name and descriptor. */ name_in_phy); int mounted; /* CD-ROM already mounted. */ char *name_out; /* Image file name. */ int fd_out; /* Image file UNIX fd. */ off_t size_io; /* Bytes read. */ off_t size_io_total; /* Total bytes read. */ time_t time_start; /* I/O start time (s). */ unsigned char buf[ MAX_READ_BYTES]; /* I/O buffer. */ /* Item list structures for GETDVI. */ static unsigned int dvi_buf; static int dvi_buf_len; typedef struct { short buf_len_avail; short itm_cod; unsigned int *buf; int *buf_len_used; int term; } dvi_itmlst_t; dvi_itmlst_t dvi_itmlst_mnt = { 4, DVI$_MNT, /* Mounted? */ &dvi_buf, &dvi_buf_len, 0 }; dvi_itmlst_t dvi_itmlst_for = { 4, DVI$_FOR, /* Mounted foreign? */ &dvi_buf, &dvi_buf_len, 0 }; /* Item list structures for MOUNT. */ typedef struct { short buf_len_avail; short itm_cod; void *buf; int *buf_len_used; } mnt_itm_t; int mnt_flags[2] = { MNT$M_FOREIGN| MNT$M_NOASSIST| MNT$M_NOWRITE, 0}; struct { mnt_itm_t name; /* */ mnt_itm_t flags; int term; } mnt_itmlst; /* Start of executable code. */ /* Check command-line argument count. */ if (argc != 3) { printf( " Usage: %s \n", argv[ 0]); } /* Set command-line argument storage. */ name_in_dsc.dsc$a_pointer = argv[ 1]; name_in_dsc.dsc$w_length = strlen( name_in_dsc.dsc$a_pointer); name_out = argv[ 2]; /* Allocate input device. */ sts = sys$alloc( &name_in_dsc, &name_in_phy_dsc.dsc$w_length, &name_in_phy_dsc, 0, 0); if ((sts & STS$M_SEVERITY) != STS$M_SUCCESS) { printf( " Error in alloc of %s. sts = %%x%08x.\n", name_in_dsc.dsc$a_pointer, sts); printf( " %s.\n", sysmsg_text( sts)); return sts; } /* NUL-terminate the physical device name. */ name_in_phy_dsc.dsc$a_pointer[ (int)name_in_phy_dsc.dsc$w_length] = '\0'; /* Open (assign) input device. */ sts = assign_dev( &name_in_phy_dsc, &chan_in); if ((sts & STS$M_SEVERITY) != STS$M_SUCCESS) { return sts; } /* Check status of input device. If mounted, must be mounted foreign. */ sts = sys$getdviw( 0, /* Event flag nr. */ chan_in, /* Channel. */ 0, /* Device name. */ &dvi_itmlst_mnt, /* Item list. */ 0, /* IOSB. */ 0, /* AST address. */ 0, /* AST parameter. */ 0); /* Null argument. */ if ((sts & STS$M_SEVERITY) != STS$M_SUCCESS) { printf( " Error in getdvi of %s (%s). sts = %%x%08x.\n", name_in_dsc.dsc$a_pointer, name_in_phy_dsc.dsc$a_pointer, sts); printf( " %s.\n", sysmsg_text( sts)); return sts; } mounted = (dvi_buf != 0); if (mounted) { sts = sys$getdviw( 0, /* Event flag nr. */ chan_in, /* Channel. */ 0, /* Device name. */ &dvi_itmlst_for, /* Item list. */ 0, /* IOSB. */ 0, /* AST address. */ 0, /* AST parameter. */ 0); /* Null argument. */ if ((sts & STS$M_SEVERITY) != STS$M_SUCCESS) { printf( " Error in getdvi of %s (%s). sts = %%x%08x.\n", name_in_dsc.dsc$a_pointer, name_in_phy_dsc.dsc$a_pointer, sts); printf( " %s.\n", sysmsg_text( sts)); return sts; } } if (mounted && (dvi_buf == 0)) { printf( " Device %s (%s) is mounted but not mounted foreign.\n", name_in_dsc.dsc$a_pointer, name_in_phy_dsc.dsc$a_pointer); return SS$_DEVNOTMOUNT; } if (! mounted) { /* Release the channel to allow mounting. */ sts = sys$dassgn( chan_in); /* Fill in MOUNT item list data. */ mnt_itmlst.name.buf_len_avail = name_in_phy_dsc.dsc$w_length; mnt_itmlst.name.itm_cod = MNT$_DEVNAM; mnt_itmlst.name.buf = name_in_phy_dsc.dsc$a_pointer; mnt_itmlst.flags.buf_len_avail = sizeof( mnt_flags); mnt_itmlst.flags.itm_cod = MNT$_FLAGS; mnt_itmlst.flags.buf = &mnt_flags; mnt_itmlst.term = 0; /* Mount the device. */ sts = sys$mount( &mnt_itmlst); if ((sts & STS$M_SEVERITY) != STS$M_SUCCESS) { printf( " Error in mount of %s (%s). sts = %%x%08x.\n", name_in_dsc.dsc$a_pointer, name_in_phy_dsc.dsc$a_pointer, sts); printf( " %s.\n", sysmsg_text( sts)); return sts; } printf( " %s (%s) mounted.\n", name_in_dsc.dsc$a_pointer, name_in_phy_dsc.dsc$a_pointer); /* Re-assign the device. */ sts = assign_dev( &name_in_phy_dsc, &chan_in); if ((sts & STS$M_SEVERITY) != STS$M_SUCCESS) { return sts; } } /* Start time-keeping here. (Include initial allocation of output file.) */ time_start = time( NULL); /* Open output file. */ /* fd_out = open( name_out, (O_RDWR| O_CREAT), 0777, */ fd_out = creat( name_out, /* File name. */ 0777, /* No mode/protection limits. */ "alq = 32768", /* Allocate initial 32K block (16MB) chunk. */ "deq = 32768", /* Extend in 32K block (16MB) chunks. */ "fop = mxv, sqo, tef", /* Create new, sequential-only, truncate. */ "rop = wbh", "mbf = 2", /* Write-behind. Multi-buffer (2). */ "mbc = 127", /* Maximum multi-block. */ "rfm = fix", /* "Binary" attributes: */ "mrs = 512", /* fixed-length records */ "bls = 512"); /* 512-bytes */ if (fd_out <= 0) { printf( " Error opening (creat) %s. Errno = %d.\n", name_out, errno); printf( " %s.\n", strerror( errno)); return errno; } /* Prepare for read and write operations. */ size_io_total = 0; lbn = 0; req_bytes = MAX_READ_BYTES; /* Loop until even the smallest read fails. */ while (req_bytes >= MIN_READ_BYTES) { /* Read a chunk. */ sts = sys$qiow( 0, /* Event flag nr. */ chan_in, /* Channel. */ IO$_READLBLK, /* Function code. */ &iosb_in, /* IOSB. */ 0, /* AST address. */ 0, /* AST parameter. */ buf, /* P1 = buffer address. */ req_bytes, /* P2 = byte count. */ lbn, /* P3 = logical block nr. */ 0, /* P4. */ 0, /* P5. */ 0); /* P6. */ size_io = iosb_in.iosb$l_bcnt; /* If initial status is success, use final status. */ if ((sts & STS$M_SEVERITY) == STS$M_SUCCESS) { sts = iosb_in.iosb$w_status; } if ((sts & STS$M_SEVERITY) != STS$M_SUCCESS) { if ((sts == SS$_ILLBLKNUM) || (sts == SS$_MEDOFL)) { /* Expected failure. Reduce read request size, and retry. */ req_bytes = req_bytes/ 2; } else { printf( " Error in read (QIOW) on %s (%s). sts = %%x%08x.\n", name_in_dsc.dsc$a_pointer, name_in_phy_dsc.dsc$a_pointer, sts); printf( " %s.\n", sysmsg_text( sts)); return sts; } } /* If read got data, write them out, and increment counters. */ if (size_io > 0) { size_io = write( fd_out, buf, size_io); if (size_io <= 0) { printf( " Error writing output file. Errno = %d.\n", errno); printf( " %s.\n", strerror( errno)); } size_io_total += size_io; lbn += size_io/ BLOCK_BYTES_HD; } } #if __USE_OFF64_T printf( " Total bytes read = %8lld.\n", size_io_total); #else /* __USE_OFF64_T */ printf( " Total bytes read = %8d.\n", size_io_total); #endif /* __USE_OFF64_T [else] */ printf( " Time (s) = %6d.\n", time( NULL)- time_start); /* Close files. */ sts = sys$dassgn( chan_in); /* If we mounted the CD-ROM device, then dismount it. */ if (! mounted) { sts = sys$dismou( &name_in_phy_dsc, 0); if ((sts & STS$M_SEVERITY) != STS$M_SUCCESS) { printf( " Error in dismou of %s. sts = %%x%08x.\n", name_in_phy_dsc.dsc$a_pointer, sts); printf( " %s.\n", sysmsg_text( sts)); } printf( " %s (%s) dismounted.\n", name_in_dsc.dsc$a_pointer, name_in_phy_dsc.dsc$a_pointer); sts = sys$dalloc( &name_in_phy_dsc, PSL$C_USER); if ((sts & STS$M_SEVERITY) != STS$M_SUCCESS) { printf( " Error in dalloc of %s. sts = %%x%08x.\n", name_in_phy_dsc.dsc$a_pointer, sts); printf( " %s.\n", sysmsg_text( sts)); } } sts = close( fd_out); return sts; }