mirror of
https://github.com/open-simh/simtools.git
synced 2026-04-27 12:28:44 +00:00
375 lines
11 KiB
C
375 lines
11 KiB
C
/* PHYUNIX.c V2.1 Physical I/O module for Unix */
|
|
|
|
/*
|
|
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 contibution of the original author.
|
|
*/
|
|
|
|
/*
|
|
* If the user mounts cd0 we open up /dev/cd0 for access.
|
|
*/
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* THE DEFINITION OF _FILE_OFFSET_BITS MUST APPEAR BEFORE ANY OTHER INCLUDES */
|
|
/* */
|
|
/* DO NOT MOVE THIS DEFINITION */
|
|
/* */
|
|
#ifndef _FILE_OFFSET_BITS /* */
|
|
#define _FILE_OFFSET_BITS 64 /* 64-bit off_t (glibc V2.2.x and later) */
|
|
#endif /* */
|
|
/* */
|
|
/******************************************************************************/
|
|
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <inttypes.h>
|
|
#include <limits.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/param.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#include "device.h"
|
|
#include "ods2.h"
|
|
#include "phyio.h"
|
|
#include "ssdef.h"
|
|
#include "phyvirt.h"
|
|
#include "compat.h"
|
|
|
|
#ifndef TRUE
|
|
#define TRUE ( 0 == 0 )
|
|
#endif
|
|
#ifndef FALSE
|
|
#define FALSE ( 0 != 0 )
|
|
#endif
|
|
|
|
#if defined(__digital__) && defined(__unix__)
|
|
#define DEV_PREFIX "/devices/rdisk/"
|
|
#else
|
|
#ifdef sun
|
|
#define DEV_PREFIX "/dev/dsk/"
|
|
#else
|
|
#define DEV_PREFIX "/dev/"
|
|
#endif
|
|
#endif
|
|
|
|
unsigned init_count = 0;
|
|
unsigned read_count = 0;
|
|
unsigned write_count = 0;
|
|
|
|
struct devdat {
|
|
char *name;
|
|
unsigned low;
|
|
unsigned high;
|
|
};
|
|
|
|
/*************************************************************** showdevs() */
|
|
|
|
static int devcmp( const void *d1, const void *d2 ) {
|
|
return strcmp( ((struct devdat *)d1)->name, ((struct devdat *)d2)->name );
|
|
}
|
|
|
|
static void showdevs( void ) {
|
|
DIR *dirp;
|
|
size_t i, cpl, n = 0, max = 0;
|
|
struct devdat (*list)[1] = NULL;
|
|
|
|
errno = 0;
|
|
if( (dirp = opendir( DEV_PREFIX )) != NULL ) {
|
|
do {
|
|
int nml;
|
|
size_t len;
|
|
unsigned unit;
|
|
char *fs;
|
|
struct dirent *dp;
|
|
struct devdat (*nl)[1];
|
|
struct stat stb;
|
|
|
|
errno = 0;
|
|
if( (dp = readdir(dirp)) == NULL )
|
|
break;
|
|
|
|
len = strlen( dp->d_name );
|
|
fs = malloc( sizeof( DEV_PREFIX ) + len );
|
|
if( fs == NULL )
|
|
break;
|
|
memcpy( fs, DEV_PREFIX, sizeof( DEV_PREFIX ) -1 );
|
|
memcpy( fs + sizeof( DEV_PREFIX ) -1, dp->d_name, len +1 );
|
|
|
|
if( stat( fs, &stb ) == -1 ) {
|
|
perror( fs );
|
|
free( fs );
|
|
continue;
|
|
}
|
|
if( !S_ISBLK( stb.st_mode ) )
|
|
continue;
|
|
|
|
memmove( fs, fs + sizeof( DEV_PREFIX ) -1, len +1 );
|
|
unit = ~0;
|
|
if( sscanf( fs, "%*[^0123456789]%n%u", &nml, &unit ) == 1 )
|
|
fs[nml] = '\0';
|
|
for( i = 0; i < n; i++ ) {
|
|
if( strcmp( (*list)[i].name, fs ) == 0 ) {
|
|
if( unit != ~0U ) {
|
|
if( unit > (*list)[i].high )
|
|
(*list)[i].high = unit;
|
|
if( unit < (*list)[i].low )
|
|
(*list)[i].low = unit;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if( i >= n ) {
|
|
nl = (struct devdat (*)[1])
|
|
realloc( list, (n+1) * sizeof( struct devdat ) );
|
|
if( nl == NULL )
|
|
break;
|
|
list = nl;
|
|
(*list)[n].name = fs;
|
|
(*list)[n].low = unit;
|
|
(*list)[n++].high = unit;
|
|
}
|
|
} while( TRUE );
|
|
(void) closedir(dirp);
|
|
}
|
|
if( errno != 0 ) {
|
|
printf( "%%ODS2-W-DIRERR, Error reading %s\n", DEV_PREFIX );
|
|
perror( " - " );
|
|
for( i = 0; i < n; i++ )
|
|
free( (*list)[i].name );
|
|
free( list );
|
|
return;
|
|
}
|
|
|
|
if( n == 0 ) {
|
|
printf( "%%ODS2-I-NODEV, No devices found\n" );
|
|
return;
|
|
}
|
|
|
|
qsort( list, n, sizeof( struct devdat ), &devcmp );
|
|
|
|
for( i = 0; i < n; i++ ) {
|
|
char buf[128];
|
|
int p;
|
|
p = snprintf( buf, sizeof(buf), "%s", (*list)[i].name );
|
|
if( (*list)[i].low != ~0U ) {
|
|
p += snprintf( buf+p, sizeof(buf)-p, "%u", (*list)[i].low );
|
|
if( (*list)[i].high != (*list)[i].low )
|
|
p += snprintf( buf+p, sizeof(buf)-p, "-%u", (*list)[i].high );
|
|
}
|
|
if( p > (int)max )
|
|
max = p;
|
|
}
|
|
cpl = 50 / (max + 1);
|
|
if( cpl == 0 )
|
|
cpl = 1;
|
|
|
|
for( i = 0; i < n; i++ ) {
|
|
int p;
|
|
if( (i % cpl) == 0 ) {
|
|
if( i ) putchar( '\n' );
|
|
putchar( ' ' );
|
|
}
|
|
p = printf( " %s", (*list)[i].name ) -1;
|
|
free( (*list)[i].name );
|
|
|
|
if( (*list)[i].low != ~0U ) {
|
|
p += printf( "%u", (*list)[i].low );
|
|
if( (*list)[i].high != (*list)[i].low )
|
|
p += printf( "-%u", (*list)[i].high );
|
|
}
|
|
for( ; p < (int)max; p++ )
|
|
putchar( ' ' );
|
|
}
|
|
printf ( "\n" );
|
|
free( list );
|
|
|
|
return;
|
|
}
|
|
|
|
/*************************************************************** phyio_show() */
|
|
|
|
void phyio_show( showtype_t type ) {
|
|
switch( type ) {
|
|
case SHOW_STATS:
|
|
printf( "PHYIO_SHOW Initializations: %d Reads: %d Writes: %d\n",
|
|
init_count, read_count, write_count );
|
|
return;
|
|
case SHOW_FILE64:
|
|
printf( "\nLarge ODS-2 image files (>2GB) are supported.\n" );
|
|
return;
|
|
case SHOW_DEVICES:
|
|
printf( " Physical devices\n" );
|
|
showdevs();
|
|
return;
|
|
default:
|
|
abort();
|
|
}
|
|
}
|
|
|
|
void phyio_help(FILE *fp ) {
|
|
fprintf( fp, " mount device\nThe device must be in %.*s.\n\n",
|
|
(int)(sizeof( DEV_PREFIX ) -2), DEV_PREFIX );
|
|
fprintf( fp, "For example, if you are using " DEV_PREFIX "%s\n", "cdrom0" );
|
|
fprintf( fp, " ODS2$> mount cdrom0\n" );
|
|
fprintf( fp, "For a list of devices, see SHOW DEVICES\n\n" );
|
|
return;
|
|
}
|
|
|
|
/*************************************************************** phyio_path() */
|
|
|
|
char *phyio_path( const char *filnam ) {
|
|
|
|
size_t n;
|
|
char *path, resolved_path[PATH_MAX+1];
|
|
|
|
if ( filnam == NULL || realpath( filnam, resolved_path ) == NULL ) {
|
|
return NULL;
|
|
}
|
|
n = strlen( resolved_path );
|
|
path = (char *) malloc( n + 1 );
|
|
if ( path != NULL ) {
|
|
memcpy( path, resolved_path, n + 1 );
|
|
}
|
|
return path;
|
|
}
|
|
|
|
/*************************************************************** phyio_init() */
|
|
|
|
unsigned phyio_init( struct DEV *dev ) {
|
|
|
|
size_t n;
|
|
int fd;
|
|
char *device;
|
|
const char *virtual;
|
|
struct stat statbuf;
|
|
|
|
init_count++;
|
|
|
|
dev->access &= ~MOU_VIRTUAL;
|
|
dev->handle = 0;
|
|
dev->sectors = 0;
|
|
|
|
virtual = virt_lookup( dev->devnam );
|
|
if ( virtual == NULL ) {
|
|
n = sizeof( DEV_PREFIX ) + strlen( dev->devnam );
|
|
device = (char *) malloc( n );
|
|
if ( device != NULL ) {
|
|
memcpy( device, DEV_PREFIX, sizeof( DEV_PREFIX ) -1 );
|
|
memcpy( device+sizeof( DEV_PREFIX ) -1, dev->devnam, n +1 - sizeof( DEV_PREFIX ) );
|
|
device[n - 2] = '\0'; /* Remove : from device name */
|
|
}
|
|
} else {
|
|
n = strlen( virtual );
|
|
device = (char *) malloc( n + 1 );
|
|
if ( device != NULL ) {
|
|
memcpy( device, virtual, n + 1 );
|
|
dev->access |= MOU_VIRTUAL;
|
|
}
|
|
}
|
|
if ( device == NULL ) {
|
|
return SS$_INSFMEM;
|
|
}
|
|
stat( device, &statbuf );
|
|
dev->sectors = ( statbuf.st_size + (off_t) 511 ) / (off_t) 512;
|
|
fd = open( device, ( dev->access & MOU_WRITE ) ? O_RDWR : O_RDONLY );
|
|
#ifdef DEBUG
|
|
printf( "%d = open( \"%s\", %s )\n", fd, device,
|
|
( dev->access & MOU_WRITE ) ? "O_RDWR" : "O_RDONLY" );
|
|
#endif
|
|
if ( fd < 0 && dev->access & MOU_WRITE ) {
|
|
dev->access &= ~MOU_WRITE;
|
|
fd = open( device, O_RDONLY );
|
|
#ifdef DEBUG
|
|
printf( "%d = open( \"%s\", O_RDONLY )\n", fd, device );
|
|
#endif
|
|
}
|
|
free( device );
|
|
if ( fd < 0 ) {
|
|
#ifdef DEBUG
|
|
perror( "open" );
|
|
#endif
|
|
return ( ( dev->access & MOU_VIRTUAL ) ?
|
|
SS$_NOSUCHFILE : SS$_NOSUCHDEV );
|
|
}
|
|
dev->handle = fd;
|
|
return SS$_NORMAL;
|
|
}
|
|
|
|
/*************************************************************** phyio_done() */
|
|
|
|
unsigned phyio_done( struct DEV *dev ) {
|
|
|
|
close( dev->handle );
|
|
dev->handle = 0;
|
|
if( dev->access & MOU_VIRTUAL )
|
|
virt_device( dev->devnam, NULL );
|
|
return SS$_NORMAL;
|
|
}
|
|
|
|
/*************************************************************** phyio_read() */
|
|
|
|
unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length,
|
|
char *buffer ) {
|
|
|
|
ssize_t res;
|
|
off_t pos;
|
|
|
|
#ifdef DEBUG
|
|
printf("Phyio read block: %d into %p (%d bytes)\n",
|
|
block, buffer, length );
|
|
#endif
|
|
|
|
read_count++;
|
|
pos = (off_t) block * (off_t) 512;
|
|
if ( ( pos = lseek( dev->handle, pos, SEEK_SET ) ) < 0 ) {
|
|
perror( "lseek " );
|
|
printf("lseek failed %" PRIuMAX "u\n",(uintmax_t)pos);
|
|
return SS$_PARITY;
|
|
}
|
|
if ( ( res = read( dev->handle, buffer, length ) ) != length ) {
|
|
perror( "read " );
|
|
printf("read failed %" PRIuMAX "u\n", (uintmax_t)res);
|
|
return SS$_PARITY;
|
|
}
|
|
return SS$_NORMAL;
|
|
}
|
|
|
|
/************************************************************** phyio_write() */
|
|
|
|
unsigned phyio_write( struct DEV *dev, unsigned block, unsigned length,
|
|
const char *buffer ) {
|
|
|
|
off_t pos;
|
|
ssize_t res;
|
|
|
|
#ifdef DEBUG
|
|
printf("Phyio write block: %d from %p (%d bytes)\n",
|
|
block, buffer, length );
|
|
#endif
|
|
|
|
write_count++;
|
|
pos = (off_t) block * (off_t) 512;
|
|
if ( ( pos = lseek( dev->handle, pos, SEEK_SET ) ) < 0 ) {
|
|
perror( "lseek " );
|
|
printf( "lseek failed %" PRIuMAX "u\n", (uintmax_t)pos );
|
|
return SS$_PARITY;
|
|
}
|
|
if ( ( res = write( dev->handle, buffer, length ) ) != length ) {
|
|
perror( "write " );
|
|
printf( "write failed %" PRIuMAX "u\n", (uintmax_t)res );
|
|
return SS$_PARITY;
|
|
}
|
|
return SS$_NORMAL;
|
|
}
|