/*****************************************************************************/ /* sysPLUS.c Show essential system data without using a scripting process as does WatchShowSystem(). It is intended as a fallback should the creation of a scripting process fail (for example; no remaining process slot, insufficient paged dynamic memory), providing essential data useful for trouble-shooting. It can also be activated using the URI /httpd/-/admin/report/system+. And also via the CLI with |rqptr| NULL which FaoToEither() handles. I have experienced both. See sysPlusNet() for usage of logical name WASD_SYSPLUS_NI. EXE$GETSPI ---------- What a dog's breakfast $GETRMI seems to be. With MonDeSi it just seemed too difficult to get consistent results across versions and platforms so I went back to EXE$GETSPI and have arrived at the same conclusion again this time. RMI$_SCS on Alpha VMS V8.3 and IA64 VSI V8.4 returns %X00000014 (%SYSTEM-F-BADPARAM, bad parameter value) when using this item. (Same on VAX V7.3 - but absolutely anything that works on VAX too is a bonus). Using this item with $GETSPI no problems. VERSION HISTORY --------------- 20-JUL-2019 MGD expand to include network, MSCP and SCS data dignified with a module of its very own adapt to allow use via CLI /SYSPLUS 25-AUG-2018 MGD initial as WatchSystemPlus() et.al. */ /*****************************************************************************/ #ifdef WASD_VMS_V7 #undef _VMS__V6__SOURCE #define _VMS__V6__SOURCE #undef __VMS_VER #define __VMS_VER 70000000 #undef __CRTL_VER #define __CRTL_VER 70000000 #endif /* standard C header files */ #include #include #include #include #include /* VMS related header files */ #include #include #include #include #include #include #include #include #include #include #include #include /* application related header files */ #include "wasd.h" #define WASD_MODULE "SYSPLUS" #define DBUG 0 /* last for selected data */ #define NUM_MINS 10 /* 96 is (still) the SPD cluster node limit (we had 70+ in the '90s :-) */ #define SCS_NODES_MAX 16 #ifndef WASD_GETSPI #define WASD_GETSPI 0 #endif /******************/ /* global storage */ /******************/ static ulong sysPlusRmiMemErrs; /********************/ /* external storage */ /********************/ extern int EfnWait, HttpdTickSecond; extern ulong MailboxMask[]; extern SYS_INFO SysInfo; extern WATCH_STRUCT Watch; /*****************************************************************************/ /* Report wrapper. */ void sysPlusReport (REQUEST_STRUCT *rqptr) { static $DESCRIPTOR (SystemFaoDsc, "!AZ, a !AZ with !UL CPU and !AZ running VMS !AZ"); static char UnderFao [] = "!AZ\n!#*-\nCurrent: !20%D Boot: !20%D Up: !%D\n\n"; static int64 SyiBootTime64, Time64, UpTime64; static VMS_ITEM_LIST3 SyiItem [] = { { sizeof(SyiBootTime64), SYI$_BOOTTIME, &SyiBootTime64, 0 }, { 0,0,0,0 } }; BOOL Not200; int status; ushort slen; char SystemBuffer [256]; IO_SB IOsb; $DESCRIPTOR (SystemBufferDsc, SystemBuffer); /*********/ /* begin */ /*********/ Not200 = true; if (rqptr) { if (Not200 = (rqptr->rqResponse.HttpStatus != 200)) { rqptr->rqResponse.PreExpired = PRE_EXPIRE_ADMIN; ResponseHeader200 (rqptr, "text/plain", NULL); } } status = sys$getsyiw (EfnWait, 0, 0, &SyiItem, &IOsb, 0, 0); if (VMSok (status)) status = IOsb.Status; if (VMSnok (status)) { FaoToEither (rqptr, "$GETSYI() !&S\n", status); return; } sys$gettim (&Time64); UpTime64 = SyiBootTime64 - Time64; status = sys$fao (&SystemFaoDsc, &slen, &SystemBufferDsc, SysInfo.NodeName, SysInfo.HwName, SysInfo.AvailCpuCnt, SysInfo.MemoryMBGB, SysInfo.Version); SystemBuffer[slen] = '\0'; if (VMSnok (status)) FaoToEither (rqptr, "$FAO() !&S\n", status); status = FaoToEither (rqptr, &UnderFao, SystemBuffer, slen, &Time64, &SyiBootTime64, &UpTime64); if (VMSnok (status)) FaoToEither (rqptr, "$FAO() !&S\n", status); if (!rqptr) { /* at the command-line take a ten second sample of CPU consumption */ sysPlusRmi ((REQUEST_STRUCT*)-1); sleep (10); /* force that sample up into the first "minute" buffer */ sysPlusRmi ((REQUEST_STRUCT*)-1); } sysPlusRmi (rqptr); sysPlusSyi (rqptr); sysPlusScs (rqptr); sysPlusMscp (rqptr); sysPlusDvi (rqptr); sysPlusNet (rqptr); sysPlusJpi (rqptr); if (Not200) { FaoToEither (rqptr, "!77*-\n\n", SystemBuffer, slen); if (rqptr) AdminEnd (rqptr); } } /*****************************************************************************/ /* Provide device data. */ void sysPlusDvi (REQUEST_STRUCT *rqptr) { #define DC$_DISK 1 #define DEV$V_NET 0x2000 static char DviHeader [] = "Device Name Errs Refs Ops Status\n\ ~~~~~~~~~~~~~~~ ~~~~~ ~~~~~ ~~~~~~~~~~ ~~~~~~\n"; static char DeviceFao [] = "!#AZ !5UL !5UL !10UL !AZ\n\ !#* !5AZ!17* !AZ\n"; static char NetSpeedFao [] = "!#* !AZ !AZ !ULMbpS\n", NetNoSpeedFao [] = "!#* !AZ !AZ\n"; static char DiskFao [] = "!#* \"!AZ\" !AZ free of !AZ (!UL%)\n"; static $DESCRIPTOR (SearchDeviceDsc, "*"); static ulong DviDevClass, DviDevChar, DviDevChar2, DviErrCnt, DviFreeBlocks, DviLanLinkStateValid, DviLanLinkUp, DviLanSpeed, DviMaxBlock, DviOpCnt, DviPid, DviRefCnt, DviSts; static ushort DviDevTypeNameLen, DviVolNamLen; static char DviDevTypeName [64+1], DviVolNam [15+1]; static struct { ushort buf_len; ushort item; uchar *buf_addr; ushort *short_ret_len; } DviItems [] = { { sizeof(DviDevClass), DVI$_DEVCLASS, &DviDevClass, 0 }, { sizeof(DviDevChar), DVI$_DEVCHAR, &DviDevChar, 0 }, { sizeof(DviDevChar2), DVI$_DEVCHAR2, &DviDevChar2, 0 }, { sizeof(DviErrCnt), DVI$_ERRCNT, &DviErrCnt, 0 }, { sizeof(DviFreeBlocks), DVI$_FREEBLOCKS, &DviFreeBlocks, 0 }, #if(__VMS_VER >= 80000000)) { sizeof(DviLanLinkStateValid), DVI$_LAN_LINK_STATE_VALID, &DviLanLinkStateValid, 0 }, { sizeof(DviLanLinkUp), DVI$_LAN_LINK_UP, &DviLanLinkUp, 0 }, { sizeof(DviLanSpeed), DVI$_LAN_SPEED, &DviLanSpeed, 0 }, #endif { sizeof(DviMaxBlock), DVI$_MAXBLOCK, &DviMaxBlock, 0 }, { sizeof(DviDevTypeName)-1, DVI$_DEVICE_TYPE_NAME, &DviDevTypeName, &DviDevTypeNameLen}, { sizeof(DviOpCnt), DVI$_OPCNT, &DviOpCnt, 0 }, { sizeof(DviPid), DVI$_PID, &DviPid, 0 }, { sizeof(DviRefCnt), DVI$_REFCNT, &DviRefCnt, 0 }, { sizeof(DviSts), DVI$_STS, &DviSts, 0 }, { sizeof(DviVolNam)-1, DVI$_VOLNAM, &DviVolNam, &DviVolNamLen }, { 0,0,0,0 } }; int status; uint64 context64; ushort slen; double freefp, sizefp; char DevCharBuf [256], DevName [64+1], DevStsBuf [256], FreeBuf [32], SizeBuf [32]; $DESCRIPTOR (DevNameDsc, DevName); $DESCRIPTOR (ScanNameDsc, DevName); IO_SB IOsb; /*********/ /* begin */ /*********/ FaoToEither (rqptr, DviHeader); context64 = 0; for (;;) { status = sys$device_scan (&ScanNameDsc, &slen, &SearchDeviceDsc, 0, &context64); if (VMSnok (status)) { if (status != SS$_NOMOREDEV) FaoToEither (rqptr, "$DEVICE_SCAN() !&S\n", status); break; } DevName[slen] = '\0'; DevNameDsc.dsc$w_length = slen; if (MATCH3 (DevName, "_BG") && !MATCH5 (DevName, "_BG0:")) continue; if (strstr (DevName, "$BG")) continue; if (MATCH3 (DevName, "_MB")) continue; if (strstr (DevName, "$MB")) continue; status = sys$getdviw (EfnWait, 0, &DevNameDsc, &DviItems, &IOsb, 0, 0, 0, 0); if (VMSok (status)) status = IOsb.Status; if (VMSnok (status)) { if (status != SS$_NOMOREDEV) FaoToEither (rqptr, "$GETDVI() !&S\n", status); break; } DevStsBuf[0] = '\0'; if (DviSts & 0x1) strcat (DevStsBuf, " tim"); if (DviSts & 0x2) strcat (DevStsBuf, " int"); if (DviSts & 0x4) strcat (DevStsBuf, " erlogip"); if (DviSts & 0x8) strcat (DevStsBuf, " cancel"); if (DviSts & 0x10) strcat (DevStsBuf, " ONLINE"); else strcat (DevStsBuf, " OFFLINE"); if (DviSts & 0x20) strcat (DevStsBuf, " power"); if (DviSts & 0x40) strcat (DevStsBuf, " TIMEOUT"); if (DviSts & 0x80) strcat (DevStsBuf, " inttype"); if (DviSts & 0x100) strcat (DevStsBuf, " busy"); if (DviSts & 0x200) strcat (DevStsBuf, " mounting"); if (DviSts & 0x400) strcat (DevStsBuf, " deadmo"); if (DviSts & 0x800) strcat (DevStsBuf, " valid"); if (DviSts & 0x1000) strcat (DevStsBuf, " unload"); if (DviSts & 0x2000) strcat (DevStsBuf, " template"); if (DviSts & 0x4000) strcat (DevStsBuf, " MNTVERIP"); if (DviSts & 0x8000) strcat (DevStsBuf, " WRONGVOL"); if (DviSts & 0x10000) strcat (DevStsBuf, " deleteucb"); if (DviSts & 0x20000) strcat (DevStsBuf, " lclvalid"); if (DviSts & 0x40000) strcat (DevStsBuf, " supmvmsg"); if (DviSts & 0x80000) strcat (DevStsBuf, " MNTVERPND"); if (DviSts & 0x100000) strcat (DevStsBuf, " dismount"); if (DviSts & 0x200000) strcat (DevStsBuf, " clutran"); if (DviSts & 0x400000) strcat (DevStsBuf, " wrtlockmv"); if (DviSts & 0x800000) strcat (DevStsBuf, " svpnend"); if (DviSts & 0x1000000) strcat (DevStsBuf, " altbsy"); if (DviSts & 0x2000000) strcat (DevStsBuf, " snapshot"); if (DviSts & 0x4000000) strcat (DevStsBuf, " noassign"); if (DviSts & 0x8000000) strcat (DevStsBuf, " exfuncsupp"); if (DviSts & 0x1000000) strcat (DevStsBuf, " fastpath"); if (DviSts & 0x2000000) strcat (DevStsBuf, " pathverip"); if (DviSts & 0x4000000) strcat (DevStsBuf, " fphwint"); if (DviSts & 0x8000000) strcat (DevStsBuf, " iopostlocal"); strncpy (DevCharBuf, DviDevTypeName, DviDevTypeNameLen); DevCharBuf[DviDevTypeNameLen] = ':'; DevCharBuf[DviDevTypeNameLen+1] = '\0'; if (DviDevChar & 0x1) strcat (DevCharBuf, " rec"); if (DviDevChar & 0x2) strcat (DevCharBuf, " ccl"); if (DviDevChar & 0x4) strcat (DevCharBuf, " TERMINAL"); if (DviDevChar & 0x8) strcat (DevCharBuf, " dir"); if (DviDevChar & 0x10) strcat (DevCharBuf, " sdi"); if (DviDevChar & 0x20) strcat (DevCharBuf, " sqd"); if (DviDevChar & 0x40) strcat (DevCharBuf, " spl"); if (DviDevChar & 0x80) strcat (DevCharBuf, " opr"); if (DviDevChar & 0x100) strcat (DevCharBuf, " rct"); if (DviDevChar & 0x200) strcat (DevCharBuf, " qsvd"); if (DviDevChar & 0x400) strcat (DevCharBuf, " qsvbl"); if (DviDevChar & 0x800) strcat (DevCharBuf, " mpdev_sec"); if (DviDevChar & 0x1000) strcat (DevCharBuf, " mpdev_mem"); if (DviDevChar & 0x2000) strcat (DevCharBuf, " NETWORK"); if (DviDevChar & 0x4000) strcat (DevCharBuf, " fod"); if (DviDevChar & 0x8000) strcat (DevCharBuf, " dua"); if (DviDevChar & 0x10000) strcat (DevCharBuf, " shr"); if (DviDevChar & 0x20000) strcat (DevCharBuf, " gen"); if (DviDevChar & 0x40000) strcat (DevCharBuf, " avl"); if (DviDevChar & 0x80000) strcat (DevCharBuf, " MOUNTED"); if (DviDevChar & 0x100000) strcat (DevCharBuf, " mbx"); if (DviDevChar & 0x200000) strcat (DevCharBuf, " DMT"); if (DviDevChar & 0x400000) strcat (DevCharBuf, " elg"); if (DviDevChar & 0x800000) strcat (DevCharBuf, " all"); if (DviDevChar & 0x1000000) strcat (DevCharBuf, " for"); if (DviDevChar & 0x2000000) strcat (DevCharBuf, " swl"); if (DviDevChar & 0x4000000) strcat (DevCharBuf, " idv"); if (DviDevChar & 0x8000000) strcat (DevCharBuf, " odv"); if (DviDevChar & 0x1000000) strcat (DevCharBuf, " rnd"); if (DviDevChar & 0x2000000) strcat (DevCharBuf, " rtm"); if (DviDevChar & 0x4000000) strcat (DevCharBuf, " rck"); if (DviDevChar & 0x8000000) strcat (DevCharBuf, " wck"); if (DviDevChar2 & 0x1) strcat (DevCharBuf, " clu"); if (DviDevChar2 & 0x2) strcat (DevCharBuf, " det"); if (DviDevChar2 & 0x4) strcat (DevCharBuf, " rtt"); if (DviDevChar2 & 0x8) strcat (DevCharBuf, " cdp"); if (DviDevChar2 & 0x10) strcat (DevCharBuf, " 2p"); if (DviDevChar2 & 0x20) strcat (DevCharBuf, " mscp"); if (DviDevChar2 & 0x40) strcat (DevCharBuf, " ssm"); if (DviDevChar2 & 0x80) strcat (DevCharBuf, " srv"); if (DviDevChar2 & 0x100) strcat (DevCharBuf, " red"); if (DviDevChar2 & 0x200) strcat (DevCharBuf, " nnm"); if (DviDevChar2 & 0x400) strcat (DevCharBuf, " wbc"); if (DviDevChar2 & 0x800) strcat (DevCharBuf, " wtc"); if (DviDevChar2 & 0x1000) strcat (DevCharBuf, " hoc"); if (DviDevChar2 & 0x2000) strcat (DevCharBuf, " loc"); if (DviDevChar2 & 0x4000) strcat (DevCharBuf, " dfs"); if (DviDevChar2 & 0x8000) strcat (DevCharBuf, " dap"); if (DviDevChar2 & 0x10000) strcat (DevCharBuf, " nlt"); if (DviDevChar2 & 0x20000) strcat (DevCharBuf, " sex"); if (DviDevChar2 & 0x40000) strcat (DevCharBuf, " shd"); if (DviDevChar2 & 0x80000) strcat (DevCharBuf, " vrt"); if (DviDevChar2 & 0x100000) strcat (DevCharBuf, " ldr"); if (DviDevChar2 & 0x200000) strcat (DevCharBuf, " nolb"); if (DviDevChar2 & 0x400000) strcat (DevCharBuf, " noclu"); if (DviDevChar2 & 0x800000) strcat (DevCharBuf, " vmem"); if (DviDevChar2 & 0x1000000) strcat (DevCharBuf, " scsi"); if (DviDevChar2 & 0x2000000) strcat (DevCharBuf, " wlg"); if (DviDevChar2 & 0x4000000) strcat (DevCharBuf, " nofe"); if (DviDevChar2 & 0x8000000) strcat (DevCharBuf, " 0x8000000"); if (DviDevChar2 & 0x1000000) strcat (DevCharBuf, " cramio"); if (DviDevChar2 & 0x2000000) strcat (DevCharBuf, " dtn"); if (DviDevChar2 & 0x4000000) strcat (DevCharBuf, " 0x40000000"); if (DviDevChar2 & 0x8000000) strcat (DevCharBuf, " pool_mbr"); FaoToEither (rqptr, DeviceFao, slen > 15 ? slen : 15, DevName+1, DviErrCnt, DviRefCnt, DviOpCnt, DevStsBuf+1, slen > 15 ? slen : 15, DviErrCnt ? "^^^^^" : " ", DevCharBuf); if (DviDevClass == DC$_DISK) { if (DviVolNamLen) { DviVolNam[DviVolNamLen] = '\0'; sizefp = (double)DviMaxBlock * 512.0 / 1073741824.0; freefp = (double)DviFreeBlocks * 512.0 / 1073741824.0; sprintf (SizeBuf, "%.2fGB", sizefp); sprintf (FreeBuf, "%.2fGB", freefp); FaoToEither (rqptr, DiskFao, slen > 39 ? slen+20 : 39, DviVolNam, FreeBuf, SizeBuf, (int)(freefp * 100.0 / sizefp)); } } else if (DviDevChar & DEV$V_NET) { if (DviLanSpeed) FaoToEither (rqptr, NetSpeedFao, slen > 39 ? slen+20 : 39, DviLanLinkStateValid ? "valid" : "invalid", DviLanLinkUp ? "UP" : "DOWN", DviLanSpeed); else FaoToEither (rqptr, NetNoSpeedFao, slen > 39 ? slen+20 : 39, DviLanLinkStateValid ? "valid" : "invalid", DviLanLinkUp ? "UP" : "DOWN"); } } FaoToEither (rqptr, "\n"); } /*****************************************************************************/ /* Provide process data. */ #define PSCAN$_GETJPI_BUFFER_SIZE 24 void sysPlusJpi (REQUEST_STRUCT *rqptr) { /* e.g. U-S-E-K- U+S-E-K- U^S-E-K- */ #define ASTFLG(bit,idx) { if (JpiAstEn & bit) if (JpiAstAct & bit) \ AstFlags[idx] = '^'; else AstFlags[idx] = '+'; \ else AstFlags[idx] = '-'; } static char JpiHeader [] = "PID Process Name Prior I/O CPU \ Page flts file State\n\ ~~~~~~~~ Username ~~~~~~ Image !46*~\n"; static char ProcessFao [] = "!8XL !15AZ !5 !9UL !3UL !2ZL:!2ZL:!2ZL.!2ZL !9UL !3UL% !AZ\n\\ !15AZ !AZ\n"; static ulong GetJpiControlFlags = JPI$M_IGNORE_TARGET_STATUS; static ulong JpiAstAct, JpiAstEn, JpiBufIo, JpiCpuTim, JpiDirIo, JpiJobType, JpiMode, JpiPagFilCnt, JpiPageFlts, JpiPgFlQuota, JpiPid, JpiPri, JpiPrib, JpiState, JpiSts, JpiSts2; static char JpiImagName [256], JpiNodeName [32], JpiPrcNam [16], JpiUserName [13]; static struct { ushort buf_len; ushort item; uchar *buf_addr; ushort *short_ret_len; } JpiItems [] = { { sizeof(GetJpiControlFlags), JPI$_GETJPI_CONTROL_FLAGS, &GetJpiControlFlags, 0 }, { sizeof(JpiAstAct), JPI$_ASTACT, &JpiAstAct, 0 }, { sizeof(JpiAstEn), JPI$_ASTEN, &JpiAstEn, 0 }, { sizeof(JpiBufIo), JPI$_BUFIO, &JpiBufIo, 0 }, { sizeof(JpiCpuTim), JPI$_CPUTIM, &JpiCpuTim, 0 }, { sizeof(JpiDirIo), JPI$_DIRIO, &JpiDirIo, 0 }, { sizeof(JpiImagName), JPI$_IMAGNAME, &JpiImagName, 0 }, { sizeof(JpiJobType), JPI$_JOBTYPE, &JpiJobType, 0 }, { sizeof(JpiMode), JPI$_MODE, &JpiMode, 0 }, { sizeof(JpiPageFlts), JPI$_PAGEFLTS, &JpiPageFlts, 0 }, { sizeof(JpiPgFlQuota), JPI$_PGFLQUOTA, &JpiPgFlQuota, 0 }, { sizeof(JpiPagFilCnt), JPI$_PAGFILCNT, &JpiPagFilCnt, 0 }, { sizeof(JpiPrcNam), JPI$_PRCNAM, &JpiPrcNam, 0 }, { sizeof(JpiPid), JPI$_PID, &JpiPid, 0 }, { sizeof(JpiPri), JPI$_PRI, &JpiPri, 0 }, { sizeof(JpiPrib), JPI$_PRIB, &JpiPrib, 0 }, { sizeof(JpiState), JPI$_STATE, &JpiState, 0 }, { sizeof(JpiSts), JPI$_STS, &JpiSts, 0 }, { sizeof(JpiSts2), JPI$_STS, &JpiSts2, 0 }, { sizeof(JpiUserName), JPI$_USERNAME, &JpiUserName, 0 }, { 0,0,0,0 } }, ScanItems [] = { { 0, PSCAN$_GETJPI_BUFFER_SIZE, 2048, 0}, { 0,0,0,0 } }; int idx, status, IdentCount, ProcessCount, SetPrvStatus; ulong *vecptr; ulong ProcessContext; ulong FaoVector [32]; char *cptr, *sptr; char AstFlags [16], ProcFlags [512]; IO_SB IOsb; /*********/ /* begin */ /*********/ if (WATCH_MODULE(WATCH_MOD__OTHER)) WatchThis (WATCHALL, WATCH_MOD__OTHER, "sysPlusJpi()"); ProcessContext = 0; status = sys$process_scan (&ProcessContext, &ScanItems); if (VMSnok (status)) { FaoToEither (rqptr, "$PROCESS_SCAN() !&S\n", status); return; } if (VMSnok (SetPrvStatus = sys$setprv (1, &MailboxMask, 0, 0))) ErrorExitVmsStatus (SetPrvStatus, "sys$setprv()", FI_LI); ProcessCount = 0; FaoToEither (rqptr, JpiHeader); for (;;) { status = sys$getjpiw (EfnWait, &ProcessContext, 0, &JpiItems, &IOsb, 0, 0); if (VMSok (status)) status = IOsb.Status; if (VMSnok (status)) { if (status != SS$_NOMOREPROC) FaoToEither (rqptr, "$GETJPI() !&S\n", status); break; } JpiPrcNam[15] = '\0'; for (cptr = JpiPrcNam; *cptr && *cptr != ' '; cptr++); *cptr = '\0'; JpiUserName[12] = '\0'; for (cptr = JpiUserName; *cptr && *cptr != ' '; cptr++); *cptr = '\0'; ProcFlags[0] = '\0'; switch (JpiState) { case 1 : strcat (ProcFlags, "COLPG"); break; case 2 : strcat (ProcFlags, "MWAIT"); break; case 3 : strcat (ProcFlags, "CEF"); break; case 4 : strcat (ProcFlags, "PFW"); break; case 5 : strcat (ProcFlags, "LEF"); break; case 6 : strcat (ProcFlags, "LEFO"); break; case 7 : strcat (ProcFlags, "HIB"); break; case 8 : strcat (ProcFlags, "HIBO"); break; case 9 : strcat (ProcFlags, "SUSP"); break; case 10 : strcat (ProcFlags, "SUSPO"); break; case 11 : strcat (ProcFlags, "FPG"); break; case 12 : strcat (ProcFlags, "COM"); break; case 13 : strcat (ProcFlags, "COMO"); break; case 14 : strcat (ProcFlags, "CUR"); break; default : strcat (ProcFlags, "?"); } strcat (ProcFlags, "\n "); switch (JpiMode) { case 0 : strcat (ProcFlags, "other"); break; case 1 : strcat (ProcFlags, "network"); break; case 2 : strcat (ProcFlags, "batch"); break; case 3 : strcat (ProcFlags, "interactive"); break; default : strcat (ProcFlags, "?"); } switch (JpiJobType) { case 0 : strcat (ProcFlags, ":detached"); break; case 1 : strcat (ProcFlags, ":network"); break; case 2 : strcat (ProcFlags, ":batch"); break; case 3 : strcat (ProcFlags, ":local"); break; case 4 : strcat (ProcFlags, ":dialup"); break; case 5 : strcat (ProcFlags, ":remote"); break; default : strcat (ProcFlags, ":?"); } /* AST flags */ AstFlags[0] = ' '; AstFlags[1] = 'U'; ASTFLG(1,2) AstFlags[3] = 'S'; ASTFLG(2,4) AstFlags[5] = 'E'; ASTFLG(4,6) AstFlags[7] = 'K'; ASTFLG(8,8) AstFlags[9] = '\0'; strcat (ProcFlags, AstFlags); if (JpiSts & 0x1) strcat (ProcFlags, " res"); if (JpiSts & 0x2) strcat (ProcFlags, " delpen"); if (JpiSts & 0x4) strcat (ProcFlags, " forcpen"); if (JpiSts & 0x8) strcat (ProcFlags, " inquan"); if (JpiSts & 0x10) strcat (ProcFlags, " pswapm"); if (JpiSts & 0x20) strcat (ProcFlags, " respen"); if (JpiSts & 0x40) strcat (ProcFlags, " ssfexc"); if (JpiSts & 0x80) strcat (ProcFlags, " ssfexce"); if (JpiSts & 0x100) strcat (ProcFlags, " ssfexcs"); if (JpiSts & 0x200) strcat (ProcFlags, " ssfexcu"); if (JpiSts & 0x400) strcat (ProcFlags, " ssrwait"); if (JpiSts & 0x800) strcat (ProcFlags, " suspen"); if (JpiSts & 0x2000) strcat (ProcFlags, " wall"); if (JpiSts & 0x4000) strcat (ProcFlags, " batch"); if (JpiSts & 0x8000) strcat (ProcFlags, " noacnt"); if (JpiSts & 0x10000) strcat (ProcFlags, " nosuspend"); if (JpiSts & 0x20000) strcat (ProcFlags, " astpen"); if (JpiSts & 0x40000) strcat (ProcFlags, " phdres"); if (JpiSts & 0x80000) strcat (ProcFlags, " hiber"); if (JpiSts & 0x100000) strcat (ProcFlags, " login"); if (JpiSts & 0x200000) strcat (ProcFlags, " netwrk"); if (JpiSts & 0x400000) strcat (ProcFlags, " pwrast"); if (JpiSts & 0x800000) strcat (ProcFlags, " nodelet"); if (JpiSts & 0x1000000) strcat (ProcFlags, " disaws"); if (JpiSts & 0x2000000) strcat (ProcFlags, " inter"); if (JpiSts & 0x4000000) strcat (ProcFlags, " recover"); if (JpiSts & 0x8000000) strcat (ProcFlags, " 0x8000000"); if (JpiSts & 0x1000000) strcat (ProcFlags, " hardaff"); if (JpiSts & 0x2000000) strcat (ProcFlags, " erdact"); if (JpiSts & 0x4000000) strcat (ProcFlags, " softsusp"); if (JpiSts & 0x8000000) strcat (ProcFlags, " preempted"); strcat (ProcFlags, "\n "); if (JpiSts2 & 0x1) strcat (ProcFlags, " qresched"); if (JpiSts2 & 0x2) strcat (ProcFlags, " deplock"); if (JpiSts2 & 0x3) strcat (ProcFlags, " fredlock"); if (JpiSts2 & 0x4) strcat (ProcFlags, " phdlock"); if (JpiSts2 & 0x10) strcat (ProcFlags, " tcb"); if (JpiSts2 & 0x20) strcat (ProcFlags, " tbspend"); if (JpiSts2 & 0x40) strcat (ProcFlags, " sslogenab"); if (JpiSts2 & 0x80) strcat (ProcFlags, " sslogperm"); if (JpiSts2 & 0x100) strcat (ProcFlags, " brkrunload"); if (JpiSts2 & 0x8000) strcat (ProcFlags, " classschedperm"); if (JpiSts2 & 0x10000) strcat (ProcFlags, " termnotify"); if (JpiSts2 & 0x20000) strcat (ProcFlags, " bytlmloan"); if (JpiSts2 & 0x40000) strcat (ProcFlags, " dispreempt"); if (JpiSts2 & 0x80000) strcat (ProcFlags, " nounshelv"); if (JpiSts2 & 0x100000) strcat (ProcFlags, " shelvres"); if (JpiSts2 & 0x200000) strcat (ProcFlags, " classched"); if (JpiSts2 & 0x400000) strcat (ProcFlags, " classupp"); if (JpiSts2 & 0x800000) strcat (ProcFlags, " intbsstate"); if (JpiSts2 & 0x1000000) strcat (ProcFlags, " windfall"); if (JpiSts2 & 0x2000000) strcat (ProcFlags, " notify"); if (JpiSts2 & 0x3C000000) strcat (ProcFlags, " sinthread"); if (JpiSts2 & 0x40000000) strcat (ProcFlags, " rwast"); if (JpiSts2 & 0x80000000) strcat (ProcFlags, " softsinthr"); ProcessCount++; vecptr = FaoVector; *vecptr++ = JpiPid; *vecptr++ = JpiPrcNam; *vecptr++ = JpiPri; *vecptr++ = JpiPrib; *vecptr++ = JpiBufIo + JpiDirIo; *vecptr++ = JpiCpuTim / 8640000; /* CPU day */ *vecptr++ = (JpiCpuTim % 8640000) / 360000; /* CPU hour */ *vecptr++ = (JpiCpuTim % 360000) / 6000; /* CPU minute */ *vecptr++ = (JpiCpuTim % 6000 ) / 100; /* CPU second */ *vecptr++ = JpiCpuTim % 100; /* CPU 10 milliseconds */ *vecptr++ = JpiPageFlts; if (JpiPagFilCnt) *vecptr++ = 100 - PercentOf32 (JpiPagFilCnt,JpiPgFlQuota); else *vecptr++ = 0; *vecptr++ = ProcFlags; *vecptr++ = JpiUserName; if (JpiImagName[0]) *vecptr++ = JpiImagName; else *vecptr++ = "[none]"; if (rqptr) status = FaolToNet (rqptr, ProcessFao, &FaoVector); else { char Buffer [32767]; status = FaolToBuffer (Buffer, sizeof(Buffer), NULL, ProcessFao, &FaoVector); fputs (Buffer, stdout); } if (VMSnok (status)) FaoToEither (rqptr, "$FAO() !&S\n", status); } if (VMSnok (SetPrvStatus = sys$setprv (0, &MailboxMask, 0, 0))) ErrorExitVmsStatus (SetPrvStatus, "sys$setprv()", FI_LI); } /*****************************************************************************/ /* Provide resource consumption data. This called with |rqptr| non-NULL to report the data. It is also called by HttpdTick() once a minute to update the per-minute and buffered data. */ void sysPlusRmi (REQUEST_STRUCT *rqptr) { #define CPU_KERNEL 1 #define CPU_EXEC 2 #define CPU_SUPER 3 #define CPU_USER 4 #define CPU_IDLE 5 #define CPU_int_mps 6 #define CPU_INTSTK 7 #define CPU_MPSYNCH 8 #define CPU_total 9 #define NUM_STATE 9 #define STATE_CEF 1 #define STATE_COLPG 2 #define STATE_COM 3 #define STATE_COMO 4 #define STATE_CUR 5 #define STATE_FPG 6 #define STATE_HIB 7 #define STATE_HIBO 8 #define STATE_LEF 9 #define STATE_LEFO 10 #define STATE_SUSP 11 #define STATE_MWAIT 12 #define STATE_SUSPO 13 #define STATE_total 14 #define MEM_ERRS 15 #define RESMASK 16 #define ULONG_LAST 17 /* CPU modes ([0]..[6]) by minutes ([1]..) plus current read ([0]) */ static uint64 RmiCpu [NUM_MINS+2][NUM_STATE+1]; /* various unsigned longs by minutes ([1]..) plus current read [0] */ static ulong RmiUlong [NUM_MINS+2][ULONG_LAST+1]; static VMS_ITEM_LIST3 RmiItem [] = { { sizeof(RmiCpu[0][CPU_EXEC]), RMI$_CPUEXEC, &RmiCpu[0][CPU_EXEC], 0 }, { sizeof(RmiCpu[0][CPU_IDLE]), RMI$_CPUIDLE, &RmiCpu[0][CPU_IDLE], 0 }, { sizeof(RmiCpu[0][CPU_INTSTK]), RMI$_CPUINTSTK, &RmiCpu[0][CPU_INTSTK], 0 }, { sizeof(RmiCpu[0][CPU_KERNEL]), RMI$_CPUKERNEL, &RmiCpu[0][CPU_KERNEL], 0 }, { sizeof(RmiCpu[0][CPU_MPSYNCH]), RMI$_CPUMPSYNCH, &RmiCpu[0][CPU_MPSYNCH], 0 }, { sizeof(RmiCpu[0][CPU_SUPER]), RMI$_CPUSUPER, &RmiCpu[0][CPU_SUPER], 0 }, { sizeof(RmiCpu[0][CPU_USER]), RMI$_CPUUSER, &RmiCpu[0][CPU_USER], 0 }, { sizeof(RmiUlong[0][MEM_ERRS]), RMI$_MEMERRS, &RmiUlong[0][MEM_ERRS], 0 }, { sizeof(RmiUlong[0][RESMASK]), RMI$_RESMASK, &RmiUlong[0][RESMASK], 0 }, { sizeof(RmiUlong[0][STATE_CEF]), RMI$_CEF, &RmiUlong[0][STATE_CEF], 0 }, { sizeof(RmiUlong[0][STATE_COLPG]), RMI$_COLPG, &RmiUlong[0][STATE_COLPG], 0 }, { sizeof(RmiUlong[0][STATE_COM]), RMI$_COM, &RmiUlong[0][STATE_COM], 0 }, { sizeof(RmiUlong[0][STATE_COMO]), RMI$_COMO, &RmiUlong[0][STATE_COMO], 0 }, { sizeof(RmiUlong[0][STATE_CUR]), RMI$_CUR, &RmiUlong[0][STATE_CUR], 0 }, { sizeof(RmiUlong[0][STATE_FPG]), RMI$_FPG, &RmiUlong[0][STATE_FPG], 0 }, { sizeof(RmiUlong[0][STATE_HIB]), RMI$_HIB, &RmiUlong[0][STATE_HIB], 0 }, { sizeof(RmiUlong[0][STATE_HIBO]), RMI$_HIBO, &RmiUlong[0][STATE_HIBO], 0 }, { sizeof(RmiUlong[0][STATE_LEF]), RMI$_LEF, &RmiUlong[0][STATE_LEF], 0 }, { sizeof(RmiUlong[0][STATE_LEFO]), RMI$_LEFO, &RmiUlong[0][STATE_LEFO], 0 }, { sizeof(RmiUlong[0][STATE_MWAIT]), RMI$_MWAIT, &RmiUlong[0][STATE_MWAIT], 0 }, { sizeof(RmiUlong[0][STATE_SUSP]), RMI$_SUSP, &RmiUlong[0][STATE_SUSP], 0 }, { sizeof(RmiUlong[0][STATE_SUSPO]), RMI$_SUSPO, &RmiUlong[0][STATE_SUSPO], 0 }, { 0,0,0,0 } }; int min, mode, status; ulong cpuTotal, modeTotal; ulong PercentCpu [NUM_STATE+1]; char when [16]; IO_SB IOsb; /*********/ /* begin */ /*********/ if (rqptr == (REQUEST_STRUCT*)-1) { /*******************/ /* per-minute data */ /*******************/ /* move all values into one minute further in the past */ for (min = NUM_MINS+1; min > 0; min--) { memcpy (RmiCpu[min], RmiCpu[min-1], sizeof(RmiCpu[min])); memcpy (RmiUlong[min], RmiUlong[min-1], sizeof(RmiUlong[min])); } } /* collect System Performance Information */ status = sys$getrmi (EfnWait, 0, 0, &RmiItem, &IOsb, 0, 0); if (VMSok (status)) sys$synch (EfnWait, &IOsb); if (VMSok (status)) status = IOsb.Status; if (VMSnok (status)) { FaoToEither (rqptr, "$GETRMI() !&S\n", status); return; } sysPlusRmiMemErrs = RmiUlong[0][MEM_ERRS]; RmiCpu[0][CPU_total] = RmiCpu[0][CPU_INTSTK] + RmiCpu[0][CPU_MPSYNCH] + RmiCpu[0][CPU_KERNEL] + RmiCpu[0][CPU_EXEC] + RmiCpu[0][CPU_SUPER] + RmiCpu[0][CPU_USER] + RmiCpu[0][CPU_IDLE]; RmiCpu[0][CPU_int_mps] = RmiCpu[0][CPU_INTSTK] + RmiCpu[0][CPU_MPSYNCH]; RmiUlong[0][STATE_total] = RmiUlong[0][STATE_CEF] + RmiUlong[0][STATE_COLPG] + RmiUlong[0][STATE_COM] + RmiUlong[0][STATE_COMO] + RmiUlong[0][STATE_CUR] + RmiUlong[0][STATE_FPG] + RmiUlong[0][STATE_HIB] + RmiUlong[0][STATE_HIBO] + RmiUlong[0][STATE_LEF] + RmiUlong[0][STATE_LEFO] + RmiUlong[0][STATE_MWAIT] + RmiUlong[0][STATE_SUSP] + RmiUlong[0][STATE_SUSPO]; if (rqptr == (REQUEST_STRUCT*)-1) return; /**********/ /* report */ /**********/ FaoToEither (rqptr, "CPU% Kern Exec Supr User Idle Othr\n\ ~~~~ ~~~~ ~~~~ ~~~~ ~~~~ ~~~~\n"); for (min = 0; min <= NUM_MINS; min++) { if (!RmiCpu[min+1][CPU_total]) break; if (min) sprintf (when, "%d min", min); else strcpy (when, "now"); for (mode = CPU_KERNEL; mode <= CPU_int_mps; mode++) { if (RmiCpu[min+1][CPU_total]) cpuTotal = (ulong)(RmiCpu[min][CPU_total] - RmiCpu[min+1][CPU_total]); else cpuTotal = 0; if (RmiCpu[min+1][mode]) modeTotal = (ulong)(RmiCpu[min][mode] - RmiCpu[min+1][mode]); else modeTotal = 0; PercentCpu[mode] = PercentOf32 (modeTotal, cpuTotal); } FaoToEither (rqptr, "!6&>AZ !3UL !3UL !3UL !3UL !3UL !3UL\n", when, PercentCpu[CPU_KERNEL], PercentCpu[CPU_EXEC], PercentCpu[CPU_SUPER], PercentCpu[CPU_USER], PercentCpu[CPU_IDLE], PercentCpu[CPU_int_mps]); } FaoToEither (rqptr, "\nStates CEF COLPG COM COMO CUR FPG HIB HIBO \ LEF LEFO MWAIT resource SUSP SUSPO Total\n\ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ ~~~~~ \ ~~~~~ ~~~~~ ~~~~~~~~~~~~~~ ~~~~~ ~~~~~ ~~~~~\n"); for (min = 0; min <= NUM_MINS; min++) { if (!RmiUlong[min+1][STATE_total]) break; if (min) sprintf (when, "%d min", min); else strcpy (when, "now"); FaoToEither (rqptr, "!6&>AZ !5UL !5UL !5UL !5UL !5UL !5UL !5UL !5UL \ !5UL !5UL !5UL !8XL !5UL !5UL !5UL\n", when, RmiUlong[min][STATE_CEF], RmiUlong[min][STATE_COLPG], RmiUlong[min][STATE_COM], RmiUlong[min][STATE_COMO], RmiUlong[min][STATE_CUR], RmiUlong[min][STATE_FPG], RmiUlong[min][STATE_HIB], RmiUlong[min][STATE_HIBO], RmiUlong[min][STATE_LEF], RmiUlong[min][STATE_LEFO], RmiUlong[min][STATE_MWAIT], RmiUlong[min][RESMASK], RmiUlong[min][STATE_SUSP], RmiUlong[min][STATE_SUSPO], RmiUlong[min][STATE_total]); } FaoToEither (rqptr, "\n"); } /*****************************************************************************/ /* Provide Mass Storage Control Protocol (MSCP) data. */ void sysPlusMscp (REQUEST_STRUCT *rqptr) { #define MSCP_ALL 0 static BOOL nope; static int status; static ulong MscpData [35]; /* by minutes ([1]..) plus current read ([0]) */ static ulong MscpBufAvail [NUM_MINS+2], MscpBufWait [NUM_MINS+2], MscpOpCount [NUM_MINS+2], MscpRead [NUM_MINS+2], MscpSplitXfer [NUM_MINS+2], MscpVcFail [NUM_MINS+2], MscpWrite [NUM_MINS+2]; static VMS_ITEM_LIST3 RmiItem [] = { #if MSCP_ALL { sizeof(MscpData), RMI$_MSCP_ALL, &MscpData, 0 }, #else { sizeof(MscpData), RMI$_MSCP_EVERYTHING, &MscpData, 0 }, #endif {0,0,0,0} }; int min; ulong ThisMscpBufAvail, ThisMscpBufWait, ThisMscpOpCount, ThisMscpRead, ThisMscpSplitXfer, ThisMscpVcFail, ThisMscpWrite; char when [16]; IO_SB IOsb; /*********/ /* begin */ /*********/ if (nope) { FaoToEither (rqptr, "MSCP data not available !&S\n\n", status); return; } if (rqptr == (REQUEST_STRUCT*)-1) { /*******************/ /* per-minute data */ /*******************/ /* move all values into one minute into the past */ for (min = NUM_MINS+1; min > 0; min--) { MscpBufAvail[min] = MscpBufAvail[min-1]; MscpOpCount[min] = MscpOpCount[min-1]; MscpRead[min] = MscpRead[min-1]; MscpWrite[min] = MscpWrite[min-1]; MscpVcFail[min] = MscpVcFail[min-1]; MscpSplitXfer[min] = MscpSplitXfer[min-1]; MscpBufWait[min] = MscpBufWait[min-1]; } } status = sys$getrmi (EfnWait, 0, 0, &RmiItem, &IOsb, 0, 0); if (VMSok (status)) sys$synch (EfnWait, &IOsb); if (VMSok (status)) status = IOsb.Status; if (VMSnok (status)) { FaoToEither (rqptr, "MSCP data not available !&S\n\n", status); nope = true; return; } #if MSCP_ALL MscpBufAvail[0] = 0; MscpOpCount[0] = MscpData[0]; MscpVcFail[0] = 0; MscpRead[0] = MscpData[1]; MscpWrite[0] = MscpData[2]; MscpSplitXfer[0] = MscpData[3]; MscpBufWait[0] = MscpData[4]; #else MscpBufAvail[0] = MscpData[0]; MscpOpCount[0] = MscpData[21]; MscpVcFail[0] = MscpData[22]; MscpRead[0] = MscpData[23]; MscpWrite[0] = MscpData[24]; MscpSplitXfer[0] = MscpData[25]; MscpBufWait[0] = MscpData[26]; #endif if (rqptr == (REQUEST_STRUCT*)-1) return; /***********/ /* report */ /**********/ #if MSCP_ALL FaoToEither (rqptr, "\ MSCP Op Cnt Read Write \ Split Wait\n\ ~~~~~~~~~~~~ ~~~~~~~~~~~~ ~~~~~~~~~~~~ \ ~~~~~~~~~~~~ ~~~~~~~~~~~~\n"); #else FaoToEither (rqptr, "\ MSCP Buf Avl Op Cnt Read Write \ VC Fail Split Wait\n\ ~~~~~~~~~~~~ ~~~~~~~~~~~~ ~~~~~~~~~~~~ ~~~~~~~~~~~~ \ ~~~~~~~~~~~~ ~~~~~~~~~~~~ ~~~~~~~~~~~~\n"); #endif for (min = 0; min <= NUM_MINS; min++) { if (min) { if (!MscpOpCount[min+1]) continue; ThisMscpBufAvail = MscpBufAvail[min]; ThisMscpOpCount = MscpOpCount[min] - MscpOpCount[min+1]; ThisMscpRead = MscpRead[min] - MscpRead[min+1]; ThisMscpWrite = MscpWrite[min] - MscpWrite[min+1]; ThisMscpVcFail = MscpVcFail[min] - MscpVcFail[min+1]; ThisMscpSplitXfer = MscpSplitXfer[min] - MscpSplitXfer[min+1]; ThisMscpBufWait = MscpBufWait[min] - MscpBufWait[min+1]; sprintf (when, "%d min", min); } else { ThisMscpBufAvail = MscpBufAvail[0]; ThisMscpOpCount = MscpOpCount[0]; ThisMscpRead = MscpRead[0]; ThisMscpWrite = MscpWrite[0]; ThisMscpVcFail = MscpVcFail[0]; ThisMscpSplitXfer = MscpSplitXfer[0]; ThisMscpBufWait = MscpBufWait[0]; strcpy (when, "total"); } #if MSCP_ALL FaoToEither (rqptr, "!6&>AZ !12UL !12UL !12UL !12UL !12UL\n", when, ThisMscpOpCount, ThisMscpRead, ThisMscpWrite, ThisMscpSplitXfer, ThisMscpBufWait); #else FaoToEither (rqptr, "!6&>AZ !12UL !12UL !12UL !12UL !12UL !12UL !12UL\n", when, ThisMscpBufAvail, ThisMscpOpCount, ThisMscpRead, ThisMscpWrite, ThisMscpVcFail, ThisMscpSplitXfer, ThisMscpBufWait); #endif } FaoToEither (rqptr, "\n"); } /*****************************************************************************/ /* This function uses undocumented sense-mode functionality to load counters from the network interface (commonly ethernet device). Multiple devices are supported using a multi-valued logical name WASD_SYSPLUS_NI and the frame-rate and byte-rate and soft/hard error-rate statistics are accumlated to represent total system data. Essential concepts have come from "EMON: moniteur ethernet (V2.1-2) Gerard Guillaume" and found in DECUSLIB freeware, and from some peeks at the T4 source code. The implementation is mine. */ void sysPlusNet (REQUEST_STRUCT *rqptr) { #define NI_DEVICE_MAX 16 #define NI_DEVNAM_MAX 31 /* the ACCUM index is used to accumulate the current device counters */ #define ACCUM (NUM_MINS+2) static int NetIntCount, IoClrCount; static ushort NetIntChan [NI_DEVICE_MAX]; static ulong DcSCOM = 32, /* DC$_SCOM */ DtNI = 13; /* DT$_NI */ static uint64 NetIntBlocksRx64 [NI_DEVICE_MAX][NUM_MINS+3], NetIntBlocksTx64 [NI_DEVICE_MAX][NUM_MINS+3], NetIntBytesRx64 [NI_DEVICE_MAX][NUM_MINS+3], NetIntBytesTx64 [NI_DEVICE_MAX][NUM_MINS+3], NetIntErrorsHard64 [NI_DEVICE_MAX][NUM_MINS+3], NetIntErrorsSoft64 [NI_DEVICE_MAX][NUM_MINS+3]; static long DeviceCount = -1, DviUnit, LnmIndex = -1, LnmAttributes; static ushort LogValueLen; static char under [] = "~~~~~~~~~~~~~~~~~~~~"; static char LogValue [64]; static char NetIntDevName [NI_DEVICE_MAX][NI_DEVNAM_MAX+1]; static struct { short BufferLength; short ItemCode; void *BufferPtr; void *LengthPtr; } LnmItems [] = { { sizeof(LnmIndex), LNM$_INDEX, &LnmIndex, 0 }, { sizeof(LnmAttributes), LNM$_ATTRIBUTES, &LnmAttributes, 0 }, { sizeof(LogValue)-1, LNM$_STRING, &LogValue, &LogValueLen }, { 0,0,0,0 } }, DevScanItems [] = { { sizeof(DcSCOM), DVS$_DEVCLASS, &DcSCOM, 0 }, { 0,0,0,0 } }, GetDviItems [] = { { sizeof(DviUnit), DVI$_UNIT, &DviUnit, 0 }, { 0,0,0,0 } }; static $DESCRIPTOR (NetIntDsc, ""); static $DESCRIPTOR (LogNameDsc, WASD_SYSPLUS_NI); static $DESCRIPTOR (LnmFileDevDsc, "LNM$FILE_DEV"); int ecnt, min, status; ushort pword, retlen; ulong LnmCount; uint64 value64, BlocksRx64, BlocksTx64, BytesRx64, BytesTx64, DevScanContext64, ErrorsHard64, ErrorsSoft64; char *vptr; char byrx [16], bytx [16], when [16], DevScanBuffer [64], CountBuffer [512]; IO_SB IOsb; $DESCRIPTOR (CountDsc, CountBuffer); $DESCRIPTOR (DevScanDsc, DevScanBuffer); /*********/ /* begin */ /*********/ if (WATCH_MODULE(WATCH_MOD__OTHER)) WatchThis (WATCHALL, WATCH_MOD__OTHER, "sysPlusNet()"); if (LnmIndex < 0) { /* first call, check for logical name defined network devices */ for (LnmIndex = 0; LnmIndex < NI_DEVICE_MAX; LnmIndex++) { status = sys$trnlnm (0, &LnmFileDevDsc, &LogNameDsc, 0, &LnmItems); if (VMSnok (status) || !(LnmAttributes & LNM$M_EXISTS)) break; LogValue[LogValueLen] = '\0'; NetIntDsc.dsc$a_pointer = LogValue; NetIntDsc.dsc$w_length = LogValueLen; status = sys$assign (&NetIntDsc, &NetIntChan[LnmIndex], 0, 0); if (VMSnok (status)) { FaoToEither (rqptr, "$ASSIGN() !AZ !&S\n", LogValue, status); continue; } strncpy (NetIntDevName[NetIntCount], LogValue, NI_DEVNAM_MAX); NetIntDevName[NetIntCount][NI_DEVNAM_MAX] = '\0'; NetIntCount++; } } if (!NetIntCount && DeviceCount < 0) { /* first call */ DeviceCount = 0; /* scan system for network devices */ DevScanContext64 = 0; while (NetIntCount < NI_DEVICE_MAX) { status = sys$device_scan (&DevScanDsc, &retlen, 0, &DevScanItems, &DevScanContext64); if (VMSnok (status)) { if (status == SS$_NOMOREDEV || status == SS$_NOSUCHDEV) break; if (VMSnok (status)) FaoToEither (rqptr, "$DEVICE_SCAN() !&S\n", status); } status = sys$getdviw (0, 0, &DevScanDsc, &GetDviItems, &IOsb, 0, 0, 0, 0); if (VMSok (status)) status = IOsb.Status; if (VMSnok (status)) FaoToEither (rqptr, "$GETDVIW() !&S\n", status); /* if not a template device then continue */ if (DviUnit != 0) continue; DevScanBuffer[retlen] = '\0'; /* RMDRIVER gives %SYSTEM-F-SYSVERDIF */ if (!strcmp (DevScanBuffer, "_RMA0:")) continue; status = sys$assign (&DevScanDsc, &NetIntChan[DeviceCount++], 0, 0); if (VMSnok (status)) FaoToEither (rqptr, "$ASSIGN() !&S\n", status); strncpy (NetIntDevName[NetIntCount], DevScanBuffer+1, NI_DEVNAM_MAX); NetIntDevName[NetIntCount][NI_DEVNAM_MAX] = '\0'; NetIntCount++; } } /* if no devices then just return from here */ if (!NetIntCount) return; if (rqptr == (REQUEST_STRUCT*)-1) { /* once a minute store previous minute's accumulated data */ for (ecnt = 0; ecnt < NetIntCount; ecnt++) { for (min = NUM_MINS+1; min > 0; min--) { NetIntBlocksRx64[ecnt][min] = NetIntBlocksRx64[ecnt][min-1]; NetIntBlocksTx64[ecnt][min] = NetIntBlocksTx64[ecnt][min-1]; NetIntBytesRx64[ecnt][min] = NetIntBytesRx64[ecnt][min-1]; NetIntBytesTx64[ecnt][min] = NetIntBytesTx64[ecnt][min-1]; NetIntErrorsHard64[ecnt][min] = NetIntErrorsHard64[ecnt][min-1]; NetIntErrorsSoft64[ecnt][min] = NetIntErrorsSoft64[ecnt][min-1]; } } } /****************/ /* collect data */ /****************/ IoClrCount = 0; /* accumulate counts from each device */ for (ecnt = 0; ecnt < NetIntCount; ecnt++) { NetIntBlocksRx64[ecnt][ACCUM] = 0; NetIntBlocksTx64[ecnt][ACCUM] = 0; NetIntBytesRx64[ecnt][ACCUM] = 0; NetIntBytesTx64[ecnt][ACCUM] = 0; NetIntErrorsHard64[ecnt][ACCUM] = 0; NetIntErrorsSoft64[ecnt][ACCUM] = 0; memset (CountBuffer, 0, sizeof(CountBuffer)); status = sys$qiow (0, NetIntChan[ecnt], IO$_SENSEMODE | IO$M_RD_COUNT | IoClrCount | #define IO$M_RD_64COUNT 0x4000 IO$M_RD_64COUNT | IO$M_CTRL, &IOsb, 0, 0, 0, &CountDsc, 0, 0, 0, 0); if (VMSok (status)) status = IOsb.Status; if (VMSnok (status)) FaoToEither (rqptr, "$QIOW() !AZ !&S\n", NetIntDevName[ecnt], status); vptr = CountBuffer; while (vptr < CountBuffer + IOsb.Count) { pword = *(ushort*)vptr; vptr += 2; /* end of list */ if (!pword) break; /* MSB should be set! */ if (!(pword & 0x8000)) break; value64 = 0; if ((pword & 0x0fff) < 200) { /* quadword value (item number less than 200) */ value64 = *(INT64PTR)vptr; vptr += 8; } else if ((pword & 0x6000) == 0x6000) { /* longword value */ value64 = *(ULONGPTR)vptr; vptr += 4; } else if ((pword & 0x6000) == 0x4000) { /* word value */ value64 = *(USHORTPTR)vptr; vptr += 2; } else if ((pword & 0x6000) == 0x2000) { /* byte value */ value64 = *(uchar*)vptr; vptr++; } if (pword & 0x1000) { /* hw map (?) */ value64 = *(ushort*)vptr; vptr += 2; continue; } switch (pword & 0x0fff) { /* these look suspiciously like "LANCP SHOW DEVICE /COUNT"! */ case 1 : /* seconds since last zeroed */ break; case 2 : case 6 : NetIntBytesRx64[ecnt][ACCUM] += value64; break; case 3 : case 7 : NetIntBytesTx64[ecnt][ACCUM] += value64; break; case 4 : case 8 : NetIntBlocksRx64[ecnt][ACCUM] += value64; break; case 5 : case 9 : NetIntBlocksTx64[ecnt][ACCUM] += value64; break; case 12 : case 13 : case 14 : case 15 : case 16 : case 17 : case 18 : case 19 : case 30 : case 21 : case 22 : case 23 : case 24 : case 27 : case 28 : case 29 : NetIntErrorsSoft64[ecnt][ACCUM] += value64; break; case 25 : case 26 : case 33 : case 34 : NetIntErrorsHard64[ecnt][ACCUM] += value64; break; /* more "traditional" counters */ case 1000 /* NMA$C_CTLIN_BRC bytes received */ : case 1002 /* NMA$C_CTLIN_MBY multicast bytes received */ : NetIntBytesRx64[ecnt][ACCUM] += value64; break; case 1001 /* NMA$C_CTLIN_BSN bytes sent */ : NetIntBytesTx64[ecnt][ACCUM] += value64; break; case 1010 /* NMA$C_CTLIN_DBR data blocks received */ : case 1012 /* NMA$C_CTLIN_MBL multicast blocks received */ : NetIntBlocksRx64[ecnt][ACCUM] += value64; break; case 1011 /* NMA$C_CTLIN_DBS data blocks sent */ : NetIntBlocksTx64[ecnt][ACCUM] += value64; break; case 1013 /* NMA$C_CTLIN_BID */ : case 1014 /* NMA$C_CTLIN_BS1 */ : case 1015 /* NMA$C_CTLIN_BSM */ : case 1040 /* NMA$C_CTLIN_RBE */ : case 1041 /* NMA$C_CTLIN_LBE */ : case 1064 /* NMA$C_CTLIN_OVR */ : case 1066 /* NMA$C_CTLIN_UBU */ : NetIntErrorsSoft64[ecnt][ACCUM] += value64; break; case 1060 /* NMA$C_CTLIN_SFL */ : case 1061 /* NMA$C_CTLIN_CDC */ : case 1063 /* NMA$C_CTLIN_UFD */ : case 1062 /* NMA$C_CTLIN_RFL */ : case 1065 /* NMA$C_CTLIN_SBU */ : NetIntErrorsHard64[ecnt][ACCUM] += value64; break; default : } } NetIntBlocksRx64[ecnt][0] = NetIntBlocksRx64[ecnt][ACCUM]; NetIntBlocksTx64[ecnt][0] = NetIntBlocksTx64[ecnt][ACCUM]; NetIntBytesRx64[ecnt][0] = NetIntBytesRx64[ecnt][ACCUM]; NetIntBytesTx64[ecnt][0] = NetIntBytesTx64[ecnt][ACCUM]; NetIntErrorsHard64[ecnt][0] = NetIntErrorsHard64[ecnt][ACCUM]; NetIntErrorsSoft64[ecnt][0] = NetIntErrorsSoft64[ecnt][ACCUM]; } if (rqptr == (REQUEST_STRUCT*)-1) return; /**********/ /* report */ /**********/ for (ecnt = 0; ecnt < NetIntCount; ecnt++) { status = FaoToEither (rqptr, "!AZ\ !8AZ!13&>AZ !13&>AZ !18&>AZ !8&>AZ !18&>AZ !8&>AZ !6&>AZ !6&>AZ\n\ !6AZ !13AZ !13AZ !18AZ !8AZ !18AZ !8AZ !6AZ !6AZ\n", ecnt ? "\n" : "", NetIntDevName[ecnt], "Packet Rx", "Packet Tx", "Bytes Rx", "", "Bytes Tx", "", "Hard", "Soft", "", under, under, under, "", under, "", under, under); if (VMSnok (status)) FaoToEither (rqptr, "$FAO() !&S\n", status); for (min = 0; min <= NUM_MINS; min++) { if (min) { if (!NetIntBlocksRx64[ecnt][min+1]) continue; BlocksRx64 = NetIntBlocksRx64[ecnt][min] - NetIntBlocksRx64[ecnt][min+1]; BlocksTx64 = NetIntBlocksTx64[ecnt][min] - NetIntBlocksTx64[ecnt][min+1]; BytesRx64 = NetIntBytesRx64[ecnt][min] - NetIntBytesRx64[ecnt][min+1]; BytesTx64 = NetIntBytesTx64[ecnt][min] - NetIntBytesTx64[ecnt][min+1]; ErrorsHard64 = NetIntErrorsHard64[ecnt][min] - NetIntErrorsHard64[ecnt][min+1]; ErrorsSoft64 = NetIntErrorsSoft64[ecnt][min] - NetIntErrorsSoft64[ecnt][min+1]; sprintf (when, "%d min", min); } else { BlocksRx64 = NetIntBlocksRx64[ecnt][ACCUM]; BlocksTx64 = NetIntBlocksTx64[ecnt][ACCUM]; BytesRx64 = NetIntBytesRx64[ecnt][ACCUM]; BytesTx64 = NetIntBytesTx64[ecnt][ACCUM]; ErrorsHard64 = NetIntErrorsHard64[ecnt][ACCUM]; ErrorsSoft64 = NetIntErrorsSoft64[ecnt][ACCUM]; strcpy (when, "total"); } status = FaoToEither (rqptr, "!6&>AZ !13@SQ !13@SQ !18@SQ !8AZ !18@SQ !8AZ !6@SQ !6@SQ\n", when, &BlocksRx64, &BlocksTx64, &BytesRx64, sysPlusNetVal(BytesRx64,byrx), &BytesTx64, sysPlusNetVal(BytesTx64,bytx), &ErrorsHard64, &ErrorsSoft64); } } FaoToEither (rqptr, "\n"); } /*****************************************************************************/ /* 64 bit accumulator to real number Tbytes, Gbytes, Mbytes or kbytes. */ char* sysPlusNetVal ( int64 bytes64, char *buf ) { #define AT_ONCE_MAX 2 char tmp [32]; float qfloat; /*********/ /* begin */ /*********/ qfloat = (float)bytes64; if (qfloat >= 1024.0 * 1024.0 * 1024.0 * 1024.0) sprintf (tmp, "%3.2fTB", qfloat / (1024.0 * 1024.0 * 1024.0 * 1024.0)); else if (qfloat >= 1024.0 * 1024.0 * 1024.0) sprintf (tmp, "%3.2fGB", qfloat / (1024.0 * 1024.0 * 1024.0)); else if (qfloat >= 1024.0 * 1024.0) sprintf (tmp, "%3.2fMB", qfloat / (1024.0 * 1024.0)); else if (qfloat >= 1024.0) sprintf (tmp, "%3.2fkB", qfloat / 1024.0); else tmp[0] = '\0'; /* right justify */ sprintf (buf, "%8.8s", tmp); return (buf); } /*****************************************************************************/ /* Provide cluster resource consumption data. This called with |rqptr| non-NULL to report the data. It is also called by HttpdTick() once a minute to update the per-minute and buffered data. */ void sysPlusScs (REQUEST_STRUCT *rqptr) { static ulong ScsRead [1+(SCS_NODES_MAX*14)]; static ulong ScsData [NUM_MINS+2][SCS_NODES_MAX][14]; static VMS_ITEM_LIST3 RmiItem [] = { { sizeof(ScsRead), RMI$_SCS, &ScsRead, 0 }, {0,0,0,0} }; /* hmmm; on VAX V7.3 this gets clobbered if placed before ScsRead[] !! */ static int status; int cnt, min, node; ulong DgramDisc, DgramRcvd, DgramSent, KbyteMap, KbyteSent, KbyteRcvd, MsgSent, MsgRcvd, QcrCnt, QbdtCnt, ReqDats, SendDats; ulong *data; char *cptr, *sptr; char name [16], when [16]; IO_SB IOsb; /*********/ /* begin */ /*********/ if (status) { FaoToEither (rqptr, "SCS data not available !&S\n\n", status); return; } if (rqptr == (REQUEST_STRUCT*)-1) { /*******************/ /* per-minute data */ /*******************/ /* move all values into one minute into the past */ for (min = NUM_MINS+1; min > 0; min--) /* first node is always this one */ for (node = 1; node < SCS_NODES_MAX; node++) if (ScsData[min-1][node][0]) memcpy (&ScsData[min][node], &ScsData[min-1][node], sizeof(ScsData[0][0])); } #if WASD_GETSPI status = exe$getspi (EfnWait, 0, 0, &RmiItem, &IOsb, 0, 0); #else status = sys$getrmi (EfnWait, 0, 0, &RmiItem, &IOsb, 0, 0); #endif if (VMSok (status)) sys$synch (EfnWait, &IOsb); if (VMSok (status)) status = IOsb.Status; if (VMSnok (status)) { FaoToEither (rqptr, "SCS data not available !&S\n\n", status); return; } status = 0; memcpy (&ScsData[0], &ScsRead[1], sizeof(ScsData[0])); if (rqptr == (REQUEST_STRUCT*)-1) return; /**********/ /* report */ /**********/ FaoToEither (rqptr, "\ SCS Node dTx dRx dDp kB Map kB Rx kB Tx \ Msg Rx Msg Tx Qbdt Qcr Req Dats Snd Dats\n\ ~~~~~~~ ~~~ ~~~ ~~~ ~~~~~~~~~~~~ ~~~~~~~~~~~~ ~~~~~~~~~~~~ \ ~~~~~~~~~~~~~ ~~~~~~~~~~~~~ ~~~~~~ ~~~~~~~ ~~~~~~~~~~~ ~~~~~~~~~~~\n"); for (min = 0; min <= NUM_MINS; min++) { if (min) sprintf (when, "%d min", min); else strcpy (when, "total"); /* first node is always this one */ for (node = 1; node < SCS_NODES_MAX; node++) { /* node name is a counted string */ cptr = (char*)&ScsData[min][node][0]; cnt = *cptr++ & 0x7; /* zero-length node name */ if (!cnt) continue; for (sptr = name; cnt--; *sptr++ = *cptr++); *sptr = '\0'; DgramSent = ScsData[min][node][2]; DgramRcvd = ScsData[min][node][3]; DgramDisc = ScsData[min][node][4]; MsgSent = ScsData[min][node][5]; MsgRcvd = ScsData[min][node][6]; SendDats = ScsData[min][node][7]; KbyteSent = ScsData[min][node][8]; ReqDats = ScsData[min][node][9]; KbyteRcvd = ScsData[min][node][10]; KbyteMap = ScsData[min][node][11]; QcrCnt = ScsData[min][node][12]; QbdtCnt = ScsData[min][node][13]; if (min) { /* if no previous minute data */ if (!ScsData[min+1][node][0]) continue; /* otherwise delta with previous minute */ DgramSent -= ScsData[min+1][node][2]; DgramRcvd -= ScsData[min+1][node][3]; DgramDisc -= ScsData[min+1][node][4]; MsgSent -= ScsData[min+1][node][5]; MsgRcvd -= ScsData[min+1][node][6]; SendDats -= ScsData[min+1][node][7]; KbyteSent -= ScsData[min+1][node][8]; ReqDats -= ScsData[min+1][node][9]; KbyteRcvd -= ScsData[min+1][node][10]; KbyteMap -= ScsData[min+1][node][11]; QcrCnt -= ScsData[min+1][node][12]; QbdtCnt -= ScsData[min+1][node][13]; } FaoToEither (rqptr, "!6&>AZ !7AZ !3UL !3UL !3UL !12UL !12UL !12UL !13UL !13UL \ !6UL !7UL !11UL !11UL\n", when, name, DgramSent, DgramRcvd, DgramDisc, KbyteMap, KbyteSent, KbyteRcvd, MsgSent, MsgRcvd, QbdtCnt, QcrCnt, ReqDats, SendDats); when[0] = '\0'; } } FaoToEither (rqptr, "\n"); } /*****************************************************************************/ /* Supports sysPlusPlus(). Provide system data. */ void sysPlusSyi (REQUEST_STRUCT *rqptr) { static ushort SyiClusterEVotes, SyiClusterQuorum, SyiNodeVotes, SyiClusterVotes, SyiNodeQuorum; static ulong SyiClusterNodes, SyiContigGblPages, SyiFreeGblPages, SyiMaxProcessCnt, SyiPageFileFree, SyiPageFilePage, SyiSwapFileFree, SyiSwapFilePage; static ulong SyiBalSlots [4], SyiMainMemory [4], SyiNPagedPool [4], SyiNPageVir [4], SyiPagedPool [4], SyiProcSlots [4]; static VMS_ITEM_LIST3 SyiItem [] = { { sizeof(SyiBalSlots), SYI$_BAL_SLOTS, &SyiBalSlots, 0 }, { sizeof(SyiContigGblPages), SYI$_CONTIG_GBLPAGES, &SyiContigGblPages, 0 }, { sizeof(SyiClusterEVotes), SYI$_CLUSTER_EVOTES, &SyiClusterEVotes, 0 }, { sizeof(SyiClusterNodes), SYI$_CLUSTER_NODES, &SyiClusterNodes, 0 }, { sizeof(SyiClusterQuorum), SYI$_CLUSTER_QUORUM, &SyiClusterQuorum, 0 }, { sizeof(SyiClusterVotes), SYI$_CLUSTER_VOTES, &SyiClusterVotes, 0 }, { sizeof(SyiFreeGblPages), SYI$_FREE_GBLPAGES, &SyiFreeGblPages, 0 }, { sizeof(SyiMaxProcessCnt), SYI$_MAXPROCESSCNT, &SyiMaxProcessCnt, 0 }, { sizeof(SyiMainMemory), SYI$_MAIN_MEMORY, &SyiMainMemory, 0 }, { sizeof(SyiNodeVotes), SYI$_NODE_VOTES, &SyiNodeVotes, 0 }, { sizeof(SyiNPagedPool), SYI$_NPAGED_POOL, &SyiNPagedPool, 0 }, { sizeof(SyiNPageVir), SYI$_NPAGEVIR, &SyiNPageVir, 0 }, { sizeof(SyiNodeQuorum), SYI$_NODE_QUORUM, &SyiNodeQuorum, 0 }, { sizeof(SyiPagedPool), SYI$_PAGED_POOL, &SyiPagedPool, 0 }, { sizeof(SyiPageFileFree), SYI$_PAGEFILE_FREE, &SyiPageFileFree, 0 }, { sizeof(SyiPageFilePage), SYI$_PAGEFILE_PAGE, &SyiPageFilePage, 0 }, { sizeof(SyiProcSlots), SYI$_PROC_SLOTS, &SyiProcSlots, 0 }, { sizeof(SyiSwapFileFree), SYI$_SWAPFILE_FREE, &SyiSwapFileFree, 0 }, { sizeof(SyiSwapFilePage), SYI$_SWAPFILE_PAGE, &SyiSwapFilePage, 0 }, { 0,0,0,0 } }; static double factor, fGB, fMB, fkB, fPS = 0.0; int status; char *cptr, *mmptr, *npptr, *pptr; char MainMemErrBuf [32], PageFileBuf [256], SwapFileBuf [256]; char MainMemBuf [4][32], NonPagedPoolBuf [4][32], PagedPoolBuf [4][32]; IO_SB IOsb; /*********/ /* begin */ /*********/ if (WATCH_MODULE(WATCH_MOD__OTHER)) WatchThis (WATCHALL, WATCH_MOD__OTHER, "sysPlusSyi()"); status = sys$getsyiw (EfnWait, 0, 0, &SyiItem, &IOsb, 0, 0); if (VMSok (status)) status = IOsb.Status; if (VMSnok (status)) { FaoToEither (rqptr, "$GETSYI() !&S\n", status); return; } if (fGB < 0.1) { fPS = (double)SysInfo.PageSize; fGB = 1073741824.0; fMB = 1048576.0; fkB = 1024.0; } if ((double)SyiMainMemory[0] * fPS / fGB < 1.0) { mmptr = "MB"; factor = fMB; } else { mmptr = "GB"; factor = fGB; } sprintf (MainMemBuf[0], "%6.2f", (double)SyiMainMemory[0] * fPS / factor); sprintf (MainMemBuf[1], "%6.2f", (double)SyiMainMemory[1] * fPS / factor); sprintf (MainMemBuf[2], "%6.2f", (double)SyiMainMemory[2] * fPS / factor); sprintf (MainMemBuf[3], "%6.2f", (double)SyiMainMemory[3] * fPS / factor); if ((double)SyiNPagedPool[0] / fGB < 1.0) { npptr = "MB"; factor = fMB; } else { npptr = "GB"; factor = fGB; } sprintf (NonPagedPoolBuf[0], "%6.2f", (double)SyiNPagedPool[0] / factor); sprintf (NonPagedPoolBuf[1], "%6.2f", (double)SyiNPagedPool[1] / factor); sprintf (NonPagedPoolBuf[2], "%6.2f", (double)SyiNPagedPool[2] / factor); sprintf (NonPagedPoolBuf[3], "%6.2f", (double)SyiNPagedPool[3] / factor); if ((double)SyiPagedPool[0] / fGB < 1.0) { pptr = "MB"; factor = fMB; } else { pptr = "GB"; factor = fGB; } sprintf (PagedPoolBuf[0], "%6.2f", (double)SyiPagedPool[0] / factor); sprintf (PagedPoolBuf[1], "%6.2f", (double)SyiPagedPool[1] / factor); sprintf (PagedPoolBuf[2], "%6.2f", (double)SyiPagedPool[2] / factor); sprintf (PagedPoolBuf[3], "%6.2f", (double)SyiPagedPool[3] / factor); if (SyiSwapFilePage) { if ((double)SyiSwapFilePage * fPS / fGB < 1.0) { cptr = "MB"; factor = fMB; } else { cptr = "GB"; factor = fGB; } sprintf (SwapFileBuf, "Swap File Usage (bytes): Free Size In use\n\ (%s) %6.2f %6.2f %3d%%\n\n", cptr, (double)SyiSwapFileFree * fPS / factor, (double)SyiSwapFilePage * fPS / factor, PercentOf32 (SyiSwapFilePage - SyiSwapFileFree, SyiSwapFilePage)); } else SwapFileBuf[0] = '\0'; if (SyiPageFilePage) { if ((double)SyiPageFilePage * fPS / fGB < 1.0) { cptr = "MB"; factor = fMB; } else { cptr = "GB"; factor = fGB; } sprintf (PageFileBuf, "Paging File Usage (bytes): Free Size In use\n\ (%s) %6.2f %6.2f %3d%%\n\n", cptr, (double)SyiPageFileFree * fPS / factor, (double)SyiPageFilePage * fPS / factor, PercentOf32 (SyiPageFilePage - SyiPageFileFree, SyiPageFilePage)); } else PageFileBuf[0] = '\0'; sprintf (MainMemErrBuf, " Errors: %u\n", sysPlusRmiMemErrs); status = FaoToEither (rqptr, "Physical Memory Usage (bytes): Total Free In Use Modified\n\ Main Memory (!AZ) !9AZ !9AZ !9AZ !9AZ\n\ !AZ\ \n\ Slot Usage (slots): Total Free Resident Swapped\n\ Process Entry Slots !4UL !4UL !4UL !4UL\n\ Balance Set Slots !4UL !4UL !4UL !4UL\n\ \n\ Dynamic Memory Usage: Total Free In Use Largest\n\ Nonpaged Dynamic Memory (!AZ) !9AZ !9AZ !9AZ !9AZ\n\ Paged Dynamic Memory (!AZ) !9AZ !9AZ !9AZ !9AZ\n\ \n\ !AZ\ !AZ\ Cluster Nodes Member Expected Votes Quorum\n" #if WASD_GETSPI "(SPI)" #else "(RMI)" #endif " !4UL !4UL !4UL !4UL !4UL\n\ \n", mmptr, MainMemBuf[0], MainMemBuf[1], MainMemBuf[2], MainMemBuf[3], MainMemErrBuf, SyiProcSlots[0], SyiProcSlots[1], SyiProcSlots[2], SyiProcSlots[3], SyiBalSlots[0], SyiBalSlots[1], SyiBalSlots[2], SyiBalSlots[3], npptr, NonPagedPoolBuf[0], NonPagedPoolBuf[1], NonPagedPoolBuf[2], NonPagedPoolBuf[3], pptr, PagedPoolBuf[0], PagedPoolBuf[1], PagedPoolBuf[2], PagedPoolBuf[3], SwapFileBuf, PageFileBuf, SyiClusterNodes, SysInfo.ClusterMember, SyiClusterEVotes, SyiClusterVotes, SyiClusterQuorum); if (VMSnok (status)) FaoToEither (rqptr, "$FAO() !&S\n", status); } /****************************************************************************/