mirror of
https://github.com/open-simh/simtools.git
synced 2026-01-25 03:36:35 +00:00
Show version includes the other configuration info, including READLINE and ASPI. Fix a memory leak in Unix show devices. Start using valgrind. Add VLD support for Windows. Fix memory leaks in main command processing. add command line arguments to history if USEing_READLINE Add atexit() and rundown support to dismount volumes at exit. Update makefiles for READLINE - some versions require you to link with termcap or ncurses as well. Fix memory leak in set default (including implicit set default on mount) Free WCCFILE on search NAM$M_SYNCHK as VMS does. Also release when returning RMS$_NMF. Add nam$l_rlf field to NAM Implement show devices for VMS. When reusing a WCB for large file, ensure that the file header pointer is valid. Add show cwd so it's easy to find out default for local files. Add set cwd Add spawn cmd so it's easy to inspect copied files. Handle condition codes properly. Finish sysmsg. Add standard macros to stsdef.h Deal with strerror on windows.
384 lines
11 KiB
C
384 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 ) ) {
|
|
free( fs );
|
|
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;
|
|
}
|
|
free( fs );
|
|
break;
|
|
}
|
|
}
|
|
if( i >= n ) {
|
|
nl = (struct devdat (*)[1])
|
|
realloc( list, (n+1) * sizeof( struct devdat ) );
|
|
if( nl == NULL ) {
|
|
free( fs );
|
|
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( "Large ODS-2 image files (>2GB) are %ssupported.\n",
|
|
(sizeof( off_t ) < 8)? "NOT ": "" );
|
|
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 ) {
|
|
if( res == 0 ) {
|
|
return SS$_ENDOFFILE;
|
|
}
|
|
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;
|
|
}
|