mirror of
https://github.com/open-simh/simtools.git
synced 2026-02-05 16:05:57 +00:00
Too much to list all, but includes (in no particular order): - Cleanup for 64-bit builds, MSVC warnings. - Structured help - Help file compiler. - Supports volsets, writes/create work. - Support for I18n in messages, help. - Makefiles. - Initialize volume/volset - Command line editing/history Builds and works on Linux and Windows (VS). Not recently built or tested on other platforms, but not intentinonally broken.
475 lines
15 KiB
C
475 lines
15 KiB
C
/* PHYVMS.c Physical I/O module for VMS */
|
|
|
|
/*
|
|
* This is part of ODS2 written by Paul Nankervis,
|
|
* email address: Paulnank@au1.ibm.com
|
|
|
|
* ODS2 is distributed freely for all members of the
|
|
* VMS community to use. However all derived works
|
|
* must maintain comments in their source to acknowledge
|
|
* the contributions of the original author and
|
|
* subsequent contributors. This is free software; no
|
|
* warranty is offered, and while we believe it to be useful,
|
|
* you use it at your own risk.
|
|
*/
|
|
|
|
/* How come VMS is so much easier to do physical I/O on than
|
|
* those other ^%$@*! systems? I can't believe that they have
|
|
* different command sets for different device types, and can
|
|
* even have different command sets depending on what mode they
|
|
* are called from! Sigh. */
|
|
|
|
/* Modified by:
|
|
*
|
|
* 31-AUG-2001 01:04 Hunter Goatley <goathunter@goatley.com>
|
|
*
|
|
* Added checks to be sure device we're mounting is a
|
|
* disk and that it's already physically mounted at the
|
|
* DCL level,
|
|
*
|
|
* 7-JUN-2005 Larry Baker <baker@usgs.gov>
|
|
*
|
|
* If Mount/Virtual, use normal Unix open()/close()/read()/write().
|
|
* Negative handle -> Unix I/O; positive handle -> SYS$QIOW().
|
|
*/
|
|
|
|
#if !defined( DEBUG ) && defined( DEBUG_PHYVMS )
|
|
#define DEBUG DEBUG_PHYVMS
|
|
#else
|
|
#ifndef DEBUG
|
|
#define DEBUG 0
|
|
#endif
|
|
#endif
|
|
|
|
#include <dcdef.h>
|
|
#include <descrip.h>
|
|
#include <devdef.h>
|
|
#include <dvidef.h>
|
|
#include <iodef.h>
|
|
#include <lib$routines.h>
|
|
#include <mntdef.h>
|
|
#include <rms.h> /* struct FAB */
|
|
#include <ssdef.h>
|
|
#include <stsdef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#ifdef VAXC
|
|
#define LIB$M_FIL_NOWILD 1
|
|
#include <file.h>
|
|
#include <unixio.h>
|
|
#else
|
|
#ifdef VAX
|
|
#define LIB$M_FIL_NOWILD 1
|
|
#else
|
|
#include <libfildef.h> /* LIB$M_FIL_NOWILD */
|
|
#endif
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#ifdef __GNUC__
|
|
unsigned sys$assign();
|
|
unsigned sys$close();
|
|
unsigned sys$open();
|
|
unsigned sys$qiow();
|
|
unsigned sys$dassgn();
|
|
#else
|
|
#include <starlet.h>
|
|
#endif
|
|
|
|
#ifndef SS$_NOMOREDEV
|
|
#define SS$_NOMOREDEV 2648
|
|
#endif
|
|
|
|
#ifndef EFN$C_ENF
|
|
#define EFN$C_ENF 0 /* 128 in recent VMS */
|
|
#endif
|
|
|
|
#include "ods2.h"
|
|
#include "phyio.h"
|
|
#include "phyvirt.h"
|
|
|
|
static vmscond_t phyio_read( struct DEV *dev, uint32_t block,
|
|
uint32_t length, char *buffer );
|
|
static vmscond_t phyio_write( struct DEV *dev, uint32_t block,
|
|
uint32_t length, const char *buffer );
|
|
|
|
struct ITMLST {
|
|
unsigned short length;
|
|
unsigned short itmcod;
|
|
void *buffer;
|
|
unsigned short *retlen;
|
|
};
|
|
|
|
#define MSGID(sts) ((sts) & (STS$M_COND_ID|STS$M_SEVERITY))
|
|
|
|
static unsigned init_count = 0;
|
|
static unsigned read_count = 0;
|
|
static unsigned write_count = 0;
|
|
|
|
/*************************************************************** showdevs() */
|
|
static void showdevs( void ) {
|
|
vmscond_t status;
|
|
size_t max = 0;
|
|
int pass;
|
|
|
|
max = 0
|
|
for( pass = 0; pass < 2; pass++ ) {
|
|
unsigned long ctx[2] = { 0, 0 };
|
|
size_t col = 0;
|
|
unsigned short retlen, iosb[4];
|
|
char devnam[64+1],
|
|
dspnam[64+1];
|
|
struct dsc$descriptor_s retdsc = { sizeof( devnam ) -1,
|
|
DSC$K_DTYPE_T,
|
|
DSC$K_CLASS_S, devnam };
|
|
$DESCRIPTOR( searchdsc, "*" );
|
|
unsigned long devclass = DC$_DISK;
|
|
struct ITMLST scanlist[] = {
|
|
{ sizeof( devclass ), DC$_DISK, &devclass, NULL },
|
|
{ 0, 0, NULL, NULL }
|
|
};
|
|
struct ITMLST dvilist[] = {
|
|
{ sizeof( dspnam ) -1, DVI$_DISPLAY_DEVNAM, dspnam, &retlen },
|
|
{ 0, 0, NULL, NULL }
|
|
};
|
|
|
|
while( 1 ) {
|
|
char *name;
|
|
size_t len;
|
|
|
|
status = sys$device_scan( &retdsc, &retlen,
|
|
&searchdsc, scanlist, &ctx );
|
|
if( MSGID(status) != SS$_NORMAL )
|
|
break;
|
|
name = devnam;
|
|
name[retlen] = '\0';
|
|
len = retlen;
|
|
status = sys$getdviw( EFN$C_ENF, 0, &retdsc, dvilist, iosb,
|
|
NULL, 0, NULL );
|
|
if( MSGID(status) == SS$_NORMAL ) {
|
|
name = dspnam;
|
|
dspnam[retlen] = '\0';
|
|
len = retlen;
|
|
}
|
|
if( pass == 0 ) {
|
|
if( len > max )
|
|
max = len;
|
|
continue;
|
|
}
|
|
if( col + max > 75 ) {
|
|
putchar( '\n' );
|
|
col = 0;
|
|
}
|
|
col += 1+ max;
|
|
|
|
printf( " %-*s", (int)max, name );
|
|
}
|
|
}
|
|
switch( MSGID(status) ) {
|
|
case SS$_NOMOREDEV:
|
|
break;
|
|
case SS$_NOSUCHDEV:
|
|
printmsg( IO_NODEVS, MSG_TEXT );
|
|
break;
|
|
case SS$_NORMAL:
|
|
break;
|
|
default:
|
|
printmsg( IO_VMSDEVSCAN, 0 );
|
|
printmsg( status, MSG_CONTINUE, IO_VMSDEVSCAN );
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*************************************************************** phyio_show() */
|
|
|
|
void phyio_show( showtype_t type ) {
|
|
switch( type ) {
|
|
case SHOW_STATS:
|
|
printmsg( IO_STATS, MSG_TEXT, init_count, read_count, write_count );
|
|
return;
|
|
case SHOW_FILE64:
|
|
printmsg( (sizeof( off_t ) < 8)? IO_NOLARGEFILE: IO_LARGEFILE, MSG_TEXT );
|
|
return;
|
|
case SHOW_DEVICES:
|
|
printf( " Physical devices\n" );
|
|
showdevs();
|
|
return;
|
|
default:
|
|
abort();
|
|
}
|
|
}
|
|
|
|
/*************************************************************** phyio_help() */
|
|
|
|
void phyio_help(FILE *fp ) {
|
|
(void) helptopic( 0, "MOUNT VMS" );
|
|
|
|
return;
|
|
}
|
|
|
|
/*************************************************************** phyio_init() */
|
|
|
|
vmscond_t phyio_init( struct DEV *dev ) {
|
|
|
|
vmscond_t sts;
|
|
const char *virtual;
|
|
|
|
init_count++;
|
|
|
|
dev->handle = -1;
|
|
dev->devread = phyio_read;
|
|
dev->devwrite = phyio_write;
|
|
dev->sectors = 0;
|
|
|
|
if( dev->access & MOU_VIRTUAL ) {
|
|
int vmsfd;
|
|
struct FAB fab;
|
|
|
|
virtual = virt_lookup( dev->devnam );
|
|
if ( virtual == NULL ) {
|
|
return SS$_NOSUCHDEV;
|
|
}
|
|
#define opnopts "ctx=stm", "rfm=udf", "shr=get,put"
|
|
vmsfd = open( virtual,
|
|
((dev->access & MOU_WRITE )? O_RDWR : O_RDONLY) |
|
|
((dev->access & (MOU_VIRTUAL|PHY_CREATE)) == (MOU_VIRTUAL|PHY_CREATE)?
|
|
O_CREAT | O_EXCL : 0),
|
|
0666, opnopts );
|
|
|
|
if ( vmsfd < 0 && (dev->access & (MOU_WRITE|PHY_CREATE)) == MOU_WRITE ) {
|
|
dev->access &= ~MOU_WRITE;
|
|
vmsfd = open( virtual, O_RDONLY, 0444, opnopts );
|
|
}
|
|
if ( vmsfd < 0 ) {
|
|
int err;
|
|
|
|
switch( errno ) {
|
|
case EEXIST:
|
|
printmsg( IO_EXISTS, 0, virtual );
|
|
return SS$_DUPFILENAME | STS$M_INHIB_MSG;
|
|
default:
|
|
err = errno;
|
|
printmsg( IO_OPENDEV, 0, virtual );
|
|
return printmsg( ODS2_OSERROR, MSG_CONTINUE, IO_OPENDEV,
|
|
strerror( err ) );
|
|
}
|
|
}
|
|
|
|
dev->handle = vmsfd;
|
|
|
|
fab = cc$rms_fab; /* Make this a real FAB (bid and bln) */
|
|
fab.fab$l_fna = (char *) virtual;
|
|
fab.fab$b_fns = strlen( virtual );
|
|
if( $SUCCESSFUL(sts = sys$open( &fab )) {/* Lookup file, get file size */
|
|
dev->sectors = fab.fab$l_alq;
|
|
sys$close( &fab );
|
|
if ( sizeof( off_t ) < 8 && dev->sectors > 0x3FFFFF ) {
|
|
close( vmsfd );
|
|
dev->handle = -1;
|
|
return printmsg( IO_OFFSET_TOO_BIG, 0 ); /* Need 64-bit off_t */
|
|
}
|
|
}
|
|
} else { /* Physical */
|
|
struct dsc$descriptor devdsc;
|
|
unsigned long devclass, cylinders, tracks, sectors;
|
|
char devname[65];
|
|
unsigned long devchar;
|
|
unsigned short iosb[4];
|
|
struct ITMLST dvi_itmlst[7] = {
|
|
{ sizeof( devclass ), DVI$_DEVCLASS, &devclass, NULL },
|
|
{ sizeof( devname ), DVI$_ALLDEVNAM, &devname, NULL },
|
|
{ sizeof( devchar ), DVI$_DEVCHAR, &devchar, NULL },
|
|
{ sizeof( cylinders ), DVI$_CYLINDERS, &cylinders, NULL },
|
|
{ sizeof( tracks ), DVI$_TRACKS, &tracks, NULL },
|
|
{ sizeof( sectors ), DVI$_SECTORS, §ors, NULL },
|
|
{ 0, 0, 0, 0 }
|
|
};
|
|
|
|
/* Get some device information: device name, class, and mount status */
|
|
memset( devname, 0, sizeof( devname ) );
|
|
devdsc.dsc$w_length = strlen( dev->devnam );
|
|
devdsc.dsc$a_pointer = dev->devnam;
|
|
if( $FAILS(sts = sys$getdviw( EFN$C_ENF, 0, &devdsc, &dvi_itmlst,
|
|
iosb, 0, 0, 0 )) ) {
|
|
return sts;
|
|
}
|
|
if( devclass != DC$_DISK ) { /* If not a disk, return an error */
|
|
return SS$_IVDEVNAM;
|
|
}
|
|
dev->sectors = cylinders * tracks * sectors;
|
|
if( !(devchar & DEV$M_MNT) ) {
|
|
#if 1
|
|
/*
|
|
* This code will mount the disk if it's not already mounted.
|
|
* If you enable it, the "mount" command will mount the disk, but
|
|
* it'll stay mounted by the process running ODS2 if ODS2 exits abnormally.
|
|
*/
|
|
unsigned long mntflags[2];
|
|
struct ITMLST mnt_itmlst[3] = {
|
|
{ 0, MNT$_DEVNAM, &devname, NULL },
|
|
{ sizeof( mntflags ), MNT$_FLAGS, &mntflags, NULL },
|
|
{ 0, 0, 0, 0 }
|
|
};
|
|
mnt_itmlst[0].length = strlen( devname );
|
|
mntflags[0] = MNT$M_FOREIGN | MNT$M_NOASSIST | MNT$M_NOMNTVER;
|
|
if( !(dev->access & MOU_WRITE) ) {
|
|
mntflags[0] |= MNT$M_NOWRITE;
|
|
}
|
|
mntflags[1] = 0;
|
|
sts = sys$mount( &mnt_itmlst );
|
|
if( $FAILED(sts) && (dev->access & MOU_WRITE) ) {
|
|
dev->access &= ~MOU_WRITE;
|
|
mntflags[0] |= MNT$M_NOWRITE;
|
|
sts = sys$mount( &mnt_itmlst );
|
|
}
|
|
if( $SUCCESSFUL(sts) ) {
|
|
dev->access |= OS_MOUNTED;
|
|
printmsg( IO_VMSMOUNT, 0, devname );
|
|
} else {
|
|
printmsg( IO_VMSNOMOUNT, 0, devname );
|
|
}
|
|
#else
|
|
sts = SS$_DEVNOTMOUNT;
|
|
#endif
|
|
}
|
|
if( $SUCCESSFUL(sts) ) {
|
|
sts = sys$assign( &devdsc, &dev->handle, 0, 0, 0, 0 );
|
|
}
|
|
}
|
|
|
|
return sts;
|
|
}
|
|
|
|
/*************************************************************** phyio_done() */
|
|
|
|
vmscond_t phyio_done( struct DEV *dev ) {
|
|
vmscond_t status;
|
|
|
|
status = SS$_NORMAL;
|
|
|
|
if ( dev->access & MOU_VIRTUAL ) {
|
|
close( dev->handle );
|
|
virt_device( dev->devnam, NULL );
|
|
} else {
|
|
#if 1
|
|
if( dev->access & OS_MOUNTED ) {
|
|
struct dsc$descriptor devdsc;
|
|
|
|
devdsc.dsc$b_dtype = DSC$K_DTYPE_T;
|
|
devdsc.dsc$b_class = DSC$K_CLASS_S;
|
|
devdsc.dsc$w_length = strlen( dev->devnam );
|
|
devdsc.dsc$a_pointer = dev->devnam;
|
|
|
|
if( $SUCCESSFUL(status = sys$dismou( &devdsc, 0 )) ) {
|
|
printmsg( IO_VMSDMT, 0, dev->devnam );
|
|
} else {
|
|
printmsg( IO_VMSNODMT, 0, dev->devnam );
|
|
}
|
|
|
|
dev->access &= ~OS_MOUNTED;
|
|
}
|
|
#endif
|
|
|
|
sys$dassgn( dev->handle );
|
|
}
|
|
dev->handle = 0;
|
|
|
|
return status;
|
|
}
|
|
|
|
/*************************************************************** phyio_read() */
|
|
|
|
static vmscond_t phyio_read( struct DEV *dev, uint32_t block, uint32_t length,
|
|
char *buffer ) {
|
|
vmscond_t sts;
|
|
|
|
#if DEBUG
|
|
printf("Phyio read block: %d into %x (%d bytes)\n",block,buffer,length);
|
|
#endif
|
|
read_count++;
|
|
if( dev->access & MOU_VIRTUAL ) {
|
|
int res;
|
|
if( (res = lseek( dev->handle, block * 512, SEEK_SET )) < 0 ) {
|
|
int err;
|
|
|
|
err = errno;
|
|
printmsg( IO_SEEKERR, block );
|
|
sts = printmsg( ODS2_OSERROR, MSG_CONTINUE,
|
|
IO_SEEKERR, strerror(err) );
|
|
return sts;
|
|
}
|
|
if( (res = read( dev->handle, buffer, length )) != length ) {
|
|
int err;
|
|
|
|
if( res == 0 ) {
|
|
return SS$_ENDOFFILE;
|
|
}
|
|
err = errno;
|
|
printmsg( IO_READERR, 0, block );
|
|
if( res == (off_t)-1 ) {
|
|
sts = printmsg( ODS2_OSERROR, MSG_CONTINUE,
|
|
IO_READERR, strerror(err) );
|
|
} else {
|
|
sts = printmsg( IO_READLEN, MSG_CONTINUE, IO_READERR,
|
|
block, (uint32_t)res, length );
|
|
}
|
|
return sts;
|
|
}
|
|
return SS$_NORMAL;
|
|
} else {
|
|
unsigned short int iosb[4];
|
|
|
|
return sys$qiow( EFN$C_ENF, dev->handle, IO$_READLBLK, iosb, 0, 0,
|
|
buffer, length, block, 0, 0, 0 );
|
|
}
|
|
}
|
|
|
|
/************************************************************** phyio_write() */
|
|
|
|
static vmscond_t phyio_write( struct DEV *dev, uint32_t block, uint32_t length,
|
|
const char *buffer ) {
|
|
|
|
vmscond_t sts;
|
|
|
|
#if DEBUG
|
|
printf("Phyio write block: %d from %x (%d bytes)\n",block,buffer,length);
|
|
#endif
|
|
write_count++;
|
|
if( dev->access & MOU_VIRTUAL ) {
|
|
int res;
|
|
if( (res = lseek( dev->handle, block * 512, 0 )) < 0 ) {
|
|
int err;
|
|
|
|
err = errno;
|
|
printmsg( IO_SEEKERR, block );
|
|
sts = printmsg( ODS2_OSERROR, MSG_CONTINUE,
|
|
IO_SEEKERR, strerror(err) );
|
|
return sts;
|
|
}
|
|
if( (res = write( dev->handle, buffer, length )) != length ) {
|
|
int err;
|
|
|
|
err = errno;
|
|
printmsg( IO_WRITEERR, 0, block );
|
|
if( res == (off_t)-1 ) {
|
|
sts = printmsg( ODS2_OSERROR, MSG_CONTINUE,
|
|
IO_WRITEERR, strerror(err) );
|
|
} else {
|
|
sts = printmsg( IO_WRITELEN, MSG_CONTINUE, IO_WRITEERR,
|
|
block, (uint32_t)res, length );
|
|
}
|
|
return sts;
|
|
}
|
|
return SS$_NORMAL;
|
|
} else {
|
|
unsigned short int iosb[4];
|
|
|
|
return sys$qiow( EFN$C_ENF, dev->handle, IO$_WRITELBLK, iosb, 0, 0,
|
|
buffer, length, block, 0, 0, 0 );
|
|
}
|
|
}
|