diff --git a/extracters/ods2/.valgrindrc b/extracters/ods2/.valgrindrc new file mode 100644 index 0000000..334700e --- /dev/null +++ b/extracters/ods2/.valgrindrc @@ -0,0 +1,3 @@ +--memcheck:leak-check=yes +--suppressions=valgrind_suppressions_readline +--suppressions=valgrind_suppressions_ods2 diff --git a/extracters/ods2/ODS2.exe b/extracters/ods2/ODS2.exe index 9585a51..c697cfc 100644 Binary files a/extracters/ods2/ODS2.exe and b/extracters/ods2/ODS2.exe differ diff --git a/extracters/ods2/ODS2.vcxproj b/extracters/ods2/ODS2.vcxproj index 090c879..9d826bb 100644 --- a/extracters/ods2/ODS2.vcxproj +++ b/extracters/ods2/ODS2.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -12,15 +12,18 @@ Win32Proj + {BCCEAED2-1732-D796-1F70-040DE5DA42AD} Application true + v140 Application false + v140 @@ -43,10 +46,10 @@ - DEBUG_BUILD;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + HOME_SKIP=1 ;HOME_LOG;USE_VLD;DEBUG_BUILD;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) MultiThreadedDebugDLL Level3 - ProgramDatabase + EditAndContinue Disabled @@ -98,6 +101,7 @@ copy $(OutDir)$(TargetName)$(TargetExt) $(SolutionDir)$(TargetName)$(TargetExt) $(SolutionDir)$(TargetName)$(TargetExt) Copying $(TargetName)$(TargetExt) + $(OutDir)$(TargetName)$(TargetExt) diff --git a/extracters/ods2/access.c b/extracters/ods2/access.c index 375d2ec..7491681 100644 --- a/extracters/ods2/access.c +++ b/extracters/ods2/access.c @@ -51,6 +51,15 @@ struct WCBKEY { struct WCB *prevwcb; }; +#if 0 +static unsigned int delta_from_name( const char *diskname ); +#endif +static unsigned int delta_from_index( size_t index ); +static unsigned int compute_delta( unsigned long sectorsize, + unsigned long sectors, + unsigned long tracks, + unsigned long cylinders ); + unsigned deallocfile(struct FCB *fcb); /* Update.c */ #define DEBUGx @@ -287,6 +296,7 @@ static void *wcb_create( unsigned hashval, void *keyval, unsigned *retsts ) { curvbn = wcbkey->prevwcb->hd_basevbn; wcb->hd_seg_num = wcbkey->prevwcb->hd_seg_num; memcpy(&wcb->hd_fid,&wcbkey->prevwcb->hd_fid,sizeof(struct fiddef)); + head = wcbkey->fcb->head; } while (TRUE) { register unsigned short *mp; @@ -825,15 +835,28 @@ unsigned dismount(struct VCB * vcb) /******************************************************************** mount() */ #ifdef DEBUG -#define HOME_LIMIT 5 +#ifndef HOME_SKIP +#define HOME_SKIP 1 +#endif +#ifndef HOME_LIMIT +#define HOME_LIMIT 3 +#endif #else -#define HOME_LIMIT 100 +#ifndef HOME_SKIP +#define HOME_SKIP 0 +#endif +#ifndef HOME_LIMIT +#define HOME_LIMIT 1000 +#endif #endif /* mount() make disk volume available for processing... */ -unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[], - struct VCB **retvcb) { +unsigned mount( unsigned flags, + unsigned devices, + char *devnam[], + char *label[], + struct VCB **retvcb ) { register unsigned device,sts = 0; struct VCB *vcb; struct VCBDEV *vcbdev; @@ -842,13 +865,21 @@ unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[], #ifdef DEBUG if (sizeof(struct HOME) != 512 || sizeof(struct HEAD) != 512) return SS$_NOTINSTALL; #endif - vcb = (struct VCB *) calloc(1, sizeof(struct VCB) + (devices - 1) * sizeof(struct VCBDEV)); - if (vcb == NULL) return SS$_INSFMEM; + if( retvcb ) + *retvcb = NULL; + + vcb = (struct VCB *) calloc( 1, sizeof(struct VCB) + + ((devices - 1) * sizeof(struct VCBDEV)) ); + if( vcb == NULL ) + return SS$_INSFMEM; + vcb->status = 0; - if (flags & MOU_WRITE) vcb->status |= VCB_WRITE; + if( flags & MOU_WRITE ) + vcb->status |= VCB_WRITE; vcb->fcb = NULL; vcb->dircache = NULL; vcb->devices = 0; + vcbdev = vcb->vcbdev; for( device = 0; device < devices; device++, vcbdev++ ) { char *dname; @@ -857,9 +888,12 @@ unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[], sts = SS$_NOSUCHVOL; vcbdev->dev = NULL; if (strlen(dname)) { /* Really want to allow skipping volumes? */ - unsigned int hba; + unsigned int hba, delta, homtry; - if( label[device] != NULL && strlen(label[device]) > sizeof( volsetSYS[0].vsr$t_label ) ) { + if( label[device] != NULL && strlen(label[device]) > + sizeof( volsetSYS[0].vsr$t_label ) ) { + printf( "%%ODS2-E-BADPARAM, Label %s is too long\n", + label[device] ); sts = SS$_BADPARAM; break; } @@ -876,35 +910,44 @@ unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[], break; } } + vcb->devices++; sts = device_lookup( strlen( dname ), dname, TRUE, &vcbdev->dev ); - if ( !( sts & STS$M_SUCCESS ) ) break; + if( !(sts & STS$M_SUCCESS) ) + break; vcbdev->dev->access = flags; /* Requested mount options */ /* (e.g., /Write) */ sts = phyio_init( vcbdev->dev ); - if ( !( sts & STS$M_SUCCESS ) ) break; - vcb->devices++; + if( !(sts & STS$M_SUCCESS) ) + break; if (vcbdev->dev->vcb != NULL) { sts = SS$_DEVMOUNT; break; } - for (hba = 1; hba <= HOME_LIMIT; hba++) { + delta = delta_from_index( (vcbdev->dev->access & MOU_DEVTYPE) >> MOU_V_DEVTYPE ); + + for( hba = 1, homtry = 0; homtry < HOME_LIMIT; homtry++, hba += delta ) { struct HOME *hom; +#if HOME_SKIP > 100 + if( homtry < HOME_SKIP ) + continue; +#endif sts = phyio_read( vcbdev->dev, hba, sizeof( struct HOME ), (char *) &vcbdev->home ); if (!(sts & STS$M_SUCCESS)) break; hom = &vcbdev->home; -#ifdef DEBUG - printf( "--->mount(): LBA=%u, HM2$L_HOMELBN=%u, " +#if defined( DEBUG ) || defined( HOME_LOG ) + printf( "--->mount(%u): LBA=%u, HM2$L_HOMELBN=%u, " + "HM2$L_ALHOMELBN=%u, " "HM2$T_FORMAT=\"%12.12s\", memcmp()=%u\n", - hba, VMSLONG( hom->hm2$l_homelbn ), + homtry+1,hba, VMSLONG( hom->hm2$l_homelbn ), + VMSLONG( hom->hm2$l_alhomelbn ), hom->hm2$t_format, memcmp( hom->hm2$t_format, "DECFILE11B ", 12 ) ); #endif - if( (hba == VMSLONG(hom->hm2$l_homelbn) || - hba == VMSLONG(hom->hm2$l_alhomelbn)) && + if( (hba == VMSLONG(hom->hm2$l_homelbn)) && (VMSLONG(hom->hm2$l_alhomelbn) != 0) && (VMSLONG(hom->hm2$l_altidxlbn) != 0) && (VMSWORD(hom->hm2$w_homevbn) != 0) && @@ -919,7 +962,7 @@ unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[], (memcmp(hom->hm2$t_format,"DECFILE11B ",12) == 0) ) { break; } -#ifdef DEBUG +#if defined( DEBUG ) || defined( HOME_LOG ) printf( "--->mount(): Home block validation failure\n" ); printf( "(VMSLONG(hom->hm2$l_alhomelbn) != 0) %u\n", (VMSLONG(hom->hm2$l_alhomelbn) != 0) ); printf( "(VMSLONG(hom->hm2$l_altidxlbn) != 0) %u\n", (VMSLONG(hom->hm2$l_altidxlbn) != 0) ); @@ -1102,7 +1145,11 @@ unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[], if( !(sts & 1) ) { vcbdev = vcb->vcbdev; for( device = 0; device < devices; device++, vcbdev++ ) { - if (vcbdev->dev == NULL) continue; + if (vcbdev->dev == NULL) { + if( flags & MOU_VIRTUAL ) + virt_device( devnam[device], NULL ); + continue; + } if( vcb->status & VCB_WRITE && vcbdev->mapfcb != NULL ) { /* sts = */ @@ -1127,6 +1174,11 @@ unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[], } else { /* *** DECREF *** */ vcbdev = vcb->vcbdev; for( device = 0; device < vcb->devices; device++, vcbdev++ ) { + if (vcbdev->dev == NULL) { + if( flags & MOU_VIRTUAL ) + virt_device( devnam[device], NULL ); + continue; + } phyio_done( vcbdev->dev ); } free(vcb); @@ -1314,3 +1366,198 @@ void show_volumes( void ) { return; } + +/*************************************************************** acccess_rundown() */ +void access_rundown( void ) { + struct VCB *vcb, *next; + unsigned sts; + + for( vcb = vcb_list; vcb != NULL; vcb = next ) { + next = vcb->next; + + sts = dismount( vcb ); + if( !(sts & STS$M_SUCCESS) ) { + printf( "Dismount failed in rundown: %s", getmsg(sts, MSG_TEXT) ); + } + } +} + +/*************************************************************** compute_delta() */ +/* + * The search delta is computed from the + * volume geometry, expressed in sectors, tracks (surfaces), and + * cylinders, according to the following rules, to handle the cases where + * one or two dimensions of the volume have a size of 1. + * + * Geometry: Delta + * + * s x 1 x 1: 1 Rule 1 + * 1 x t x 1: 1 Rule 2 + * 1 x 1 x c: 1 Rule 3 + * + * s x t x 1: s+1 Rule 4 + * s x 1 x c: s+1 Rule 5 + * 1 x t x c: t+1 Rule 6 + * + * s x t x c: (t+1)*s+1 Rule 7 + */ + + +#define DISK( name, sectors, tracks, cylinders ) \ + {#name, 512 ## ul, sectors ## ul, tracks ## ul, cylinders ## ul}, +#define DISKS( name, sectorsize, sectors, tracks, cylinders ) \ + {#name, sectorsize ## ul, sectors ## ul, tracks ## ul, cylinders ## ul}, +struct disktype disktype[] = { + DISK(UNKNOWN, 1, 1, 1) /* First = short sequence delta = 1 */ + DISK(RK05, 12, 2, 203) + DISK(RK06, 22, 3, 411) + DISK(RK07, 22, 3, 815) + DISK(RK11, 12, 2, 203) + + DISK(RL01, 40, 2, 256) + DISK(RL02, 40, 2, 512) + + DISK(RM02, 32, 5, 823) + DISK(RM03, 32, 5, 823) + DISK(RP04, 22, 19, 411) + DISK(RP05, 22, 19, 411) + DISK(RM80, 31, 14, 559) + DISK(RP06, 22, 19, 815) + DISK(RM05, 32, 19, 823) + DISK(RP07, 50, 32, 630) + +#if 0 /* Not useful now as RSX20-F used ODS-1 */ + DISKS(RM02-T, 576, 30, 5, 823) + DISKS(RM03-T, 576, 30, 5, 823) + DISKS(RP04-T, 576, 20, 19, 411) + DISKS(RP05-T, 576, 20, 19, 411) + DISKS(RM80-T, 576, 30, 14, 559) + DISKS(RP06-T, 576, 20, 19, 815) + DISKS(RM05-T, 576, 30, 19, 823) + DISKS(RP07-T, 576, 43, 32, 630) +#endif + + DISK(RX50, 10, 1, 80) + DISK(RX33, 15, 2, 80) + +#if 0 + DISK(RD50, 99, 99, 9999) +#endif + DISK(RD51, 18, 4, 306) + DISK(RD31, 17, 4, 615) + DISK(RD52, 17, 8, 512) + DISK(RD53, 17, 7, 1024) + DISK(RD54, 17, 15, 1225) + + DISK(RA72, 51, 20, 1921) + +#if 0 + DISK(RA80, 99, 99, 9999) + +#endif + DISK(RA81, 51, 14, 1258) + DISK(RA82, 57, 15, 1435) + + DISK(RA90, 69, 13, 2649) + DISK(RA92, 73, 13, 3099) + + DISK(RRD40,128, 1, 10400) + DISK(RRD50,128, 1, 10400) + DISKS(RX01, 128, 26, 1, 77) + DISKS(RX02, 256, 26, 1, 77) + +#if 0 + DISK(RX23-SD, 99, 99, 9999) + DISK(RX23-DD, 99, 99, 9999) + + DISK(RX33-SD, 10, 1, 80) + DISK(RX33-DD, 99, 99, 9999) +#endif + + DISK(RX50, 10, 1, 80) +#if 0 + DISK(RC25, 99, 99, 9999 ) + + DISK(RF30, 99, 99, 9999 ) + DISK(RF31, 99, 99, 9999 ) + DISK(RF35, 99, 99, 9999 ) + DISK(RF36, 99, 99, 9999 ) + DISK(RF71, 99, 99, 9999 ) + DISK(RF72, 99, 99, 9999 ) + DISK(RF73, 99, 99, 9999 ) + DISK(RF74, 99, 99, 9999 ) + + DISK(RZ22, 99, 99, 9999 ) + DISK(RZ23, 99, 99, 9999 ) + DISK(RZ24, 99, 99, 9999 ) + DISK(RZ25, 99, 99, 9999 ) + DISK(RZ26, 99, 99, 9999 ) + DISK(RZ27, 99, 99, 9999 ) + DISK(RZ28, 99, 99, 9999 ) + DISK(RZ29, 99, 99, 9999 ) + DISK(RZ31, 99, 99, 9999 ) + DISK(RZ33, 99, 99, 9999 ) + DISK(RZ35, 99, 99, 9999 ) + DISK(RZ55, 99, 99, 9999 ) + DISK(RZ56, 99, 99, 9999 ) + DISK(RZ57, 99, 99, 9999 ) + DISK(RZ58, 99, 99, 9999 ) + DISK(RZ59, 99, 99, 9999 ) + + DISK(RZ72, 99, 99, 9999 ) + DISK(RZ73, 99, 99, 9999 ) + DISK(RZ74, 99, 99, 9999 ) +#endif + + { NULL, 0, 0, 0, 0 } +}; + + +static unsigned int compute_delta( unsigned long sectorsize, + unsigned long sectors, + unsigned long tracks, + unsigned long cylinders ) { + + if( sectorsize < 512 ) + sectors = (sectorsize * sectors) / 512; + + if( sectors > 1 && tracks > 1 && cylinders > 1 ) /* Rule 7 */ + return (tracks + 1) * sectors +1; + + if( (sectors > 1 && tracks > 1 && cylinders == 1 ) || /* Rule 4 */ + (sectors > 1 && tracks == 1 && cylinders > 1 ) ) /* Rule 5 */ + return sectors + 1; + + if( sectors == 1 && tracks > 1 && cylinders > 1 ) /* Rule 6 */ + return tracks + 1; + + return 1; /* Rules 1-3 */ +} + +#if 0 +static unsigned int delta_from_name( const char *diskname ) { + struct disktype *dp; + + for( dp = disktype; dp->name != NULL; dp++ ) { + if( !strcmp( dp->name, diskname ) ) + return compute_delta( dp->sectorsize, dp->sectors, dp->tracks, dp->cylinders ); + } + + return ~0u; +} +#endif +static unsigned int delta_from_index( size_t index ) { + struct disktype *dp; + unsigned int delta; + + if( index >= sizeof(disktype)/sizeof(disktype[0]) ) + abort(); + dp = disktype + index; + delta = compute_delta( dp->sectorsize, dp->sectors, dp->tracks, dp->cylinders ); + +#if defined( DEBUG ) || HOME_SKIP > 0 + printf( "HOM search index for %s is %u\n", dp->name, delta ); +#endif + + return delta; +} diff --git a/extracters/ods2/access.h b/extracters/ods2/access.h index 5aab745..2ef9f46 100644 --- a/extracters/ods2/access.h +++ b/extracters/ods2/access.h @@ -256,6 +256,13 @@ struct VCB { extern struct VCB *vcb_list; void show_volumes( void ); +struct disktype { + const char *name; + unsigned long sectorsize, sectors, tracks, cylinders; +}; + +extern struct disktype disktype[]; + /* RVN_TO_DEV( vcb, rvn ) - returns device from relative volume number */ /* returns NULL if RVN illegal or device not mounted */ @@ -289,4 +296,6 @@ unsigned update_create(struct VCB *vcb,struct fiddef *did,char *filename, unsigned update_extend(struct FCB *fcb,unsigned blocks,unsigned contig); vmsword checksum( vmsword *block ); +void access_rundown( void ); + #endif /* # ifndef _ACCESS_H */ diff --git a/extracters/ods2/compat.c b/extracters/ods2/compat.c index 7282b49..e4bd3ed 100644 --- a/extracters/ods2/compat.c +++ b/extracters/ods2/compat.c @@ -5,7 +5,7 @@ * * Microsoft deprecates sprintf, but doesn't supply standard * replacement until very recent IDEs. - * Microsoft doesn't like fopen. + * Microsoft doesn't like fopen, or strerror, or getcwd. * One needs to use a M$ call to translate system errors. * * Finding out about drive letter assignments is unique to windows. @@ -18,12 +18,14 @@ #ifdef _WIN32 #include +#include #endif #if defined(_MSC_VER) && _MSC_VER < 1900 -int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) -{ +/******************************************************************* c99_vsnprintf() */ + +int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) { int count = -1; if (size != 0) @@ -34,8 +36,9 @@ int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) return count; } -int c99_snprintf(char *outBuf, size_t size, const char *format, ...) -{ +/******************************************************************* c99_snprintf() */ + +int c99_snprintf(char *outBuf, size_t size, const char *format, ...) { int count; va_list ap; @@ -49,6 +52,8 @@ int c99_snprintf(char *outBuf, size_t size, const char *format, ...) #ifdef _MSC_VER +/******************************************************************* openf() */ + FILE *openf( const char *filename, const char *mode ) { errno_t err; FILE *fd = NULL; @@ -63,11 +68,24 @@ FILE *openf( const char *filename, const char *mode ) { #ifdef _WIN32 +/******************************************************************* ods2_strerror() */ + +const char *ods2_strerror( int errn ) { + static char buf[256]; + + if( strerror_s( buf, sizeof( buf ), errn ) != 0 ) + snprintf( buf, sizeof( buf ), "Untranslatable error %u", errn ); + + return buf; +} + +/******************************************************************* w32_errstr() */ + TCHAR *w32_errstr( DWORD eno, ... ) { va_list ap; TCHAR *msg; - if( eno == 0 ) + if( eno == NO_ERROR ) eno = GetLastError(); va_start(ap,eno); @@ -81,6 +99,8 @@ TCHAR *w32_errstr( DWORD eno, ... ) { return msg; } +/******************************************************************* driveFromLetter() */ + char *driveFromLetter( const char *letter ) { DWORD rv = ERROR_INSUFFICIENT_BUFFER; size_t cs = 16; diff --git a/extracters/ods2/compat.h b/extracters/ods2/compat.h index 5a4fa60..ae39b2b 100644 --- a/extracters/ods2/compat.h +++ b/extracters/ods2/compat.h @@ -20,11 +20,24 @@ FILE *openf( const char *filename, const char *mode ); #endif #ifdef _WIN32 +#include #include #include +#include +#undef getcwd +#define getcwd _getcwd +#undef chdir +#define chdir _chdir + +#undef strerror +#define strerror(n) ods2_strerror(n) +const char *ods2_strerror( errno_t errn ); TCHAR *w32_errstr( DWORD eno, ... ); char *driveFromLetter( const char *letter ); + +#else /* Not WIN32 */ +#include #endif #define UNUSED(x) (void)(x) diff --git a/extracters/ods2/makefile.solaris b/extracters/ods2/makefile.solaris index 2af0778..186be7d 100644 --- a/extracters/ods2/makefile.solaris +++ b/extracters/ods2/makefile.solaris @@ -7,7 +7,7 @@ CC=gcc CCFLAGS = -O4 -g DEFS = -DUSE_READLINE -LDFLAGS = -lreadline +LDFLAGS = -lreadline -ltermcap # Object file extension OBJ = .o diff --git a/extracters/ods2/makefile.tru64 b/extracters/ods2/makefile.tru64 index 640e94a..d4b10a3 100644 --- a/extracters/ods2/makefile.tru64 +++ b/extracters/ods2/makefile.tru64 @@ -4,7 +4,7 @@ CCFLAGS = -O4 -g # DEFS = -DUSE_READLINE -# LDFLAGS = -lreadline +# LDFLAGS = -lreadline -ltermcap # Object file extension OBJ = .o diff --git a/extracters/ods2/makefile.unix b/extracters/ods2/makefile.unix index 8f86399..fb334d4 100644 --- a/extracters/ods2/makefile.unix +++ b/extracters/ods2/makefile.unix @@ -9,7 +9,7 @@ CCFLAGS = -O4 -g # Include readline support DEFS = -DUSE_READLINE -LDFLAGS = -lreadline +LDFLAGS = -lreadline -ltermcap # Object file extension OBJ = .o diff --git a/extracters/ods2/ods2.c b/extracters/ods2/ods2.c index 3aefaff..0878537 100644 --- a/extracters/ods2/ods2.c +++ b/extracters/ods2/ods2.c @@ -104,32 +104,38 @@ #define _BSD_SOURCE #include /* isalpha(), isspace(), tolower() */ +#include #include #include #include #include -#include "version.h" -#include "compat.h" -#include "sysmsg.h" -#include "phyio.h" -#include "phyvirt.h" -#ifdef _WIN32 -#include -#endif +#include "version.h" + #include "access.h" +#include "compat.h" #include "descrip.h" #include "device.h" #include "direct.h" #include "ods2.h" #include "phyio.h" +#include "phyvirt.h" #include "rms.h" #include "ssdef.h" #include "stsdef.h" +#include "sysmsg.h" + +#if !defined( _WIN32 ) && !defined( VMS ) +#include +#include +#else +# ifdef _WIN32 +# include +# endif +#endif #ifdef VMS #include - #else #include "vmstime.h" #endif @@ -148,6 +154,14 @@ #define FALSE ( 0 != 0 ) #endif +#if defined( _WIN32 ) && defined(_MSC_VER) && defined( DEBUG_BUILD ) && defined( USE_VLD ) +/* Normally done in the project file, but VLD is optional and I'd rather not provide + * instructions as they vary by IDE version. See http://vld.codeplex.com/ if interested. + */ +#include "C:\\Program Files (x86)\\Visual Leak Detector\\include\\vld.h" +#pragma comment (lib,"C:\\Program Files (x86)\\Visual Leak Detector\\lib\\Win32\\vld.lib") +#endif + #define MAXREC 32767 #define PRINT_ATTR ( FAB$M_CR | FAB$M_PRN | FAB$M_FTN ) @@ -158,6 +172,7 @@ #include #endif +/******************************************************************* fgetline() */ /* Read a line of input - unlimited length * Removes \n, returns NULL at EOF * Caller responsible for free() @@ -170,7 +185,7 @@ static char *fgetline( FILE *stream, int keepnl ) { int c; while( (c = fgetc(stream)) != EOF && c != '\n' ) { - if( idx + (keepnl != 0) +1 > bufsize ) { /* Allow space for char + (optional \n) + \0 */ + if( idx + (keepnl != 0) +2 > bufsize ) { /* In buf + char + (optional \n) + \0 */ char *nbuf; bufsize += xpnsize; nbuf = (char *) realloc( buf, bufsize ); @@ -202,11 +217,12 @@ static char *fgetline( FILE *stream, int keepnl ) { return buf; } +/******************************************************************* keycomp() */ /* keycomp: routine to compare parameter to a keyword - case insensitive! */ static int keycomp(const char *param, const char *keywrd) { while (*param != '\0') { - if (tolower(*param++) != *keywrd++) return 0; + if( tolower(*param++) != tolower(*keywrd++) ) return 0; } return 1; } @@ -217,11 +233,12 @@ static int keycomp(const char *param, const char *keywrd) { */ #define NV NOVAL, NULL #define KV(list) KEYVAL, list +#define CV(list) KEYCOL, list struct qual { const char *name; int set; int clear; - enum qualtype { NOVAL, KEYVAL } qtype; + enum qualtype { NOVAL, KEYVAL, KEYCOL } qtype; void *arg; const char *helpstr; }; @@ -261,6 +278,7 @@ static void qualhelp( int par, struct qual *qtable ); static int vms_qual = 1; static int verify_cmd = 1; +/******************************************************************* checkquals() */ /* checkquals: Given valid qualifier definitions, process qualifer * list from a command left to right. Also handles parameters and * qualifier values (/Qual=value). @@ -322,6 +340,7 @@ static int checkquals(int result, struct qual qualset[],int qualc,char *qualv[]) *nvp++ = '\0'; switch( qp->qtype ) { case KEYVAL: + case KEYCOL: result = checkquals( result, (struct qual *)qp->arg, -1, &qv ); if( result == -1 ) return result; @@ -336,6 +355,9 @@ static int checkquals(int result, struct qual qualset[],int qualc,char *qualv[]) return result; } +/******************************************************************* dodir() */ +/*********************************************************** prvmstime() */ + static int prvmstime(VMSTIME vtime, const char *sfx) { int sts = 0; char tim[24]; @@ -358,6 +380,8 @@ static int prvmstime(VMSTIME vtime, const char *sfx) { return sts; } +/*********************************************************** pwrap() */ + static void pwrap( int *pos, const char *fmt, ... ) { char pbuf[200], *p, *q; va_list ap; @@ -392,6 +416,7 @@ static void pwrap( int *pos, const char *fmt, ... ) { } } +/*********************************************************** dirtotal() */ #define dir_extra (dir_date | dir_fileid | dir_owner | dir_prot | dir_size) #define dir_date (1 << 0) @@ -486,6 +511,8 @@ static void dirtotal( int options, int size, int alloc ) { return; } +/************************************************************ dodir() */ + static unsigned dodir(int argc,char *argv[],int qualc,char *qualv[]) { char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1]; int options; @@ -1412,7 +1439,7 @@ static unsigned dostats( void ) { /******************************************************************* doshow() */ -/* show: version */ +/*********************************************************** show_version() */ #define MNAMEX(n) #n #define MNAME(n) MNAMEX(n) @@ -1431,23 +1458,26 @@ static void show_version( void ) { # endif printf( " direct SCSI access support"); #endif - printf( "\n\n" ); + printf( "\n " ); + phyio_show( SHOW_FILE64 ); + putchar( '\n' ); return; } -/* show: the show command */ +/*********************************************************** doshow() */ -static struct qual showkwds[] = { {"default", 0, 0, NV, "Default directory"}, - {"devices", 1, 0, NV, "Devices"}, - {"qualifier_style", 2, 0, NV, "Qualifier style (Unix, VMS)" }, - {"statistics", 3, 0, NV, "Debugging statistics", }, - {"time", 4, 0, NV, "Time"}, - {"verify", 5, 0, NV, "Command file echo" }, - {"version", 6, 0, NV, "Version"}, - {"volumes", 7, 0, NV, "Mounted volume information" }, +static struct qual showkwds[] = { {"cwd", 0, 0, NV, "Working directory on local system"}, + {"default", 1, 0, NV, "Default directory on VMS volume"}, + {"devices", 2, 0, NV, "Devices"}, + {"qualifier_style", 3, 0, NV, "Qualifier style (Unix, VMS)" }, + {"statistics", 4, 0, NV, "Debugging statistics"}, + {"time", 5, 0, NV, "Time"}, + {"verify", 6, 0, NV, "Command file echo" }, + {"version", 7, 0, NV, "Version"}, + {"volumes", 8, 0, NV, "Mounted volume information" }, {NULL, 0, 0, NV, NULL } }; -static struct param showpars[] = { {"item_name", REQ, KEYWD, PA(showkwds), NULL }, +static struct param showpars[] = { {"item_name", REQ, KEYWD, PA(showkwds), "" }, {NULL, 0, 0, NOPA, NULL } }; @@ -1463,6 +1493,29 @@ unsigned doshow(int argc,char *argv[],int qualc,char *qualv[]) { default: return SS$_BADPARAM; case 0: { + size_t size = 32; + char *buf = NULL; + while( 1 ) { + char *nbuf; + nbuf = (char *)realloc( buf, size ); + if( nbuf == NULL ) { + free( buf ); + return SS$_INSFMEM; + } + buf = nbuf; + if( getcwd( buf, size ) != NULL ) + break; + if( errno != ERANGE ) { + perror( "getcwd" ); + return SS$_BADPARAM; + } + size *= 2; + } + printf( " Current working directory is %s\n", buf ); + free( buf ); + return SS$_NORMAL; + } + case 1: { int sts; unsigned short curlen; char curdir[NAM$C_MAXRSS + 1]; @@ -1478,16 +1531,16 @@ unsigned doshow(int argc,char *argv[],int qualc,char *qualv[]) { } return sts; } - case 1: + case 2: phyio_show( SHOW_DEVICES ); virt_show( NULL ); return SS$_NORMAL; - case 2: + case 3: printf ( " Qualifier style: %s\n", vms_qual? "/VMS": "-unix" ); return SS$_NORMAL; - case 3: + case 4: return dostats(); - case 4: { + case 5: { unsigned sts; char timstr[24]; unsigned short timlen; @@ -1504,56 +1557,66 @@ unsigned doshow(int argc,char *argv[],int qualc,char *qualv[]) { } } return SS$_NORMAL; - case 5: + case 6: printf( "Command file verification is %s\n", (verify_cmd? "on": "off") ); return SS$_NORMAL; - case 6: + case 7: show_version(); return SS$_NORMAL; - case 7: + case 8: show_volumes(); return SS$_NORMAL; } return SS$_NORMAL; } -/******************************************************************* setdef() */ +/******************************************************************* doset() */ +/*********************************************************** setdef() */ -static unsigned setdef_count = 0; +static int default_set = FALSE; -static unsigned setdef( char *newdef ) -{ +static unsigned setdef( char *newdef ) { register unsigned sts; struct dsc_descriptor defdsc; defdsc.dsc_a_pointer = (char *) newdef; - defdsc.dsc_w_length = strlen( defdsc.dsc_a_pointer ); + defdsc.dsc_w_length = (unsigned short)strlen( defdsc.dsc_a_pointer ); sts = sys_setddir( &defdsc, NULL, NULL ); if ( sts & STS$M_SUCCESS ) { - setdef_count++; + default_set = TRUE; } else { printf( "%%ODS2-E-SETDEF, Error %s setting default to %s\n", getmsg(sts, MSG_TEXT), newdef ); } return sts; } -/******************************************************************** doset() */ +static unsigned setcwd( char *newdef ) { + if( chdir( newdef ) != 0 ) { + printf( "%%ODS2-W-SETDEF, Error %s setting cwd to %s\n", + strerror( errno ), newdef ); + return SS$_BADPARAM; + } + return SS$_NORMAL; +} + +/************************************************************ sethelp() */ static hlpfunc_t sethelp; -static struct qual setkwds[] = { {"default", 0, 0, NV, "Default directory"}, +static struct qual setkwds[] = { {"cwd", 0, 0, NV, "Working directory on local system"}, {"directory_qualifiers", 1, 0, NV, "Default qualifiers for DIRECTORY command" }, - {"qualifier_style", 2, 0, NV, "Qualifier style (Unix, VMS)" }, - {"verify", 3, 0, NV, "-Display commands in indirect files" }, - {"noverify", 4, 0, NV, NULL }, + {"default", 2, 0, NV, "Default directory on VMS volume"}, + {"qualifier_style", 3, 0, NV, "Qualifier style (Unix, VMS)"}, + {"verify", 4, 0, NV, "-Display commands in indirect files"}, + {"noverify", 5, 0, NV, NULL }, {NULL, 0, 0, NV, NULL } }; static struct qual setqskwds[] = {{"unix", 1, 0, NV, "Unix style options, '-option'"}, {"vms", 2, 0, NV, "VMS style qualifiers, '/qualifier'"}, {NULL, 0, 0, NV, NULL } }; -static struct param setpars[] = { {"item_name", REQ, KEYWD, PA(setkwds), NULL }, - {"value" , CND, KEYWD, sethelp, setqskwds, NULL }, +static struct param setpars[] = { {"item_name", REQ, KEYWD, PA(setkwds), "" }, + {"value" , CND, KEYWD, sethelp, setqskwds, "" }, {NULL, 0, 0, NOPA, NULL }, }; @@ -1575,21 +1638,25 @@ static const char * sethelp( struct CMDSET *cmd, struct param *p, int argc, char return NULL; switch( par ) { case 0: - p->helpstr = "default directory on volume - "; - p->ptype = VMSFS; + p->helpstr = "working directory for local files"; + p->ptype = STRING; break; case 1: + p->helpstr = "default directory on volume"; + p->ptype = VMSFS; + break; + case 2: p->helpstr = "directory qualifier name "; p->ptype = KEYWD; p->arg = dirquals; break; - case 2: + case 3: p->helpstr = "style "; p->ptype = KEYWD; p->arg = setqskwds; break; - case 3: case 4: + case 5: p->ptype = NONE; break; @@ -1599,6 +1666,8 @@ static const char * sethelp( struct CMDSET *cmd, struct param *p, int argc, char return NULL; } +/*********************************************************** doset() */ + static unsigned doset(int argc,char *argv[],int qualc,char *qualv[]) { int parnum; @@ -1611,11 +1680,12 @@ static unsigned doset(int argc,char *argv[],int qualc,char *qualv[]) { default: return SS$_BADPARAM; case 0: /* default */ + case 2: /* current working directory */ if( qualc ) { printf( "%%ODS2-E-NOQUAL, No qualifiers are permitted\n" ); return 0; } - return setdef( argv[2] ); + return (parnum == 0)? setdef( argv[2] ) : setcwd( argv[2] ); case 1:{ /* directory_qualifiers */ int options = checkquals(dir_default,dirquals,qualc,qualv); if( options == -1 ) @@ -1623,7 +1693,7 @@ static unsigned doset(int argc,char *argv[],int qualc,char *qualv[]) { dir_defopt = options; return 1; } - case 2: { /* qualifier_style */ + case 3: { /* qualifier_style */ int par = checkquals (0,setqskwds,1,argv+2); if( par == -1 ) return SS$_BADPARAM; @@ -1639,16 +1709,16 @@ static unsigned doset(int argc,char *argv[],int qualc,char *qualv[]) { } return 1; } - case 3: + case 4: verify_cmd = 1; return 1; - case 4: + case 5: verify_cmd = 0; return 1; } } -/* The bits we need when we don't have real VMS routines underneath... */ +/******************************************************************* dodismount() */ static struct param dmopars[] = { {"drive_letter", REQ, STRING, NOPA, "Drive containing volume to dismount", }, {NULL, 0, 0, NOPA, NULL } @@ -1678,7 +1748,10 @@ unsigned dodismount(int argc,char *argv[],int qualc,char *qualv[]) { #error MOU_WRITE != 1 #endif -static struct qual mouquals[] = { {"image", MOU_VIRTUAL, 0, NV, "Mount a disk image file", }, +#define DT_NAME "drive_type" + +static struct qual mouquals[] = { {DT_NAME, 0, MOU_DEVTYPE, CV(NULL), "Drive type (DEC model name) "}, + {"image", MOU_VIRTUAL, 0, NV, "Mount a disk image file", }, {"readonly", 0, MOU_WRITE, NV, "Only allow reading from volume"}, {"virtual", MOU_VIRTUAL, 0, NV, NULL, }, {"write", MOU_WRITE, 0, NV, "Allow writing to volume", }, @@ -1691,6 +1764,10 @@ static struct param moupars[] = { {"volumes", REQ, LIST, NOPA, { NULL, 0, 0, NOPA, NULL } }; +/******************************************************************* domount() */ + +/*********************************************************** parselist() */ + static int parselist( char ***items, size_t min, char *arg, const char *label ) { size_t n = 0, i; char **list = NULL; @@ -1737,7 +1814,9 @@ static int parselist( char ***items, size_t min, char *arg, const char *label ) return (int)n; } -static unsigned domount(int argc,char *argv[],int qualc,char *qualv[]) { +/*********************************************************** domount() */ + +static unsigned domount( int argc,char *argv[],int qualc,char *qualv[] ) { int sts = 1,devices = 0; char **devs = NULL, **labs = NULL; @@ -1760,7 +1839,7 @@ static unsigned domount(int argc,char *argv[],int qualc,char *qualv[]) { struct VCB *vcb; sts = mount( options | MOU_LOG, devices, devs, labs, &vcb ); if (sts & STS$M_SUCCESS) { - if (setdef_count == 0) { + if( !default_set ) { char *colon, *buf; size_t len; @@ -1770,7 +1849,8 @@ static unsigned domount(int argc,char *argv[],int qualc,char *qualv[]) { perror( "malloc" ); } else { colon = strchr( vcb->vcbdev[0].dev->devnam, ':' ); - if( colon != NULL ) len = (size_t)(colon - vcb->vcbdev[0].dev->devnam); + if( colon != NULL ) + len = (size_t)(colon - vcb->vcbdev[0].dev->devnam); memcpy( buf, vcb->vcbdev[0].dev->devnam, len ); memcpy( buf+len, ":[000000]", sizeof( ":[000000]" ) ); setdef(buf); @@ -1788,8 +1868,68 @@ static unsigned domount(int argc,char *argv[],int qualc,char *qualv[]) { return sts; } +/******************************************************************* dospawn() */ + +static unsigned dospawn( int argc,char *argv[],int qualc,char *qualv[] ) { +#ifdef VMS + unsigned sts; + + UNUSED( argc ); + UNUSED( argv ); + UNUSED( qualc ); + UNUSED( qualv ); + + sts = lib$spawn( 0,0,0,0,0,0,0,0,0,0,0,0,0 ); + return sts; +#else +# ifdef _WIN32 + UNUSED( argc ); + UNUSED( argv ); + UNUSED( qualc ); + UNUSED( qualv ); + + if( system( "cmd" ) == -1 ) { + perror( "cmd" ); + return SS$_NOSUCHFILE; + } + return SS$_NORMAL; +# else + char *shell, *p; + pid_t pid; + + UNUSED( argc ); + UNUSED( argv ); + UNUSED( qualc ); + UNUSED( qualv ); + + if( (shell = getenv( "SHELL" )) == NULL ) + shell = "/bin/sh"; + if( (p = strrchr( shell, '/')) == NULL ) + p = shell; + else + p++; + + if( (pid = fork()) == 0 ) { + execlp( shell, p, (char *)NULL ); + perror( "%s" ); + exit(EXIT_FAILURE); + } + if( pid == -1 ) { + perror( shell ); + return SS$_NOSUCHFILE; + } + waitpid( pid, NULL, 0 ); + + return SS$_NORMAL; +# endif +#endif + +} + /******************************************************************* dohelp() */ +/*********************************************************** cmdhelp() */ + static void cmdhelp( struct CMDSET *cmdset ) { struct CMDSET *cmd; int n = 0; @@ -1809,10 +1949,12 @@ static void cmdhelp( struct CMDSET *cmdset ) { printf( "\n" ); } +/*********************************************************** cmdhelp() */ + static void qualhelp( int par, struct qual *qtable ) { struct qual *q; int n = 0; - size_t max = 0; + size_t max = 0, col = 4; if( par < 0 ) max = -par; @@ -1838,14 +1980,28 @@ static void qualhelp( int par, struct qual *qtable ) { if( *q->helpstr == '-' ) switch( q->qtype ) { case NOVAL: - printf( NOSTR "%-*s - %s\n", - (int) (max-NOSTR_LEN), q->name, q->helpstr+1 ); + if( *q->helpstr ) { + printf( NOSTR "%-*s - %s\n", + (int) (max-NOSTR_LEN), q->name, q->helpstr+1 ); + break; + } + if( col + max > 50 ) { + printf( "\n " ); + col = 8; + } else { + while( col < 8 ) { + putchar( ' ' ); col++; + } + } + printf( "%-*s", (int) max, q->name ); + col += max; break; case KEYVAL: + case KEYCOL: printf( NOSTR "%s=%-*s - %s\n", q->name, (int) (max-(NOSTR_LEN+strlen(q->name)+1)), "", q->helpstr+1 ); - qualhelp( -(int)max, (struct qual *)q->arg ); + qualhelp( q->qtype == KEYCOL? 1 : -(int)max, (struct qual *)q->arg ); break; default: abort(); @@ -1853,12 +2009,26 @@ static void qualhelp( int par, struct qual *qtable ) { else switch( q->qtype ) { case NOVAL: - printf("%-*s - %s\n", (int) max, q->name, q->helpstr ); + if( *q->helpstr ) { + printf("%-*s - %s\n", (int) max, q->name, q->helpstr ); + break; + } + if( col + max > 50 ) { + printf( "\n " ); + col = 8; + } else { + while( col < 8 ) { + putchar( ' ' ); col++; + } + } + printf( "%-*s", (int) max, q->name ); + col += max; break; case KEYVAL: + case KEYCOL: printf( "%s=%-*s - %s\n", q->name, (int)(max-strlen(q->name)+1), "", q->helpstr ); - qualhelp( -(int)max, (struct qual *)q->arg ); + qualhelp( q->qtype == KEYCOL? 1 : -(int)max, (struct qual *)q->arg ); break; default: abort(); @@ -1871,6 +2041,8 @@ static void qualhelp( int par, struct qual *qtable ) { #undef NOSTR #undef NOSTR_LEN +/*********************************************************** parhelp() */ + static void parhelp( struct CMDSET *cmd, int argc, char **argv) { struct param *p; struct param *ptable; @@ -1888,14 +2060,14 @@ static void parhelp( struct CMDSET *cmd, int argc, char **argv) { size_t max = 0; for( p = ptable; p->name != NULL; p++ ) { - if( 1||p->helpstr ) { + if( p->helpstr ) { size_t len = strlen(p->name); if( len > max ) max = len; } } for( p = ptable; p->name != NULL; p++ ) { - if(1|| p->helpstr ) { + if( p->helpstr ) { size_t len = strlen(p->name); if( !col ) { printf( " Parameters:\n " ); @@ -1913,7 +2085,8 @@ static void parhelp( struct CMDSET *cmd, int argc, char **argv) { col += len; } } - printf( "\n\n Type help PARAMETER for more about each parameter.\n" ); + printf( "\n\n Type help %s PARAMETER for more about each parameter.\n", + cmd->name ); return; } @@ -1968,13 +2141,15 @@ static void parhelp( struct CMDSET *cmd, int argc, char **argv) { return; } +/*********************************************************** dohelp() */ /* help: Display help guided by command table. */ -#define NCMD 16 + +#define NCMD 17 static struct CMDSET cmdset[NCMD+1]; -static struct param helppars[] = { {"command", OPT, CMDNAM, PA(cmdset), NULL }, - {"parameter", OPT, STRING, NOPA, NULL }, - {"value", OPT, STRING, NOPA, NULL }, +static struct param helppars[] = { {"command", OPT, CMDNAM, PA(cmdset), "" }, + {"parameter", OPT, STRING, NOPA, "" }, + {"value", OPT, STRING, NOPA, "" }, {NULL, 0, 0, NOPA, NULL }, }; @@ -1983,19 +2158,20 @@ static unsigned dohelp(int argc,char *argv[],int qualc,char *qualv[]); static struct CMDSET cmdset[NCMD+1] = { { "copy", docopy, 0,copyquals,copypars, "Copy a file from VMS to host file", }, - { "import", doimport, 0,NULL, importpars, "Copy a file from host to VMS", }, { "delete", dodelete, 0,delquals, delpars, "Delete a VMS file", }, { "difference",dodiff, 0,NULL, diffpars, "Compare VMS file to host file", }, { "directory", dodir, 0,dirquals,dirpars, "List directory of VMS files", }, + { "dismount", dodismount,0,NULL, dmopars, "Dismount a VMS volume", }, { "exit", NULL, 2,NULL, NULL, "Exit ODS2", }, { "extend", doextend, 0,NULL, extendpars, NULL }, { "help", dohelp, 0,NULL, helppars, "Obtain help on a command", }, - { "quit", NULL, 2,NULL, NULL, "Exit ODS-2", }, - { "show", doshow, 0,NULL, showpars, "Display state", }, - { "search", dosearch, 0,NULL, searchpars, "Search VMS file for a string", }, - { "set", doset, 0,NULL, setpars, "Set PARAMETER - set HELP for list", }, - { "dismount", dodismount,0,NULL, dmopars, "Dismount a VMS volume", }, + { "import", doimport, 0,NULL, importpars, "Copy a file from host to VMS", }, { "mount", domount, 0,mouquals, moupars, "Mount a VMS volume", }, + { "quit", NULL, 2,NULL, NULL, "Exit ODS-2", }, + { "search", dosearch, 0,NULL, searchpars, "Search VMS file for a string", }, + { "set", doset, 0,NULL, setpars, "Set PARAMETER - set HELP for list", }, + { "show", doshow, 0,NULL, showpars, "Display state", }, + { "spawn", dospawn, 0,NULL, NULL, "Open a command subprocess", }, { "test", dotest, 0,NULL, testpars, NULL }, { "type", dotype, 0,NULL, typepars, "Display a VMS file on the terminal", }, { NULL, NULL, 0,NULL, NULL, NULL } /* ** END MARKER ** */ @@ -2064,15 +2240,6 @@ static unsigned dohelp(int argc,char *argv[],int qualc,char *qualv[]) { } printf( "%s: command not found\n", argv[1] ); return 0; - - printf(" set_default type\n"); - printf(" Example:-\n $ mount e:\n"); - printf(" $ search e:[vms_common.decc*...]*.h rms$_wld\n"); - printf(" $ set default e:[sys0.sysmgr]\n"); - printf(" $ copy *.com;-1 c:\\*.*\n"); - printf(" $ directory/file/size/date [-.sys*...].%%\n"); - printf(" $ exit\n"); - return 1; } /*************************************************************** cmdexecute() */ @@ -2142,7 +2309,7 @@ static int cmdexecute( int argc, char *argv[], int qualc, char *qualv[] ) { /* cmdsplit: break a command line into its components */ /* - * New feature for Unix: '//' or '--' stops qualifier parsing. + * Feature for Unix: '//' or '--' stops qualifier parsing. * This enables us to copy to Unix directories with VMS style /qualifiers. * copy /bin // *.com /tmp/ * * is split into argv[0] -> "*.com" argv[1] -> "/tmp/ *" qualv[0]-> "/bin" @@ -2156,60 +2323,71 @@ static int cmdsplit(char *str) { char *sp = str; int i; char q = vms_qual? '/': '-'; - for (i = 0; i < MAXITEMS; i++) argv[i] = qualv[i] = ""; - while (*sp != '\0') { - while (*sp == ' ') sp++; - if (*sp != '\0') { - if (*sp == q) { - *sp++ = '\0'; - if (*sp == q) { - sp++; - q = '\0'; - continue; - } - if( qualc >= MAXITEMS ) { - printf( "%%ODS2-E-CMDERR, Too many qualifiers specified\n" ); - return 0; + + for( i = 0; i < MAXITEMS; i++ ) argv[i] = qualv[i] = ""; + + while( *sp != '\0' ) { + while( *sp == ' ' ) sp++; + if( *sp == '\0' ) + break; + + if( *sp == q ) { /* Start of qualifier */ + *sp++ = '\0'; /* Terminate previous word */ + if (*sp == q) { /* qq = end of qualifiers */ + sp++; + q = '\0'; + continue; + } + if( qualc >= MAXITEMS ) { + printf( "%%ODS2-E-CMDERR, Too many qualifiers specified\n" ); + return 0; + } + qualv[qualc++] = sp; + } else { /* New argument */ + if( argc >= MAXITEMS ) { + printf( "%%ODS2-E-CMDERR, Too many arguments specified\n" ); + return 0; + } + argv[argc++] = sp; + if( *sp == '"' ) { + ++argv[argc-1]; + for( ++sp; *sp && (*sp != '"' || sp[1] == '"'); sp++ ) { + if( *sp == '"' ) /* Interior "" => " */ + memmove( sp, sp+1, strlen(sp+1)+1 ); } - qualv[qualc++] = sp; - } else { - if( argc >= MAXITEMS ) { - printf( "%%ODS2-E-CMDERR, Too many arguments specified\n" ); - return 0; - } - argv[argc++] = sp; - if( *sp == '"' ) { - ++argv[argc-1]; - for( ++sp; *sp && (*sp != '"' || sp[1] == '"'); sp++ ) { - if( *sp == '"' ) - memmove( sp, sp+1, strlen(sp+1)+1 ); - } - if( *sp == '"' ) { - *sp++ = '\0'; - if( *sp && *sp != ' ' ) { - printf( "%%ODS2-E-CMDERR, Unterminated string\n" ); - return 0; - } - } else { + if( *sp == '"' ) { /* Ending " of string */ + *sp++ = '\0'; + if( *sp && *sp != ' ' ) { /* Something following */ printf( "%%ODS2-E-CMDERR, Unterminated string\n" ); return 0; } - continue; + } else { + printf( "%%ODS2-E-CMDERR, Unterminated string\n" ); + return 0; } - } - while (*sp != ' ' && *sp != q && *sp != '\0') sp++; - if (*sp == '\0') { - break; - } else { - if (*sp != q) *sp++ = '\0'; - } + continue; + } /* Quoted string */ } + + /* Find end of atom */ + + while( !(*sp == '\0' || *sp == ' ' || *sp == q) ) sp++; + if (*sp == '\0') + break; + if( *sp == ' ' ) + *sp++ = '\0'; } - if (argc > 0) return cmdexecute(argc,argv,qualc,qualv); + if( argc > 0 ) + return cmdexecute( argc, argv, qualc, qualv ); + return 1; } +/******************************************************************* main() */ + +/*********************************************************** getcmd() */ + #ifdef VMS static char *getcmd( char *inp, size_t max, char *prompt ) { struct dsc_descriptor prompt_d = { strlen(prompt),DSC$K_DTYPE_T, @@ -2242,6 +2420,7 @@ static char *getcmd( char *inp, size_t max, char *prompt ) { } #endif /* VMS */ +/*********************************************************** main() */ /* main: the simple mainline of this puppy... */ /* @@ -2285,10 +2464,43 @@ int main( int argc,char *argv[] ) { history_truncate_file( hfname, 200 ); stifle_history( 200 ); read_history( hfname ); - } else { - hfname = NULL; } #endif + sts = sys_initialize(); + if( !(sts & STS$M_SUCCESS) ) { + printf( "Unable to initialize library: %s\n", getmsg( sts, MSG_TEXT ) ); + exit(EXIT_FAILURE); + } + { /* Build parser keyword list from disk table entries */ + struct qual *qp, *kp = NULL; + struct disktype * dp; + size_t n = 0; + + for( dp = disktype; dp->name != NULL; dp++ ) + ; + n = (size_t) (dp - disktype); + kp = (struct qual *)calloc( n+1, sizeof( struct qual ) ); + if( kp == NULL ) { + perror( "malloc" ); + exit( EXIT_FAILURE ); + } + for( qp = mouquals; qp->name != NULL; qp++ ) + if( !strcmp( qp->name, DT_NAME ) ) + break; + qp->arg = kp; + + for( dp = disktype; dp->name != NULL; dp++ ) { + kp->name = dp->name; + kp->set = (int)((dp-disktype) << MOU_V_DEVTYPE); + kp->clear = MOU_DEVTYPE; + kp->qtype = NOVAL; + if( dp != disktype ) + kp->helpstr = ""; + kp++; + } + if( (((unsigned)(dp-disktype)) << MOU_V_DEVTYPE) & ~MOU_DEVTYPE ) + abort(); /* MOU_DEVTYPE isn't wide enough for the max index */ + } if( argc > 1 ) { int i, l = 0; @@ -2327,6 +2539,10 @@ int main( int argc,char *argv[] ) { *p = '\0'; i += strlen( ptr ) +1; } +#ifdef USE_READLINE + if( ptr != NULL && *ptr ) + add_history( ptr ); +#endif } if( ptr == NULL ) { if (atfile != NULL) { @@ -2404,18 +2620,30 @@ int main( int argc,char *argv[] ) { } } /* while 1 */ + free( command_line ); + if( rl != NULL ) { free( rl ); } #ifdef USE_READLINE if( hfname != NULL ) { write_history( hfname ); + clear_history(); } + wordfree( &wex ); /* hfname points into wex and should not be free()d */ #endif - if (atfile != NULL) fclose(atfile); -#ifdef VMS - return 1; -#else - return 0; -#endif + if (atfile != NULL) + fclose(atfile); + + { + struct qual *qp; + + for( qp = mouquals; qp->name != NULL; qp++ ) + if( !strcmp( qp->name, DT_NAME ) ) { + free( qp-> arg ); + qp->arg = NULL; + break; + } + } + exit( EXIT_SUCCESS ); } diff --git a/extracters/ods2/ods2.h b/extracters/ods2/ods2.h index 1bdbbf7..7b7bcb2 100644 --- a/extracters/ods2/ods2.h +++ b/extracters/ods2/ods2.h @@ -5,10 +5,11 @@ #ifndef _ODS2_H #define _ODS2_H -#define MOU_WRITE 1 -#define MOU_VIRTUAL 2 -#define MOU_LOG 4 +#define MOU_WRITE 1 +#define MOU_VIRTUAL 2 +#define MOU_LOG 4 -#define SUB_DELETE 1 +#define MOU_V_DEVTYPE 8 +#define MOU_DEVTYPE (0xffff << MOU_V_DEVTYPE) #endif /* #ifndef _ODS2_H */ diff --git a/extracters/ods2/phynt.c b/extracters/ods2/phynt.c index bbdd9f7..1f2543a 100644 --- a/extracters/ods2/phynt.c +++ b/extracters/ods2/phynt.c @@ -40,6 +40,7 @@ #include "stsdef.h" #include "compat.h" #include "phyvirt.h" +#include "sysmsg.h" #ifdef USE_ASPI #include "scsidefs.h" @@ -558,9 +559,11 @@ static void getsysversion( void ) { OSVERSIONINFO sysver; memset( &sysver, 0, sizeof( sysver ) ); +#pragma warning (disable : 4996) sysver.dwOSVersionInfoSize = sizeof( sysver ); GetVersionEx( &sysver /* lpVersionInfo */ ); +#pragma warning (default : 4996) is_NT = ( sysver.dwPlatformId == VER_PLATFORM_WIN32_NT ) ? 1 : 0 ; } @@ -580,21 +583,21 @@ static unsigned phy_getsect( struct DEV *dev, unsigned sector ) { sector, dev->bytespersector, dev->IoBuffer ); } else #endif - { + { if ( dev->access & MOU_VIRTUAL || is_NT ) { - DWORD DistanceLow, DistanceHigh, BytesRead; - DistanceLow = ( sector * dev->blockspersector ) << 9; - DistanceHigh = ( sector * dev->blockspersector ) >> 23; - SetLastError( 0 ); - SetFilePointer( dev->API.Win32.handle,/* hFile */ - DistanceLow, /* lDistanceToMove */ - &DistanceHigh, /* lpDistanceToMoveHigh */ - FILE_BEGIN /* dwMoveMethod */ - ); - if ( GetLastError() != NO_ERROR ) { - TCHAR *msg = w32_errstr(0); - printf( "PHYIO_READ: SetFilePointer() failed: %s\n", - msg ); + DWORD BytesRead; + __int64 distance; + LARGE_INTEGER li; + distance = (((__int64)sector) * dev->blockspersector) << 9; + li.QuadPart = distance; + if( SetFilePointer( dev->API.Win32.handle,/* hFile */ + li.LowPart, /* lDistanceToMove */ + &li.HighPart, /* lpDistanceToMoveHigh */ + FILE_BEGIN /* dwMoveMethod */ + ) == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR ) { + TCHAR *msg = w32_errstr(NO_ERROR); + printf( "PHYIO_READ: SetFilePointer() failed at sector %lu: %s\n", + sector, msg ); LocalFree(msg); sts = SS$_PARITY; } @@ -607,9 +610,14 @@ static unsigned phy_getsect( struct DEV *dev, unsigned sector ) { &BytesRead, /* lpNumberOfBytesRead */ NULL /* lpOverlapped */ ) || BytesRead != dev->bytespersector ) { - TCHAR *msg = w32_errstr(0); - printf( "PHYIO_READ: ReadFile() failed: %s\n", - msg ); + TCHAR *msg; + + if( BytesRead == 0 ) + return SS$_ENDOFFILE; + + msg = w32_errstr(NO_ERROR); + printf( "PHYIO_READ: ReadFile() failed at sector %lu: %s\n", + sector, msg ); LocalFree(msg); sts = SS$_PARITY; } @@ -641,7 +649,7 @@ static unsigned phy_getsect( struct DEV *dev, unsigned sector ) { NULL /* lpOverlapped */ ) && !( reg.reg_Flags & 0x0001 ); if ( !result ) { - TCHAR *msg = w32_errstr(0); + TCHAR *msg = w32_errstr(NO_ERROR); printf( "PHYIO_READ: Read sector %d failed: %s\n", sector, msg ); LocalFree(msg); @@ -672,34 +680,33 @@ static unsigned phy_putsect( struct DEV *dev, unsigned sector ) { #endif { if ( dev->access & MOU_VIRTUAL || is_NT ) { - DWORD DistanceLow, DistanceHigh, BytesWritten; - DistanceLow = ( sector * dev->blockspersector ) << 9; - DistanceHigh = ( sector * dev->blockspersector ) >> 23; - SetLastError( 0 ); - SetFilePointer( dev->API.Win32.handle, /* hFile */ - DistanceLow, /* lDistanceToMove */ - &DistanceHigh, /* lpDistanceToMoveHigh */ - FILE_BEGIN /* dwMoveMethod */ - ); - if ( GetLastError() != NO_ERROR ) { - TCHAR *msg = w32_errstr(0); - printf( "PHYIO_WRITE: SetFilePointer() failed: %s\n", - msg ); + DWORD BytesWritten; + __int64 distance; + LARGE_INTEGER li; + distance = (((__int64)sector) * dev->blockspersector) << 9; + li.QuadPart = distance; + if( SetFilePointer( dev->API.Win32.handle,/* hFile */ + li.LowPart, /* lDistanceToMove */ + &li.HighPart, /* lpDistanceToMoveHigh */ + FILE_BEGIN /* dwMoveMethod */ + ) == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR ) { + TCHAR *msg = w32_errstr(NO_ERROR); + printf( "PHYIO_WRITE: SetFilePointer() failed at sector %lu: %s\n", + sector, msg ); LocalFree(msg); sts = SS$_PARITY; } if ( sts & STS$M_SUCCESS ) { - /* hFile */ - if ( !WriteFile( dev->API.Win32.handle, - dev->IoBuffer, /* lpBuffer */ - /* nNumberOfBytesToWrite */ + if ( !WriteFile( dev->API.Win32.handle, /* hFile */ + dev->IoBuffer, /* lpBuffer */ + /* nNumberOfBytesToWrite */ dev->bytespersector, - &BytesWritten, /* lpNumberOfBytesWritten */ - NULL /* lpOverlapped */ + &BytesWritten, /* lpNumberOfBytesWritten */ + NULL /* lpOverlapped */ ) || BytesWritten != dev->bytespersector ) { - TCHAR *msg = w32_errstr(0); - printf( "PHYIO_WRITE: WriteFile() failed: %s\n", - msg ); + TCHAR *msg = w32_errstr(NO_ERROR); + printf( "PHYIO_WRITE: WriteFile() failed at sector %lu: %s\n", + sector, msg ); LocalFree(msg); sts = SS$_PARITY; } @@ -730,7 +737,7 @@ static unsigned phy_putsect( struct DEV *dev, unsigned sector ) { NULL /* lpOverlapped */ ) && !( reg.reg_Flags & 0x0001 ); if ( !result ) { - TCHAR *msg = w32_errstr(0); + TCHAR *msg = w32_errstr(NO_ERROR); printf( "PHYIO_WRITE: Write sector %d failed: %s\n", sector, msg ); LocalFree(msg); @@ -751,7 +758,7 @@ void phyio_show( showtype_t type ) { init_count, read_count, write_count ); return; case SHOW_FILE64: - printf( "\nLarge ODS-2 image files (>2GB) are supported.\n" ); + printf( "Large ODS-2 image files (>2GB) are %ssupported.\n", "" ); return; case SHOW_DEVICES: { TCHAR *namep = NULL, *dname = NULL; @@ -793,8 +800,8 @@ void phyio_show( showtype_t type ) { free(namep); } } - } return; + } default: abort(); } @@ -934,15 +941,15 @@ unsigned phyio_init( struct DEV *dev ) { ); } if ( dev->API.Win32.handle == INVALID_HANDLE_VALUE ) { - TCHAR *msg = w32_errstr(0); + TCHAR *msg = w32_errstr(NO_ERROR); printf( "PHYIO_INIT: Open( \"%s\" ) failed: %s\n", dev->devnam, msg ); LocalFree(msg); return SS$_NOSUCHDEV; } if ( !LockVolume( dev ) ) { - TCHAR *msg = w32_errstr(0); - printf( "PHYIO_INIT: LockVolume( \"%s\" ) failed: %a\n", + TCHAR *msg = w32_errstr(NO_ERROR); + printf( "PHYIO_INIT: LockVolume( \"%s\" ) failed: %s\n", dev->devnam, msg ); LocalFree(msg); phyio_done( dev ); @@ -950,7 +957,7 @@ unsigned phyio_init( struct DEV *dev ) { } } if ( !GetDiskGeometry( dev, &dev->sectors, &dev->bytespersector ) ) { - TCHAR *msg = w32_errstr(0); + TCHAR *msg = w32_errstr(NO_ERROR); printf( "PHYIO_INIT: GetDiskGeometry( \"%s\" ) failed: %s\n", dev->devnam, msg ); LocalFree(msg); @@ -989,6 +996,10 @@ unsigned phyio_init( struct DEV *dev ) { ); } if ( dev->API.Win32.handle == INVALID_HANDLE_VALUE ) { + TCHAR *msg = w32_errstr(NO_ERROR); + printf( "PHYIO_INIT: CreateFile() failed for %s: %s\n", + virtual, msg ); + LocalFree(msg); return SS$_NOSUCHFILE; } SetLastError( 0 ); @@ -1078,8 +1089,8 @@ unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length, offset = 0; } if ( !( sts & STS$M_SUCCESS ) ) { - printf( "PHYIO_READ Error %d Block %d Length %d", - sts, block, length ); + printf( "PHYIO_READ Error %s Block %d Length %d", + getmsg(sts, MSG_TEXT), block, length ); #ifdef USE_ASPI printf( " (ASPI: %x %x %x)", ASPI_status, ASPI_HaStat, ASPI_TargStat ); diff --git a/extracters/ods2/phyunix.c b/extracters/ods2/phyunix.c index d7ed90c..51a911f 100644 --- a/extracters/ods2/phyunix.c +++ b/extracters/ods2/phyunix.c @@ -111,8 +111,10 @@ static void showdevs( void ) { free( fs ); continue; } - if( !S_ISBLK( stb.st_mode ) ) + if( !S_ISBLK( stb.st_mode ) ) { + free( fs ); continue; + } memmove( fs, fs + sizeof( DEV_PREFIX ) -1, len +1 ); unit = ~0; @@ -126,14 +128,17 @@ static void showdevs( void ) { 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 ) + if( nl == NULL ) { + free( fs ); break; + } list = nl; (*list)[n].name = fs; (*list)[n].low = unit; @@ -206,7 +211,8 @@ void phyio_show( showtype_t type ) { init_count, read_count, write_count ); return; case SHOW_FILE64: - printf( "\nLarge ODS-2 image files (>2GB) are supported.\n" ); + printf( "Large ODS-2 image files (>2GB) are %ssupported.\n", + (sizeof( off_t ) < 8)? "NOT ": "" ); return; case SHOW_DEVICES: printf( " Physical devices\n" ); @@ -338,6 +344,9 @@ unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length, 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; diff --git a/extracters/ods2/phyvirt.c b/extracters/ods2/phyvirt.c index 0d0274c..ccc1f8a 100644 --- a/extracters/ods2/phyvirt.c +++ b/extracters/ods2/phyvirt.c @@ -52,7 +52,7 @@ void virt_show( const char *devnam ) { unsigned devlen, devsiz; struct VDEV *vp; - if ( devnam == NULL ) { + if( devnam == NULL ) { size_t maxd = sizeof( "Device" ) -1, maxp = sizeof( "File" ) -1, n; @@ -61,7 +61,7 @@ void virt_show( const char *devnam ) { printf( " No virtual devices are assigned\n" ); return; } - for ( vp = virt_device_list; vp != NULL; vp = vp->next ) { + for( vp = virt_device_list; vp != NULL; vp = vp->next ) { n = strlen( vp->devnam ); if( n > maxd ) maxd = n; @@ -79,23 +79,23 @@ void virt_show( const char *devnam ) { for( n = 0; n < maxp; n++ ) putchar( '-' ); putchar( '\n' ); - for ( vp = virt_device_list; vp != NULL; vp = vp->next ) { + for( vp = virt_device_list; vp != NULL; vp = vp->next ) { n = strlen( vp->path ); printf( " %-*s %.*s\n", (int)maxd, vp->devnam, (int)maxp, (n > maxp)? vp->path+(n-maxp): vp->path ); } } else { devlen = strlen( devnam ); - for ( devsiz = 0; devsiz < devlen; devsiz++ ) { - if ( devnam[devsiz] == ':' ) { + for( devsiz = 0; devsiz < devlen; devsiz++ ) { + if( devnam[devsiz] == ':' ) { break; } } - if ( devsiz == 0 ) { + if( devsiz == 0 ) { return; } - for ( vp = virt_device_list; vp != NULL; vp = vp->next ) { - if ( virt_compare( devsiz, (char *) devnam, vp->devnam ) == 0 ) { + for( vp = virt_device_list; vp != NULL; vp = vp->next ) { + if( virt_compare( devsiz, (char *) devnam, vp->devnam ) == 0 ) { printf( " %s => %s\n", vp->devnam, vp->path ); return; } @@ -111,13 +111,13 @@ static int virt_compare( unsigned keylen, const char *keynam, register int cmp; cmp = 0; - while ( keylen-- > 0 ) { + while( keylen-- > 0 ) { cmp = toupper( *keynam++ ) - toupper( *devnam++ ); - if ( cmp != 0 ) { + if( cmp != 0 ) { break; } } - if ( cmp == 0 && *devnam != '\0' && *devnam != ':' ) { + if( cmp == 0 && *devnam != '\0' && *devnam != ':' ) { cmp = -1; } return cmp; @@ -133,16 +133,16 @@ char *virt_lookup( const char *devnam ) { struct VDEV *vp; devlen = strlen( devnam ); - for ( devsiz = 0; devsiz < devlen; devsiz++ ) { - if ( devnam[devsiz] == ':' ) { + for( devsiz = 0; devsiz < devlen; devsiz++ ) { + if( devnam[devsiz] == ':' ) { break; } } - if ( devsiz == 0 ) { + if( devsiz == 0 ) { return NULL; } - for ( vp = virt_device_list; vp != NULL; vp = vp->next ) { - if ( virt_compare( devsiz, (char *) devnam, vp->devnam ) == 0 ) { + for( vp = virt_device_list; vp != NULL; vp = vp->next ) { + if( virt_compare( devsiz, (char *) devnam, vp->devnam ) == 0 ) { return vp->path; } } @@ -176,21 +176,22 @@ unsigned virt_device( char *devnam, char **vname ) { } path = p; - for ( vpp = &virt_device_list; *vpp != NULL; vpp = &(*vpp)->next ) { + for( vpp = &virt_device_list; *vpp != NULL; vpp = &(*vpp)->next ) { if( strcmp( (*vpp)->path, path ) == 0 ) { printf( "%%ODS2-E-MAPPED, %s is in use on virtual drive %s\n", path, (*vpp)->devnam ); + free( path ); return SS$_DEVMOUNT; } } } devlen = strlen( devnam ); - for ( devsiz = 0; devsiz < devlen; devsiz++ ) { - if ( devnam[devsiz] == ':' ) { + for( devsiz = 0; devsiz < devlen; devsiz++ ) { + if( devnam[devsiz] == ':' ) { break; } } - if ( devsiz == 0 ) { + if( devsiz == 0 ) { free( path ); return SS$_BADPARAM; } @@ -216,21 +217,21 @@ static struct VDEV *virt_insert( const char *devnam, unsigned devsiz, struct VDEV *vp, **vpp, **here; here = NULL; - for ( vpp = &virt_device_list; *vpp != NULL; vpp = &(*vpp)->next ) { - if ( virt_compare( devsiz, (char *) devnam, (*vpp)->devnam ) < 0 ) { + for( vpp = &virt_device_list; *vpp != NULL; vpp = &(*vpp)->next ) { + if( virt_compare( devsiz, (char *) devnam, (*vpp)->devnam ) < 0 ) { here = vpp; } } - if ( here == NULL ) { + if( here == NULL ) { here = vpp; } vp = (struct VDEV *) malloc( sizeof( struct VDEV ) ); - if ( vp == NULL ) { + if( vp == NULL ) { return NULL; } vp->devnam = (char *) malloc( devsiz + 1 ); vp->path = (char *) malloc( (pathsiz = strlen( path )) + 1 ); - if ( vp->devnam == NULL || vp->path == NULL ) { + if( vp->devnam == NULL || vp->path == NULL ) { free( vp->devnam ); free( vp->path ); free( vp ); @@ -251,8 +252,8 @@ static void virt_remove( const char *devnam, unsigned devsiz ) { struct VDEV *vp, **vpp; - for ( vpp = &virt_device_list; *vpp != NULL; vpp = &(*vpp)->next ) { - if ( virt_compare( devsiz, (char *) devnam, (*vpp)->devnam ) == 0 ) { + for( vpp = &virt_device_list; *vpp != NULL; vpp = &(*vpp)->next ) { + if( virt_compare( devsiz, (char *) devnam, (*vpp)->devnam ) == 0 ) { vp = *vpp; *vpp = (*vpp)->next; free( vp->devnam ); diff --git a/extracters/ods2/phyvms.c b/extracters/ods2/phyvms.c index 88ac8aa..2d7d963 100644 --- a/extracters/ods2/phyvms.c +++ b/extracters/ods2/phyvms.c @@ -39,6 +39,7 @@ #include #include /* struct FAB */ #include +#include #include #include #include @@ -67,15 +68,23 @@ unsigned sys$dassgn(); #include #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 "virtual.h" struct ITMLST { - unsigned short length; - unsigned short itmcod; - void *buffer; - unsigned long *retlen; + unsigned short length; + unsigned short itmcod; + void *buffer; + unsigned short *retlen; }; #define chk( sts ) { register chksts; \ @@ -83,10 +92,86 @@ struct ITMLST { lib$stop( chksts ); \ } +#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 ) { + unsigned long 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: + printf( "No devices found\n" ); + case SS$_NORMAL: + break; + default: + printf( "%%ODS2-W-ERRDEV, Error scanning devices: %s\n", + getmsg( status, MSG_TEXT ) ); + break; + } + return; +} + /*************************************************************** phyio_show() */ void phyio_show( showtype_t type ) { @@ -96,13 +181,12 @@ void phyio_show( showtype_t type ) { init_count, read_count, write_count ); return; case SHOW_FILE64: - printf( "\nLarge ODS-2 image files (>2GB) are supported.\n" ); + printf( "Large ODS-2 image files (>2GB) are %ssupported.\n", + (sizeof( off_t ) < 8)? "NOT ": "" ); return; case SHOW_DEVICES: -#if 0 /* VMS doesn't make listing devices easy */ printf( " Physical devices\n" ); showdevs(); -#endif return; default: abort(); @@ -178,6 +262,7 @@ unsigned phyio_init( struct DEV *dev ) { 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 }, @@ -191,7 +276,7 @@ unsigned phyio_init( struct DEV *dev ) { /* Get some device information: device name, class, and mount status */ devdsc.dsc$w_length = strlen( dev->devnam ); devdsc.dsc$a_pointer = dev->devnam; - sts = sys$getdviw( 0, 0, &devdsc, &dvi_itmlst, 0, 0, 0, 0 ); + sts = sys$getdviw( EFN$C_ENF, 0, &devdsc, &dvi_itmlst, iosb, 0, 0, 0 ); if ( !( sts & STS$M_SUCCESS ) ) { return sts; } @@ -295,6 +380,9 @@ unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length, return SS$_PARITY; } if ( ( res = read( dev->handle, buffer, length ) ) != length ) { + if( res == 0 ) { + return SS$_ENDOFFILE; + } perror( "read " ); printf( "read failed %d\n", res ); return SS$_PARITY; diff --git a/extracters/ods2/rms.c b/extracters/ods2/rms.c index cab1b48..a9f494f 100644 --- a/extracters/ods2/rms.c +++ b/extracters/ods2/rms.c @@ -37,6 +37,7 @@ #include "ssdef.h" #include "stsdef.h" #include "compat.h" +#include "sysmsg.h" #ifndef TRUE #define TRUE ( 0 == 0 ) @@ -455,6 +456,7 @@ unsigned do_search(struct FAB *fab,struct WCCFILE *wccfile) wcc->wcd_reslen - 6,".DIR;1",6); } else { sts = RMS$_NMF; + cleanup_wcf(&wccfile); break; /* giveup */ } } @@ -753,7 +755,13 @@ unsigned do_parse(struct FAB *fab,struct WCCFILE **wccret) } if (wccret != NULL) *wccret = wccfile; if (nam != NULL) { - nam->nam$l_wcc = wccfile; + if( (nam->nam$b_nop & NAM$M_SYNCHK) && + !fab->fab$b_dns && !nam->nam$l_rlf ) { + cleanup_wcf(&wccfile); + if( wccret ) *wccret = NULL; + } else { + nam->nam$l_wcc = wccfile; + } } return SS$_NORMAL; } @@ -795,14 +803,21 @@ unsigned sys_setddir(struct dsc_descriptor *newdir,unsigned short *oldlen, sts = sys_parse(&fab); if (sts & STS$M_SUCCESS) { if (nam.nam$b_name + nam.nam$b_type + nam.nam$b_ver > 2) { - return RMS$_DIR; + sts = RMS$_DIR; + } else { + if (nam.nam$l_fnb & NAM$M_WILDCARD) + sts = RMS$_WLD; + else { + default_name = default_buffer; + default_size[0] = nam.nam$b_dev; + default_size[1] = nam.nam$b_dir; + memcpy(default_name + nam.nam$b_dev + nam.nam$b_dir,".;",3); + } } - if (nam.nam$l_fnb & NAM$M_WILDCARD) return RMS$_WLD; - default_name = default_buffer; - default_size[0] = nam.nam$b_dev; - default_size[1] = nam.nam$b_dir; - memcpy(default_name + nam.nam$b_dev + nam.nam$b_dir,".;",3); } + fab.fab$b_dns = 0; + nam.nam$l_rlf = 0; + sys$parse( &fab ); } return sts; } @@ -1473,3 +1488,18 @@ unsigned sys_extend(struct FAB *fab) fab->fab$l_alq - ifi_table[ifi_no]->wcf_fcb->hiblock,0); return sts; } + +/*************************************************************** sys_initialize() */ +static void sys_rundown( void ) { + access_rundown(); + + sysmsg_rundown(); +} + +/*************************************************************** sys_initialize() */ +unsigned sys_initialize( void ) { + if( atexit( sys_rundown ) != 0 ) + return SS$_INSFMEM; + + return SS$_NORMAL; +} diff --git a/extracters/ods2/rms.h b/extracters/ods2/rms.h index b009b86..5775a8e 100644 --- a/extracters/ods2/rms.h +++ b/extracters/ods2/rms.h @@ -15,6 +15,8 @@ #include "vmstime.h" +#define RMS$_FACILITY 1 + #define RMS$_RTB 98728 #define RMS$_EOF 98938 #define RMS$_FNF 98962 @@ -170,10 +172,11 @@ struct NAM { void *nam$l_wcc; int nam$b_nop; int nam$l_fnb; + struct NAM *nam$l_rlf; }; #ifdef RMS$INITIALIZE -struct NAM cc$rms_nam = {0,0,0,0,0,0,0,0,0,0,0,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0,0,0}; +struct NAM cc$rms_nam = {0,0,0,0,0,0,0,0,0,0,0,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0,0,0,NULL}; #else extern struct NAM cc$rms_nam; #endif @@ -317,4 +320,6 @@ unsigned sys_extend(struct FAB *fab); unsigned sys_setddir(struct dsc_descriptor *newdir,unsigned short *oldlen, struct dsc_descriptor *olddir); +unsigned sys_initialize(void); + #endif /* #ifndef _RMS_H */ diff --git a/extracters/ods2/ssdef.h b/extracters/ods2/ssdef.h index c74839e..602f7f2 100644 --- a/extracters/ods2/ssdef.h +++ b/extracters/ods2/ssdef.h @@ -13,6 +13,8 @@ #ifndef _SSDEF_H #define _SSDEF_H +#define SYSTEM$_FACILITY 0 + #define SS$_NORMAL 1 #define SS$_WASCLR 1 #define SS$_WASSET 9 @@ -45,6 +47,7 @@ #define SS$_NOSUCHFILE 2320 #define SS$_NOMOREFILES 2352 #define SS$_ITEMNOTFOUND 2640 +#define SS$_NOMOREDEV 2648 #define SS$_NOSUCHVOL 3882 #define SS$_NOTINSTALL 8212 #define SS$_DEVNOTDISM 8628 diff --git a/extracters/ods2/stsdef.h b/extracters/ods2/stsdef.h index 931cf00..247534c 100644 --- a/extracters/ods2/stsdef.h +++ b/extracters/ods2/stsdef.h @@ -5,6 +5,52 @@ #ifndef _STSDEF_H #define _STSDEF_H -#define STS$M_SUCCESS 1 +#define STS$V_SEVERITY 0 +#define STS$M_SEVERITY 0x00000007 +#define STS$S_SEVERITY 3 +#define STS$V_COND_ID 3 +#define STS$M_COND_ID 0x0FFFFFF8 +#define STS$S_COND_ID 25 +#define STS$V_CONTROL 28 +#define STS$M_CONTROL 0xF0000000 +#define STS$S_CONTROL 4 +#define STS$V_SUCCESS 0 +#define STS$M_SUCCESS 0x01 +#define STS$S_SUCCESS 1 +#define STS$V_MSG_NO 3 +#define STS$M_MSG_NO 0x0000FFF8 +#define STS$S_MSG_NO 13 +#define STS$V_CODE 3 +#define STS$M_CODE 0x00007FF8 +#define STS$S_CODE 12 +#define STS$V_FAC_SP 15 +#define STS$M_FAC_SP 0x00008000 +#define STS$S_FAC_SP 1 +#define STS$V_CUST_DEF 27 +#define STS$M_CUST_DEF 0x08000000 +#define STS$S_CUST_DEF 1 +#define STS$V_INHIB_MSG 28 +#define STS$M_INHIB_MSG 0x10000000 +#define STS$S_INHIB_MSG 1 +#define STS$V_FAC_NO 16 +#define STS$M_FAC_NO 0x0FFF0000 +#define STS$S_FAC_NO 12 + +#define STS$K_WARNING 0 +#define STS$K_SUCCESS 1 +#define STS$K_ERROR 2 +#define STS$K_INFO 3 +#define STS$K_SEVERE 4 + +#define $VMS_STATUS_CODE(code) ( ( (code) & STS$M_CODE ) >> STS$V_CODE ) +#define $VMS_STATUS_COND_ID(code) ( ( (code) & STS$M_COND_ID ) >> STS$V_COND_ID ) +#define $VMS_STATUS_CONTROL(code) ( ( (code) & STS$M_CONTROL ) >> STS$V_CONTROL ) +#define $VMS_STATUS_CUST_DEF(code) ( ( (code) & STS$M_CUST_DEF ) >> STS$V_CUST_DEF ) +#define $VMS_STATUS_FAC_NO(code) ( ( (code) & STS$M_FAC_NO ) >> STS$V_FAC_NO ) +#define $VMS_STATUS_FAC_SP(code) ( ( (code) & STS$M_FAC_SP ) >> STS$V_FAC_SP ) +#define $VMS_STATUS_INHIB_MSG(code) ( ( (code) & STS$M_INHIB_MSG ) >> STS$V_INHIB_MSG ) +#define $VMS_STATUS_MSG_NO(code) ( ( (code) & STS$M_MSG_NO ) >> STS$V_MSG_NO ) +#define $VMS_STATUS_SEVERITY(code) ( ( (code) & STS$M_SEVERITY ) >> STS$V_SEVERITY ) +#define $VMS_STATUS_SUCCESS(code) ( ( (code) & STS$M_SUCCESS ) >> STS$V_SUCCESS ) #endif /* #ifndef _STSDEF_H */ diff --git a/extracters/ods2/sysmsg.c b/extracters/ods2/sysmsg.c index 1731299..a4ad9f6 100644 --- a/extracters/ods2/sysmsg.c +++ b/extracters/ods2/sysmsg.c @@ -1,7 +1,18 @@ /* Timothe Litt litt _at_ acm _ddot_ org */ +/* + 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. +*/ /* Message code translations for non-VMS systems */ +#include +#include #include #include #include @@ -16,83 +27,226 @@ #include "compat.h" #include "sysmsg.h" +#define MSG(code,text) { $VMS_STATUS_COND_ID(code), #code, text }, + +static +const struct VMSFAC { + unsigned int code; + const char *const text; +} fac2text[] = { + { SYSTEM$_FACILITY, "SYSTEM" }, + { RMS$_FACILITY, "RMS" }, + { 0, NULL }, + { 0, "NONAME" } +}; + +static const char sev2text[(STS$M_SEVERITY>>STS$V_SEVERITY)+1] = + { 'W', 'S', 'E', 'I', 'F', '?', '?', '?', }; + +/* Unknown facility or message code */ + +#ifndef SS$_NOMSG +#define SS$_NOMSG 0xFFFFFFFF +#endif + +static const char nofmt[] = "Message number %08X"; +static char notext[sizeof(nofmt)+8]; + static const struct VMSMSG { - unsigned int code; - const char *const text; -} *mp, vms2text[] = { -{RMS$_BUG, "%RMS-F-BUG, fatal RMS condition detected, process deleted"}, -{RMS$_DIR, "%RMS-F-DIR, error in directory name"}, -{RMS$_DNF, "%RMS-E-DNF, directory not found"}, -{RMS$_EOF, "%RMS-E-EOF, end of file detected"}, -{RMS$_ESS, "%RMS-F-ESS, expanded string area too small"}, -{RMS$_FNF, "%RMS-E-FNF, file not found"}, -{RMS$_FNM, "%RMS-F-FNM, error in file name"}, -{RMS$_IFI, "%RMS-F-IFI, invalid internal file identifier (IFI) value"}, -{RMS$_NAM, "%RMS-F-NAM, invalid NAM block or NAM block not accessible"}, -{RMS$_NMF, "%RMS-E-NMF, no more files found"}, -{RMS$_RSS, "%RMS-F-RSS, invalid resultant string size"}, -{RMS$_RSZ, "%RMS-F-RSZ, invalid record size"}, -{RMS$_RTB, "%RMS-W-RTB, !UL byte record too large for user's buffer"}, -{RMS$_WCC, "%RMS-E-WCC, invalid wild card context (WCC) value"}, -{RMS$_WLD, "%RMS-F-WLD, invalid wildcard operation"}, -{SS$_ABORT, "%SYSTEM-F-ABORT, abort"}, -{SS$_BADFILENAME, "%SYSTEM-W-BADFILENAME, bad file name syntax"}, -{SS$_BADIRECTORY, "%SYSTEM-W-BADIRECTORY, bad directory file format"}, -{SS$_BADPARAM, "%SYSTEM-F-BADPARAM, bad parameter value"}, -{SS$_BUGCHECK, "%SYSTEM-F-BUGCHECK, internal consistency failure"}, -{SS$_DATACHECK, "%SYSTEM-F-DATACHECK, write check error"}, -{SS$_DEVICEFULL, "%SYSTEM-W-DEVICEFULL, device full - allocation failure"}, -{SS$_DEVMOUNT, "%SYSTEM-F-DEVMOUNT, device is already mounted"}, -{SS$_DEVNOTALLOC, "%SYSTEM-W-DEVNOTALLOC, device not allocated"}, -{SS$_DEVNOTDISM, "%SYSTEM-F-DEVNOTDISM, device not dismounted"}, -{SS$_DEVNOTMOUNT, "%SYSTEM-F-DEVNOTMOUNT, device is not mounted"}, -{SS$_DUPFILENAME, "%SYSTEM-W-DUPFILENAME, duplicate file name"}, -{SS$_DUPLICATE, "%SYSTEM-F-DUPLNAM, duplicate name"}, -{SS$_ENDOFFILE, "%SYSTEM-W-ENDOFFILE, end of file"}, -{SS$_FILELOCKED, "%SYSTEM-W-FILELOCKED, file is deaccess locked"}, -{SS$_FILESEQCHK, "%SYSTEM-W-FILESEQCHK, file identification sequence number check"}, -{SS$_ILLEFC, "%SYSTEM-F-ILLEFC, illegal event flag cluster"}, -{SS$_INSFMEM, "%SYSTEM-F-INSFMEM, insufficient dynamic memory"}, -{SS$_ITEMNOTFOUND, "%SYSTEM-W-ITEMNOTFOUND, requested item cannot be returned"}, -{SS$_IVCHAN, "%SYSTEM-F-IVCHAN, invalid I/O channel"}, -{SS$_IVDEVNAM, "%SYSTEM-F-IVDEVNAM, invalid device name"}, -{SS$_NOIOCHAN, "%SYSTEM-F-NOIOCHAN, no I/O channel available"}, -{SS$_NOMOREFILES, "%SYSTEM-W-NOMOREFILES, no more files"}, -{SS$_NORMAL, "%SYSTEM-S-NORMAL, normal successful completion"}, -{SS$_NOSUCHDEV, "%SYSTEM-W-NOSUCHDEV, no such device available"}, -{SS$_NOSUCHFILE, "%SYSTEM-W-NOSUCHFILE, no such file"}, -{SS$_NOSUCHVOL, "%SYSTEM-E-NOSUCHVOL, No such volume"}, -{SS$_NOTINSTALL, "%SYSTEM-F-NOTINSTALL, writable shareable images must be installed"}, -{SS$_PARITY, "%SYSTEM-F-PARITY, parity error"}, -{SS$_UNSUPVOLSET, "%SYSTEM-E-UNSUPVOLSET, Volume set not supported"}, -{SS$_WASCLR, "%SYSTEM-S-NORMAL, normal successful completion"}, -{SS$_WASSET, "%SYSTEM-S-WASSET, Event flag was set"}, -{SS$_WRITLCK, "%SYSTEM-F-WRITLCK, write lock error"}, -{SS$_OFFSET_TOO_BIG, "SYSTEM-F-OFFSET_TOO_BIG, Volume is too large for local file system: needs 64-bit I/O" }, -{0, NULL}, - }; + unsigned int code; + const char *const txtcode; + char *text; +} vms2text[] = { + MSG(RMS$_BUG, "fatal RMS condition detected, process deleted") + MSG(RMS$_DIR, "error in directory name") + MSG(RMS$_DNF, "directory not found") + MSG(RMS$_EOF, "end of file detected") + MSG(RMS$_ESS, "expanded string area too small") + MSG(RMS$_FNF, "file not found") + MSG(RMS$_FNM, "error in file name") + MSG(RMS$_IFI, "invalid internal file identifier (IFI) value") + MSG(RMS$_NAM, "invalid NAM block or NAM block not accessible") + MSG(RMS$_NMF, "no more files found") + MSG(RMS$_RSS, "invalid resultant string size") + MSG(RMS$_RSZ, "invalid record size") + MSG(RMS$_RTB, "%u byte record too large for user's buffer") /* !UL byte */ + MSG(RMS$_WCC, "invalid wild card context (WCC) value") + MSG(RMS$_WLD, "invalid wildcard operation") + MSG(SS$_ABORT, "abort") + MSG(SS$_BADFILENAME, "bad file name syntax") + MSG(SS$_BADIRECTORY, "bad directory file format") + MSG(SS$_BADPARAM, "bad parameter value") + MSG(SS$_BUGCHECK, "internal consistency failure") + MSG(SS$_DATACHECK, "write check error") + MSG(SS$_DEVICEFULL, "device full - allocation failure") + MSG(SS$_DEVMOUNT, "device is already mounted") + MSG(SS$_DEVNOTALLOC, "device not allocated") + MSG(SS$_DEVNOTDISM, "device not dismounted") + MSG(SS$_DEVNOTMOUNT, "device is not mounted") + MSG(SS$_DUPFILENAME, "duplicate file name") + MSG(SS$_DUPLICATE, "duplicate name") + MSG(SS$_ENDOFFILE, "end of file") + MSG(SS$_FILELOCKED, "file is deaccess locked") + MSG(SS$_FILESEQCHK, "file identification sequence number check") + MSG(SS$_ILLEFC, "illegal event flag cluster") + MSG(SS$_INSFMEM, "insufficient dynamic memory") + MSG(SS$_ITEMNOTFOUND, "requested item cannot be returned") + MSG(SS$_NOMOREDEV, "no more devices") + MSG(SS$_IVCHAN, "invalid I/O channel") + MSG(SS$_IVDEVNAM, "invalid device name") + MSG(SS$_NOIOCHAN, "no I/O channel available") + MSG(SS$_NOMOREFILES, "no more files") + MSG(SS$_NORMAL, "normal successful completion") + MSG(SS$_NOSUCHDEV, "no such device available") + MSG(SS$_NOSUCHFILE, "no such file") + MSG(SS$_NOSUCHVOL, "No such volume") + MSG(SS$_NOTINSTALL, "writable shareable images must be installed") + MSG(SS$_PARITY, "parity error") + MSG(SS$_UNSUPVOLSET, "Volume set not supported") + MSG(SS$_WASCLR, "normal successful completion") + MSG(SS$_WASSET, "Event flag was set") + MSG(SS$_WRITLCK, "write lock error") + MSG(SS$_OFFSET_TOO_BIG, "Volume is too large for local file system: needs 64-bit I/O" ) + {0, NULL, NULL}, + { SS$_NOMSG, "SS$_NOMSG", notext } +}; -const char *getmsg( unsigned int vmscode, unsigned int flags ) { - const char fmt[] = "%%SYSTEM-E-NOSUCHMSG, Unknown message code %08X"; - static char buf[sizeof(fmt)+8+1]; - const char *txtp = NULL; +static char *buf = NULL; +static size_t bufsize = 0; - for( mp = vms2text; mp->text; mp++ ) { - if( vmscode == mp-> code ) { - txtp = mp->text; - break; - } +/******************************************************************* xpand() */ + +static int xpand( size_t used, size_t add ) { + char *nbuf; + size_t need; + + need = used + add + 1; /* Always allow for \0 */ + if( need < bufsize ) { + return 1; } - if( txtp == NULL ) { - txtp = buf; + nbuf = realloc( buf, need + 16 + 1); /* 16 minimizes reallocs */ + if( nbuf == NULL ) { + return 0; } - if( flags == MSG_TEXT ) { - txtp = strchr( txtp, ',' ); - if( txtp == NULL ) abort(); - return txtp+2; + buf = nbuf; + bufsize = need + 16 + 1; + return 1; +} + +/******************************************************************* getmsg() */ + +const char *getmsg( unsigned int vmscode, unsigned int flags, ... ) { + const struct VMSMSG *mp = NULL; + const struct VMSFAC *fp = NULL; + + if( !(flags & MSG_FULL) ) + flags = (flags & ~MSG_FULL) | MSG_FULL; + + while( 1 ) { + size_t i = 0, len; + + do { + if( flags & (MSG_FACILITY|MSG_SEVERITY|MSG_NAME) ) { + if( !xpand( i, 1 ) ) + return strerror( errno ); + buf[i++] = '%'; + + if( fp == NULL ) { + for( fp = fac2text; fp->text != NULL; fp++ ) { + if( fp->code == $VMS_STATUS_FAC_NO(vmscode) ) + break; + } + } + if( fp->text == NULL ) + break; + if( flags & MSG_FACILITY ) { + len = strlen( fp->text ); + if( !xpand( i, len +1 ) ) + return strerror( errno ); + + memcpy( buf+i, fp->text, len ); + i += len; + if( flags & (MSG_SEVERITY|MSG_NAME) ) + buf[i++] = '-'; + } + if( flags & MSG_SEVERITY ) { + if( !xpand( i, 2 ) ) + return strerror( errno ); + buf[i++] = sev2text[$VMS_STATUS_SEVERITY(vmscode)]; + if( flags & MSG_NAME ) + buf[i++] = '-'; + } + if( flags & MSG_NAME ) { + char *p; + + if( mp == NULL ) { + for( mp = vms2text; mp->text != NULL; mp++ ) { + if( $VMS_STATUS_COND_ID(vmscode) == mp-> code ) + break; + } + } + if( mp->text == NULL ) + break; + p = strchr( mp->txtcode, '_' ); + if( p == NULL ) + abort(); + len = strlen( ++p ); + if( !xpand( i, len ) ) + return strerror( errno ); + memcpy( buf+i, p, len ); + i += len; + } + if( flags & MSG_TEXT ) { + if( !xpand( i, 2 ) ) + return strerror( errno ); + buf[i++] = ','; + buf[i++] = ' '; + } + } + if( flags & MSG_TEXT ) { + va_list ap; + if( mp == NULL ) { + for( mp = vms2text; mp->text; mp++ ) { + if( $VMS_STATUS_COND_ID(vmscode) == mp-> code ) + break; + } + if( mp->text == NULL ) + break; + } + if( flags & MSG_WITHARGS ) { + va_start( ap, flags ); + len = vsnprintf( buf+i, 1, mp->text, ap ); + va_end( ap ); + } else + len = strlen( mp->text ); + if( !xpand( i, len ) ) + return strerror( errno ); + if( flags & MSG_WITHARGS ) { + va_start( ap, flags ); + (void) vsnprintf( buf+i, len+1, mp->text, ap ); + va_end( ap ); + } else + memcpy( buf+i, mp->text, len ); + i += len; + } + buf[i] = '\0'; + return buf; + } while( 0 ); + + if( fp == NULL || fp->text == NULL ) + fp = fac2text + (sizeof(fac2text)/sizeof(fac2text[0])) -1; + + mp = vms2text + (sizeof(vms2text)/sizeof(vms2text[0])) -1; + snprintf( notext, sizeof(notext), nofmt, vmscode ); } - return txtp; +} + +/******************************************************************* sysmsg_rundown() */ + +void sysmsg_rundown( void ) { + free( buf ); + buf = NULL; } /* diff --git a/extracters/ods2/sysmsg.h b/extracters/ods2/sysmsg.h index cf46ca7..b8f4a04 100644 --- a/extracters/ods2/sysmsg.h +++ b/extracters/ods2/sysmsg.h @@ -1,8 +1,18 @@ #ifndef SYSMSG_H #define SYSMSG_H -#define MSG_TEXT 0 -#define MSG_FULL 1 -const char *getmsg( unsigned int vmscode, unsigned int flags ); +#include + +#define MSG_FACILITY (1 << 0) +#define MSG_SEVERITY (1 << 1) +#define MSG_NAME (1 << 2) +#define MSG_TEXT (1 << 3) +#define MSG_WITHARGS (1 << 4) + +#define MSG_FULL (MSG_FACILITY|MSG_SEVERITY|MSG_NAME|MSG_TEXT) + +const char *getmsg( unsigned int vmscode, unsigned int flags, ... ); + +void sysmsg_rundown( void ); #endif diff --git a/extracters/ods2/valgrind_suppressions_ods2 b/extracters/ods2/valgrind_suppressions_ods2 new file mode 100644 index 0000000..6d39ba5 --- /dev/null +++ b/extracters/ods2/valgrind_suppressions_ods2 @@ -0,0 +1,2 @@ +# suppression rules for ods2 +# The goal is that there aren't any. diff --git a/extracters/ods2/valgrind_suppressions_readline b/extracters/ods2/valgrind_suppressions_readline new file mode 100644 index 0000000..470c88e --- /dev/null +++ b/extracters/ods2/valgrind_suppressions_readline @@ -0,0 +1,46 @@ +# Suppression rules for users of readline +# This attempts to suppress the stuff that +# readline creates from termcap, etc, while +# still tracking the data returned to the caller. +# +# Most history memory can be released with the +# clear_history() call - after write_history +# if desired. However, the master history +# structure remains. Don't know how to +# distinguish the two, so the history calls +# that add lines are suppressed. Note +# that read_history calls add_history internally. + +{ + history + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:add_history +} +{ + readline + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:rl_initialize + ... + fun:readline +} +{ + readline + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:init_line_structures + ... + fun:readline +} +{ + readline + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:rl_set_prompt + fun:readline +}