/*****************************************************************************/ /* WATCH.c The WATCH facility is a powerful adjunct in server administration. From the administration menu it provides an online, real-time, in-browser-window view of request processing in the running server. The ability to observe live request processing on an ad hoc basis, without changing server configuration or shutting-down/restarting the server process, makes this facility a great configuration and problem resolution tool. It allows (amongst other uses) o assessment of mapping rules o assessment of authorization rules o investigation of request processing problems o general observation of server behaviour A single client per server process can access the WATCH facility at any one time. The report can be generated for a user-specified number of seconds or aborted at any time using the browser's stop button. An event is considered any significant point for which the server code has a reporting call provided. These have been selected to provide maximum information with minimum clutter and impact on server performance. Obvious examples are connection acceptance and closure, request path resolution, error report generation, network reads and writes, etc. These events may be selected on a "category" basis from the WATCH menu. This module also provides functions to display a process using SHOW PROCESS /ALL via the DCL.C module, and to delete a process, as well as a function to "peek" at selected fields in the data structures of any request during processing (intended more as a diagnosis and development tool). The "module" WATCHing functionality is basically for low-level, on-line debugging. It is not intended as a general site administration tool. EXCLUDING WATCH --------------- The WATCH menu and associated functionality can be compiled-out of the server executable using appropriate macros. The obvious one for elimination is "module" WATCHing (as mentioned ab ove, generally intended for low-level debugging). By default this is not a compile-time inclusion and requires a WATCH_MOD=1 definition during building. "Category" WATCHing is intended as a general site administration tool and so for all but the most demanding sites should be left compiled in (as it is by default). To exclude build using a WATCH_CAT=0 macro. COMMAND-LINE WATCH ------------------ The command-line version of WATCH accepts a number of variants. /WATCH[=NOSTARTUP,][ITEMS=([NO]item[,[NO]item)][,client[,service[,path]]] The leading keyword NOSTARTUP suppresses WATCH output during server startup. Items can be any category or module item name (e.g. MAPPING, _MAPURL, AUTHORIZATION, _AUTH), or ALLCAT or ALLMOD for all categories or modules, and NOwhatever to turn off a particular WATCH item. The convenience keyword LIST provides a list of all category and module keywords that may be used. /WATCH=ITEMS=(ALLCAT,NOMAPPING,ALLMOD,NO_FAO) /WATCH=NOSTARTUP,ITEMS=(MAPPING,AUTHORIZATION,_CONFIG,_AUTH..) /WATCH=ITEMS=(ALLCAT,ALLMOD,NO_FAO,NO_DETAIL),*,*,/HT_ROOT/SRC/* /WATCH=LIST VERSION HISTORY --------------- 10-JUL-2007 MGD add HTTP status filter 27-JUN-2007 MGD WatchShowCluster() 31-DEC-2006 MGD add "WebDAV" item 14-OCT-2006 MGD significantly enhance original filtering StringMatchRegex() instead of decc$match_wild() for filtering (changes the syntax slightly and adds regex matching) added REG_NEWLINE to REGEX_C_FLAGS so that anchors match newlines in strings to support 'Request' filter in WATCH 10-NOV-2004 MGD WatchNoticed() and WASD_WATCH_NOTICED to improve diagnostics 20-JUL-2004 MGD HTTP/1.1 compliance data 16-JUL-2004 MGD remove potential %DCL-W-TKNOVF in WatchShowSystem() 19-JUL-2003 MGD revise detached process candidate identification, revise process report format 05-MAY-2003 MGD remove 'quotas' WATCH item, add (string) 'match' 25-MAR-2003 MGD WatchShowProcess() username 31-JAN-2003 MGD DCL and DECnet record building items, additional items in WatchShowSystem(), no menu difference between category and module WATCHing 08-OCT-2002 MGD add scripting account information 15-JUN-2002 MGD bugfix; RequestUriPtr formatting in WatchPeek() 04-JUN-2002 MGD reserve WATCH across all instances 31-MAR-2002 MGD add CC command-line 03-FEB-2002 MGD add server process log options 03-JAN-2002 MGD refine command-line interface 29-OCT-2001 MGD PERSONA_MACRO reporting 15-SEP-2001 MGD WatchShowSystem(), per-node and per-cluster instances 04-AUG-2001 MGD support module WATCHing (WATCH_MOD), conditional compilation of both WATCH_CAT and WATCH_MOD, bugfix; check ParseQueryField() in WatchBegin() for NULL 18-APR-2001 MGD move TCP/IP agent analysis to NetTcpIpAgentInfo() 14-MAR-2001 MGD add WatchPeek() throttle, proxy authorization 06-JAN-2001 MGD DETAIL category 01-OCT-2000 MGD DCL task changes 26-AUG-2000 MGD integrate WATCH peek and processing into WatchBegin() 17-JUN-2000 MGD add "quotas" as a WATCH item, bugfix; WatchCliSettings() storage 28-MAY-2000 MGD add process quotas, using $getjpi ...lm values from startup 08-MAY-2000 MGD make path filter a path/track filter 04-MAR-2000 MGD use FaolToNet(), et.al. 02-JAN-2000 MGD add ODS to WatchPackageInfo() 10-NOV-1999 MGD use decc$match_wild() for the WatchFilter() 30-OCT-1999 MGD dignified with a module of it's own (unbundled from ADMIN.C) 07-NOV-1998 MGD initial (as part of ADMIN.C) */ /*****************************************************************************/ #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 /* application related header files */ #include "wasd.h" /* some extra prototypes required for 'watchfunc.h' */ SesolaClientCertRenegotiate (void*); SesolaNetAccept (void*); SesolaNetShutdown (void*); SesolaNetClientConnect (void*); SesolaNetClientShutdown (void*); #include "watchfunc.h" #define WASD_MODULE "WATCH" /******************/ /* global storage */ /******************/ #define WATCH_CATEGORY_LIST_SIZE 1024 #define WATCH_FILTER_SIZE 128 BOOL WatchCliNoStartup, WatchFilterOutClient, WatchFilterOutPath, WatchFilterOutRealm, WatchFilterOutRequest, WatchFilterOutService, WatchFilterOutUser; int WatchStatusFilter = -1; char WatchClientFilter [WATCH_FILTER_SIZE], WatchPathFilter [WATCH_FILTER_SIZE], WatchRealmFilter [WATCH_FILTER_SIZE], WatchRequestFilter [WATCH_FILTER_SIZE], WatchServiceFilter [WATCH_FILTER_SIZE], WatchUserFilter [WATCH_FILTER_SIZE]; char ErrorWatchAuthNeeded [] = "Authorization must be enabled to access WATCH!", ErrorWatchPersonaNeeded [] = "/PERSONA must be enabled to attempt to show this process.", ErrorWatchBufferOvf [] = "*ERROR* sys$fao() BUFFEROVF", ErrorWatchNumber [] = "Not found in current request list.", #if !WATCH_CAT ErrorWatchNoCategory [] = "Category WATCHing is not a compiled option!", #endif /* !WATCH_CAT */ #if !WATCH_MOD ErrorWatchNoModule [] = "Module WATCHing is not a compiled option!", #endif /* !WATCH_MOD */ ErrorWatchSelf [] = "Cannot WATCH yourself!", ErrorWatchQueryString [] = "WATCH query string problem (no such item).", ErrorWatchSysFao [] = "*ERROR* sys$fao()"; WATCH_STRUCT Watch, WatchCli; /********************/ /* external storage */ /********************/ #ifdef DBUG extern BOOL Debug; #else #define Debug 0 #endif extern BOOL DclPersonaServicesAvailable, DclScriptDetachProcess, LoggingEnabled, OdsExtended, OperateWithSysPrv, PersonaMacro, ProtocolHttpsConfigured, ProxyCacheEnabled, ProxyServingEnabled; extern int DclMailboxBytLmRequired, EfnWait, GzipFindImageStatus, HttpdTickSecond, InstanceNodeCurrent, NetAcceptBytLmRequired, NetListenBytLmRequired, SesolaGblSecStructSize; extern int ToLowerCase[], ToUpperCase[]; extern unsigned long MailboxMask[], ProcessRightsIdent[], WorldMask[]; extern char BuildDateTime[], CliScriptAs[], CommandLine[], ErrorSanityCheck[], HttpdScriptAsUserName[], ServerHostPort[], SoftwareID[], TcpIpAgentInfo[], TimeGmtString[]; extern char *GzipZlibNamePtr, *GzipZlibVersionPtr; extern CONFIG_STRUCT Config; extern MSG_STRUCT Msgs; extern HTTPD_GBLSEC *HttpdGblSecPtr; extern HTTPD_PROCESS HttpdProcess; extern LIST_HEAD RequestList; extern SUPERVISOR_LIST SupervisorListArray[]; extern SYS_INFO SysInfo; /*****************************************************************************/ /* Check if the watch facility is already in use, report error if it is. Provide form for selection of WATCH parameters. */ WatchReport ( REQUEST_STRUCT *rqptr, REQUEST_AST NextTaskFunction ) { #if WATCH_CAT static char ResponseFao [] = "
\n\

\n\ \n\ \n\
Select WATCH Criteria
\n\ \ \n\ \n\
\n\ \ Request\n\
Processing\n\
Header\n\
Body\n\
Response \n\
Processing\n\
Header\n\
Body\n\
\n\ General\n\
Connection\n\
Mapping\n\
Authorization\n\
Error\n\
CGI\n\
DCL\n\
DECnet\n\
WebDAV\n\
\n\ Network\n\
Activity\n\
Data\n\
Other \n\
!AZLogging!AZ\
Match\n\
Script\n\     \n\
!AZSSL!AZ\n\
Timer\n\
\n\ Proxy\n\ !AZ\
Processing\n\
Request Header\n\
Request Body\n\
Response Header\n\
Response Body\n\ !AZ\ !AZ\
Cache\n\
Cache Maintenance\n\ !AZ\
\n\ \ !AZ\ \

\n\ \n\
\n\ \n\ \n\ \ \ \n\ \ \ \n\ \ \ \n\ \ \ \n\ \ \ \ \n\ \ \ \n\
\ Filtering in out
 \  Client
 \ Service
 \ Request
 \ Path/Track
 \ Realm & User 
 \ HTTP Status
\n\
\n\ \

\n\ \n\
\n\ or\n\ Seconds Duration\n\
\ Include (only) \ in Server Process Log\n\

  \ \n\

\n\ \

\n\ \n\ \ \n\

\n\ \ \n\ \n"; #if WATCH_MOD static char WatchModFao [] = "

\n\ \n\
\n\ Module\n\
AUTH..\n\
BODY\n\
CACHE\n\
CGI\n\
CONFIG \n\
DCL\n\
\n\
DECNET\n\
DIR\n\
FAO\n\
FILE\n\
HTADMIN\n\
INSTANCE\n\
\n\
MAPURL\n\
METACON\n\
MSG\n\
NET\n\
ODS\n\
PROXY..\n\
\n\
PUT\n\
REQUEST\n\
RESPONSE\n\
SERVICE\n\
SESOLA..\n\
SSI\n\
\n\
THROTTLE\n\
UPD\n\
VM\n\
WebDAV\n\
other\n\
detail\n\
\n"; #else static char WatchModFao [] = ""; #endif /* WATCH_MOD */ int status; unsigned long FaoVector [32]; unsigned long *vecptr; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchReport()\n"); if (Watch.Disabled) { rqptr->rqResponse.HttpStatus = 403; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_GENERAL_DISABLED), FI_LI); SysDclAst (NextTaskFunction, rqptr); return; } if (!rqptr->RemoteUser[0]) { rqptr->rqResponse.HttpStatus = 403; ErrorGeneral (rqptr, ErrorWatchAuthNeeded, FI_LI); SysDclAst (NextTaskFunction, rqptr); return; } if (WatchInUse (rqptr, false)) { SysDclAst (NextTaskFunction, rqptr); return; } AdminPageTitle (rqptr, "WATCH Report"); vecptr = FaoVector; *vecptr++ = ADMIN_REPORT_WATCH; if (LoggingEnabled) { *vecptr++ = ""; *vecptr++ = ""; } else { *vecptr++ = ""; *vecptr++ = ""; } if (ProtocolHttpsConfigured) { *vecptr++ = ""; *vecptr++ = ""; } else { *vecptr++ = ""; *vecptr++ = ""; } if (ProxyServingEnabled) { *vecptr++ = ""; *vecptr++ = ""; } else { *vecptr++ = "\n"; *vecptr++ = "\n"; } if (ProxyCacheEnabled) { *vecptr++ = ""; *vecptr++ = ""; } else { *vecptr++ = "\n"; *vecptr++ = "\n"; } #if WATCH_MOD *vecptr++ = WatchModFao; #else *vecptr++ = ""; #endif status = FaolToNet (rqptr, ResponseFao, &FaoVector); if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); ResponseHeader200 (rqptr, "text/html", &rqptr->NetWriteBufferDsc); SysDclAst (NextTaskFunction, rqptr); #else /* WATCH_CAT */ rqptr->rqResponse.HttpStatus = 403; ErrorGeneral (rqptr, ErrorWatchNoCategory, FI_LI); SysDclAst (NextTaskFunction, rqptr); #endif /* WATCH_CAT */ } /*****************************************************************************/ /* This function provides both a WATCH-processing report, and a WATCH-peek report. This can be a WATCH-only report, peek-only, or peek-then-WATCH. If we're going to use the WATCH-processing report then we have to do it exclusively, check if the WATCH facility is already in use, report error if it is. Parse the query string WATCH parameters. Report any errors. Place the parameters into the WATCH global storage. This reserves the WATCH facility for this client via the 'Watch.RequestPtr' (and indicate this with a flag in the request structure, which will be detected as the request concludes and the WATCH facility released for reuse). Generate a plain-text HTTP header and output a WATCH report heading. If a WATCH-peek report is requested call WatchPeek() to generate it. For a peek-only report we declares the next function AST there. If WATCH-processing was only/also requested generate a WATCH-processing header then return BUT do not declare any AST to continue processing. The client will just "hang" there receiving output from WatchThis() via the structure pointed to by 'Watch.RequestPtr'. Can be used to WATCH all new requests (matching any filter criteria of course) or in a "one-shot" mode where a single request is selected to display all categories at any point during it's processing. */ WatchBegin ( REQUEST_STRUCT *rqptr, REQUEST_AST NextTaskFunction ) { #if WATCH_CAT static char ResponseFao [] = "!20%D WATCH REPORT !AZ\n\ !#*-\n\ !AZ (!AZ)\n\ !AZ\n\ !AZ\ $ CC (!#AZ/!UL) !AZ\n\ !AZ with !UL CPU!%s and !ULMB running VMS !AZ \ (!AZ, !AZ, !AZ, !&@, REGEX !AZ, lksb$b_valblk[!UL])!AZ\n\ $ HTTPD !AZ\n\ !AZ\ !&@\ Process: !AZ !AZ !AZ !AZ\n\ !&@\ !&@\ !&@"; static char ResponseWatchingFao [] = "|Time_______|Module__|Line|Item|Category__|Event...|\n"; static char DummyReadBuffer [32]; BOOL DoPeek, DoWatch, FilterOutClient, FilterOutPath, FilterOutRequest, FilterOutRealm, FilterOutService, FilterOutUser, FilterSet, StdoutOnly, StdoutToo; int status, ConnectNumber, DurationSeconds, StatusFilter, WatchCategory, WatchModule; char *cptr, *qptr, *sptr, *zptr, *InstanceClusterPtr, *InstanceNodePtr; char Buffer [8192], CategoryList [WATCH_CATEGORY_LIST_SIZE], ClientFilter [WATCH_FILTER_SIZE], FieldName [256], FieldValue [WATCH_FILTER_SIZE], PathFilter [WATCH_FILTER_SIZE], RealmFilter [WATCH_FILTER_SIZE], RequestFilter [WATCH_FILTER_SIZE], ServiceFilter [WATCH_FILTER_SIZE], UserFilter [WATCH_FILTER_SIZE]; unsigned short Length; unsigned long ucnt; unsigned long *vecptr; unsigned long FaoVector [64]; LIST_ENTRY *leptr; REQUEST_STRUCT *rqeptr; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchBegin()\n"); if (Watch.Disabled) { rqptr->rqResponse.HttpStatus = 403; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_GENERAL_DISABLED), FI_LI); SysDclAst (NextTaskFunction, rqptr); return; } if (!rqptr->RemoteUser[0]) { rqptr->rqResponse.HttpStatus = 403; ErrorGeneral (rqptr, ErrorWatchAuthNeeded, FI_LI); SysDclAst (NextTaskFunction, rqptr); return; } if (WatchInUse (rqptr, true)) { SysDclAst (NextTaskFunction, rqptr); return; } ConnectNumber = DurationSeconds = WatchCategory = WatchModule = 0; ClientFilter[0] = PathFilter[0] = RealmFilter[0] = RequestFilter[0] = ServiceFilter[0] = UserFilter[0] = '\0'; DoPeek = DoWatch = FilterOutClient = FilterOutPath = FilterOutRequest = FilterOutRealm = FilterOutService = FilterOutUser = FilterSet = StdoutOnly = StdoutToo = false; StatusFilter = -1; if (rqptr->rqHeader.QueryStringLength) { qptr = rqptr->rqHeader.QueryStringPtr; while (*qptr) { status = StringParseQuery (&qptr, FieldName, sizeof(FieldName), FieldValue, sizeof(FieldValue)); if (VMSnok (status)) { if (status == SS$_IVCHAR) rqptr->rqResponse.HttpStatus = 400; rqptr->rqResponse.ErrorTextPtr = "parsing query string"; ErrorVmsStatus (rqptr, status, FI_LI); SysDclAst (NextTaskFunction, rqptr); return; } if (strsame (FieldName, "at", -1) && FieldValue[0]) { DoPeek = true; ConnectNumber = strtol (FieldValue, NULL, 10); if (Debug) fprintf (stdout, "ConnectNumber: %d\n", ConnectNumber); } else if (strsame (FieldName, "this", -1) && FieldValue[0]) { WatchCategory = WATCH_ONE_SHOT_CAT; #if WATCH_MOD WatchModule = WATCH_ONE_SHOT_MOD; #endif /* WATCH_MOD */ ConnectNumber = strtol (FieldValue, NULL, 10); if (Debug) fprintf (stdout, "ConnectNumber: %d\n", ConnectNumber); } else if (strsame (FieldName, "aut", -1) && FieldValue[0]) WatchCategory |= WATCH_AUTH; else if (strsame (FieldName, "cgi", -1) && FieldValue[0]) WatchCategory |= WATCH_CGI; else if (strsame (FieldName, "con", -1) && FieldValue[0]) WatchCategory |= WATCH_CONNECT; else if (strsame (FieldName, "dcl", -1) && FieldValue[0]) WatchCategory |= WATCH_DCL; else if (strsame (FieldName, "dnt", -1) && FieldValue[0]) WatchCategory |= WATCH_DECNET; else if (strsame (FieldName, "err", -1) && FieldValue[0]) WatchCategory |= WATCH_ERROR; else if (strsame (FieldName, "log", -1) && FieldValue[0]) WatchCategory |= WATCH_LOG; else if (strsame (FieldName, "map", -1) && FieldValue[0]) WatchCategory |= WATCH_MAPPING; else if (strsame (FieldName, "mat", -1) && FieldValue[0]) WatchCategory |= WATCH_MATCH; else if (strsame (FieldName, "net", -1) && FieldValue[0]) WatchCategory |= WATCH_NETWORK; else if (strsame (FieldName, "oct", -1) && FieldValue[0]) WatchCategory |= WATCH_NETWORK_OCTETS; else if (strsame (FieldName, "pxy", -1) && FieldValue[0]) WatchCategory |= WATCH_PROXY; else if (strsame (FieldName, "pca", -1) && FieldValue[0]) WatchCategory |= WATCH_PROXY_CACHE; else if (strsame (FieldName, "pcm", -1) && FieldValue[0]) WatchCategory |= WATCH_PROXY_CACHE_MNT; else if (strsame (FieldName, "prh", -1) && FieldValue[0]) WatchCategory |= WATCH_PROXY_REQU_HDR; else if (strsame (FieldName, "prb", -1) && FieldValue[0]) WatchCategory |= WATCH_PROXY_REQU_BDY; else if (strsame (FieldName, "psh", -1) && FieldValue[0]) WatchCategory |= WATCH_PROXY_RESP_HDR; else if (strsame (FieldName, "psb", -1) && FieldValue[0]) WatchCategory |= WATCH_PROXY_RESP_BDY; else if (strsame (FieldName, "rqp", -1) && FieldValue[0]) WatchCategory |= WATCH_REQUEST; else if (strsame (FieldName, "rqb", -1) && FieldValue[0]) WatchCategory |= WATCH_REQUEST_BODY; else if (strsame (FieldName, "rqh", -1) && FieldValue[0]) WatchCategory |= WATCH_REQUEST_HEADER; else if (strsame (FieldName, "rsp", -1) && FieldValue[0]) WatchCategory |= WATCH_RESPONSE; else if (strsame (FieldName, "rsb", -1) && FieldValue[0]) WatchCategory |= WATCH_RESPONSE_BODY; else if (strsame (FieldName, "rsh", -1) && FieldValue[0]) WatchCategory |= WATCH_RESPONSE_HEADER; else if (strsame (FieldName, "scr", -1) && FieldValue[0]) WatchCategory |= WATCH_SCRIPT; else if (strsame (FieldName, "ssl", -1) && FieldValue[0]) WatchCategory |= WATCH_SESOLA; else if (strsame (FieldName, "tmr", -1) && FieldValue[0]) WatchCategory |= WATCH_TIMER; else if (strsame (FieldName, "dav", -1) && FieldValue[0]) WatchCategory |= WATCH_WEBDAV; else if (strsame (FieldName, "clf", -1)) strcpy (ClientFilter, FieldValue); else if (strsame (FieldName, "clo", -1)) { if (FieldValue[0] == 'o') FilterOutClient = true; } else if (strsame (FieldName, "sef", -1)) strcpy (ServiceFilter, FieldValue); else if (strsame (FieldName, "seo", -1)) { if (FieldValue[0] == 'o') FilterOutService = true; } else if (strsame (FieldName, "rhf", -1)) strcpy (RequestFilter, FieldValue); else if (strsame (FieldName, "rho", -1)) { if (FieldValue[0] == 'o') FilterOutRequest = true; } else if (strsame (FieldName, "paf", -1)) strcpy (PathFilter, FieldValue); else if (strsame (FieldName, "pao", -1)) { if (FieldValue[0] == 'o') FilterOutPath = true; } else if (strsame (FieldName, "sts", -1)) { if (isdigit(FieldValue[0])) StatusFilter = atoi(FieldValue); } else if (strsame (FieldName, "sto", -1)) { /* do absolutely nothing! */ } else if (strsame (FieldName, "arf", -1)) strcpy (RealmFilter, FieldValue); else if (strsame (FieldName, "aro", -1)) { if (FieldValue[0] == 'o') FilterOutRealm = true; } else if (strsame (FieldName, "auf", -1)) strcpy (UserFilter, FieldValue); else if (strsame (FieldName, "auo", -1)) { if (FieldValue[0] == 'o') FilterOutUser = true; } else if (strsame (FieldName, "stdout", -1)) StdoutToo = true; else if (strsame (FieldName, "only", -1)) StdoutOnly = true; else if (strsame (FieldName, "dul", -1) || strsame (FieldName, "dut", -1) || strsame (FieldName, "sec", -1) || strsame (FieldName, "seconds", -1)) { for (cptr = FieldValue; *cptr && !isdigit(*cptr); cptr++); if (*cptr) DurationSeconds = atoi (cptr); } else #if WATCH_MOD if (strsame (FieldName, "_aut", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_AUTH; else if (strsame (FieldName, "_bod", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_BODY; else if (strsame (FieldName, "_cac", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_CACHE; else if (strsame (FieldName, "_cgi", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_CGI; else if (strsame (FieldName, "_con", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_CONFIG; else if (strsame (FieldName, "_dcl", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_DCL; else if (strsame (FieldName, "_det", -1) && FieldValue[0]) WatchModule |= WATCH_MOD__DETAIL; else if (strsame (FieldName, "_dec", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_DECNET; else if (strsame (FieldName, "_dir", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_DIR; else if (strsame (FieldName, "_fao", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_FAO; else if (strsame (FieldName, "_fil", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_FILE; else if (strsame (FieldName, "_hta", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_HTADMIN; else if (strsame (FieldName, "_ins", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_INSTANCE; else if (strsame (FieldName, "_map", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_MAPURL; else if (strsame (FieldName, "_met", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_METACON; else if (strsame (FieldName, "_msg", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_MSG; else if (strsame (FieldName, "_net", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_NET; else if (strsame (FieldName, "_ods", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_ODS; else if (strsame (FieldName, "_oth", -1) && FieldValue[0]) WatchModule |= WATCH_MOD__OTHER; else if (strsame (FieldName, "_pro", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_PROXY; else if (strsame (FieldName, "_put", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_PUT; else if (strsame (FieldName, "_req", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_REQUEST; else if (strsame (FieldName, "_res", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_RESPONSE; else if (strsame (FieldName, "_ser", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_SERVICE; else if (strsame (FieldName, "_ses", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_SESOLA; else if (strsame (FieldName, "_ssi", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_SSI; else if (strsame (FieldName, "_thr", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_THROTTLE; else if (strsame (FieldName, "_upd", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_UPD; else if (strsame (FieldName, "_vm", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_VM; else if (strsame (FieldName, "_dav", -1) && FieldValue[0]) WatchModule |= WATCH_MOD_WEBDAV; else #else if (FieldName[0] == '_') { rqptr->rqResponse.HttpStatus = 403; ErrorGeneral (rqptr, ErrorWatchNoModule, FI_LI); SysDclAst (NextTaskFunction, rqptr); return; } else #endif /* WATCH_MOD */ { rqptr->rqResponse.HttpStatus = 403; ErrorGeneral (rqptr, ErrorWatchQueryString, FI_LI); SysDclAst (NextTaskFunction, rqptr); return; } } } if (WatchCategory || WatchModule) DoWatch = true; if (!DurationSeconds) DurationSeconds = WATCH_ONE_SHOT_DEFAULT_SECONDS; if (!DoPeek && !DoWatch) { rqptr->rqResponse.HttpStatus = 403; ErrorGeneral (rqptr, ErrorWatchQueryString, FI_LI); SysDclAst (NextTaskFunction, rqptr); return; } if (ConnectNumber) { /* find this connection number in the current request list */ for (leptr = RequestList.HeadPtr; leptr; leptr = leptr->NextPtr) { rqeptr = (REQUEST_STRUCT*)leptr; if (Debug) fprintf (stdout, "ConnectNumber: %d\n", rqeptr->ConnectNumber); if (rqeptr->ConnectNumber == ConnectNumber) break; } if (!leptr) { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, ErrorWatchNumber, FI_LI); SysDclAst (NextTaskFunction, rqptr); return; } if (rqeptr == rqptr) { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, ErrorWatchSelf, FI_LI); SysDclAst (NextTaskFunction, rqptr); return; } if (WatchCategory == WATCH_ONE_SHOT_CAT) { rqeptr->WatchItem = WATCH_ONE_SHOT_ITEM; if (rqeptr->DclTaskPtr) rqeptr->DclTaskPtr->WatchItem = WATCH_ONE_SHOT_ITEM; if (rqeptr->ProxyTaskPtr) rqeptr->ProxyTaskPtr->WatchItem = WATCH_ONE_SHOT_ITEM; } } if (WatchCategory == WATCH_ONE_SHOT_CAT) strcpy (CategoryList, "ALL"); else { zptr = (sptr = CategoryList) + 80; /* first the categories */ for (ucnt = 1; ucnt; ucnt = ucnt << 1) { cptr = WatchWhat (WatchCategory & ucnt); if (cptr) { if (sptr > CategoryList) { *sptr++ = ','; if (sptr > zptr) { zptr = sptr + 80; *sptr++ = '\n'; } else *sptr++ = ' '; } while (*cptr) *sptr++ = TOLO(*cptr++); } } /* then any modules */ for (ucnt = 1; ucnt; ucnt = ucnt << 1) { cptr = WatchWhat ((WatchModule & ucnt) | WATCH__MODULE); if (cptr) { if (sptr > CategoryList) { *sptr++ = ','; if (sptr > zptr) { zptr = sptr + 80; *sptr++ = '\n'; } else *sptr++ = ' '; } while (*cptr) *sptr++ = TOLO(*cptr++); } } *sptr = '\0'; } if (RealmFilter[0] || UserFilter[0] || ClientFilter[0] || PathFilter[0] || RequestFilter[0] || ServiceFilter[0] || StatusFilter >= 0) FilterSet = true; if (Debug) fprintf (stdout, "%08.08X %d %d %d %d %d %d %d |%s| %d |%s|%s|%s|%s|%s|%s|%d|\n", WatchCategory, FilterSet, FilterOutClient, FilterOutPath, FilterOutRealm, FilterOutRequest, FilterOutService, FilterOutRequest, CategoryList, DurationSeconds, RealmFilter, UserFilter, ClientFilter, PathFilter, RequestFilter, ServiceFilter, StatusFilter); /* never deflate WATCH output */ rqptr->rqResponse.NoGzip = true; /* generate a WATCH report header */ rqptr->rqResponse.PreExpired = PRE_EXPIRE_WATCH; ResponseHeader200 (rqptr, "text/plain", NULL); vecptr = FaoVector; *vecptr++ = 0; *vecptr++ = ServerHostPort; *vecptr++ = 36 + strlen(ServerHostPort); *vecptr++ = SoftwareID; *vecptr++ = BuildDateTime; *vecptr++ = TcpIpAgentInfo; *vecptr++ = SesolaVersion(); *vecptr++ = strchr(__VMS_VERSION, ' ') - __VMS_VERSION; *vecptr++ = __VMS_VERSION; *vecptr++ = __DECC_VER; *vecptr++ = WatchFuncCc; *vecptr++ = SysInfo.HwName; *vecptr++ = SysInfo.AvailCpuCnt; *vecptr++ = SysInfo.MemoryMB; *vecptr++ = SysInfo.Version; #ifdef ODS_EXTENDED if (OdsExtended) *vecptr++ = "ODS-5 enabled"; else if (SysInfo.VersionInteger >= 720) *vecptr++ = "ODS-5 disabled"; else *vecptr++ = "ODS-5 unavailable"; #else /* ODS_EXTENDED */ *vecptr++ = "ODS-5 unavailable"; #endif /* ODS_EXTENDED */ *vecptr++ = ENAMEL_NAML_USED; *vecptr++ = ENAMEL_FIB_USED; if (Config.cfMisc.GzipResponseCompLevel) { if (VMSok(GzipFindImageStatus)) { *vecptr++ = "!AZ V!AZ"; *vecptr++ = GzipZlibNamePtr; *vecptr++ = GzipZlibVersionPtr; } else { *vecptr++ = "ZLIB !&S"; *vecptr++ = GzipFindImageStatus; } } else *vecptr++ = "ZLIB disabled"; *vecptr++ = Config.cfMisc.RegexSyntax ? "enabled" : "disabled"; *vecptr++ = SysInfo.LockValueBlockSize; if (OperateWithSysPrv) *vecptr++ = ", SYSPRV"; else *vecptr++ = ""; *vecptr++ = CommandLine; *vecptr++ = WatchServerQuotas(); if (DclScriptDetachProcess) { *vecptr++ = "DCL Scripting: detached, !&@PERSONA!AZ !AZ\n"; if (HttpdScriptAsUserName[0]) { if (CliScriptAs[0]) *vecptr++ = "/script=as=!AZ, "; else *vecptr++ = "as !AZ, "; *vecptr++ = HttpdScriptAsUserName; } else *vecptr++ = ""; if (PersonaMacro) *vecptr++ = "_MACRO"; else *vecptr++ = ""; if (DclPersonaServicesAvailable) *vecptr++ = "enabled"; else *vecptr++ = "disabled"; } else { *vecptr++ = "DCL Scripting: subprocess\n\ BYTLM-available:!UL BYTLM-per-subproc:!&@ (approx !&@ subprocesses) \ BYTLM-net-accept:!UL BYTLM-net-listen:!UL\n"; *vecptr++ = HttpdProcess.BytLmAvailable; if (DclMailboxBytLmRequired) { *vecptr++ = "!UL"; *vecptr++ = DclMailboxBytLmRequired; *vecptr++ = "!UL"; *vecptr++ = (HttpdProcess.BytLmAvailable - (NetAcceptBytLmRequired * Config.cfServer.ConnectMax)) / DclMailboxBytLmRequired; } else { *vecptr++ = "?"; *vecptr++ = "?"; } *vecptr++ = NetAcceptBytLmRequired; *vecptr++ = NetListenBytLmRequired; } *vecptr++ = HttpdProcess.PrcNam; *vecptr++ = HttpdProcess.ModeName; *vecptr++ = HttpdProcess.SysInput; *vecptr++ = HttpdProcess.SysOutput; InstanceNodePtr = InstanceClusterPtr = NULL; if (InstanceNodeCurrent > 1) { InstanceLockList (INSTANCE_NODE, ", ", &InstanceNodePtr); if (InstanceNodePtr) { *vecptr++ = "Node: !AZ\n"; *vecptr++ = InstanceNodePtr; } else *vecptr++ = ""; } else *vecptr++ = ""; InstanceLockList (INSTANCE_CLUSTER, ", ", &InstanceClusterPtr); if (InstanceClusterPtr) { *vecptr++ = "Instances: !AZ\n"; *vecptr++ = InstanceClusterPtr; } else *vecptr++ = ""; if (DoWatch && !DoPeek) { *vecptr++ = "Watching: !AZ (!SL!&@)\n!&@"; *vecptr++ = CategoryList; *vecptr++ = WatchCategory; if (WatchModule) { *vecptr++ = "/!SL"; *vecptr++ = WatchModule & ~WATCH__MODULE; } else *vecptr++ = ""; if (FilterSet) { *vecptr++ = "Filter Client:!AZ:\"!AZ\" Service:!AZ:\"!AZ\" Request:!AZ:\"!AZ\" \ Path:!AZ:\"!AZ\" Realm:!AZ:\"!AZ\" User:!AZ:\"!AZ\" Status:IN:\"!&@\"\n"; *vecptr++ = FilterOutClient ? "OUT" : "IN"; *vecptr++ = ClientFilter; *vecptr++ = FilterOutService ? "OUT" : "IN"; *vecptr++ = ServiceFilter; *vecptr++ = FilterOutRequest ? "OUT" : "IN"; *vecptr++ = RequestFilter; *vecptr++ = FilterOutPath ? "OUT" : "IN"; *vecptr++ = PathFilter; *vecptr++ = FilterOutRealm ? "OUT" : "IN"; *vecptr++ = RealmFilter; *vecptr++ = FilterOutUser ? "OUT" : "IN"; *vecptr++ = UserFilter; if (StatusFilter >= 0) { *vecptr++ = "!UL"; *vecptr++ = StatusFilter; } else *vecptr++ = ""; } else *vecptr++ = "Filter: NONE\n"; } else *vecptr++ = ""; status = FaolToBuffer (Buffer, sizeof(Buffer), &Length, ResponseFao, &FaoVector); if (VMSnok (status) || status == SS$_BUFFEROVF) ErrorNoticed (rqptr, status, NULL, FI_LI); if (StdoutToo || StdoutOnly) fputs (Buffer, stdout); NetWrite (rqptr, 0, Buffer, Length); if (InstanceNodePtr) VmFree (InstanceNodePtr, FI_LI); if (InstanceClusterPtr) VmFree (InstanceClusterPtr, FI_LI); if (DoPeek) WatchPeek (rqptr, rqeptr); if (!DoWatch) { SysDclAst (NextTaskFunction, rqptr); return; } /* go on to generate a WATCH processing report */ if (StdoutToo || StdoutOnly) fputs (ResponseWatchingFao, stdout); NetWrite (rqptr, 0, ResponseWatchingFao, sizeof(ResponseWatchingFao)-1); /* might as well use the lowest overhead */ NetReadRaw (rqptr, &WatchDummyReadAst, DummyReadBuffer, sizeof(DummyReadBuffer)); /* now we fill in the other WATCH facility details */ Watch.Category = WatchCategory; Watch.Module = WatchModule & ~WATCH__MODULE; Watch.StdoutOnly = StdoutOnly; Watch.StdoutToo = StdoutToo; Watch.Count = 0; if (Watch.FilterSet = FilterSet) { WatchFilterOutClient = FilterOutClient; WatchFilterOutPath = FilterOutPath; WatchFilterOutRealm = FilterOutRealm; WatchFilterOutRequest = FilterOutRequest; WatchFilterOutService = FilterOutService; WatchFilterOutUser = FilterOutUser; strcpy (WatchClientFilter, ClientFilter); strcpy (WatchPathFilter, PathFilter); strcpy (WatchRequestFilter, RequestFilter); strcpy (WatchServiceFilter, ServiceFilter); strcpy (WatchRealmFilter, RealmFilter); strcpy (WatchUserFilter, UserFilter); WatchStatusFilter = StatusFilter; } /* make sure we get the duration we asked for! */ HttpdTimerSet (rqptr, TIMER_OUTPUT, DurationSeconds); HttpdTimerSet (rqptr, TIMER_NOPROGRESS, DurationSeconds); /* the request now just "hangs", reading WATCH plain-text output! */ #else /* WATCH_CAT */ rqptr->rqResponse.HttpStatus = 403; ErrorGeneral (rqptr, ErrorWatchNoCategory, FI_LI); SysDclAst (NextTaskFunction, rqptr); #endif /* WATCH_CAT */ } /*****************************************************************************/ /* Check and report if the WATCH facility is already being used (locally or via another instance). */ #if WATCH_CAT BOOL WatchInUse ( REQUEST_STRUCT *rqptr, BOOL ReserveWatch ) { BOOL InstanceWatchInUse, LocalWatchInUse; int status; unsigned short Length; unsigned long *vecptr; unsigned long FaoVector [8]; char Buffer [256]; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchInUse()\n"); if (!rqptr) { /* release WATCH */ if (VMSnok (status = InstanceUnLock (INSTANCE_NODE_WATCH))) ErrorExitVmsStatus (status, "InstanceUnLock()", FI_LI); return (false); } LocalWatchInUse = InstanceWatchInUse = false; /* attempt to obtain the WATCH lock */ status = InstanceLockNoWait (INSTANCE_NODE_WATCH); if (status == SS$_NOTQUEUED) { /* the lock is already in use (WATCH is in use elsewhere) */ if (Watch.RequestPtr || Watch.Category || Watch.Module) LocalWatchInUse = true; else InstanceWatchInUse = true; } else { /* allows for CLI WATCH */ if (LocalWatchInUse = Watch.Category || Watch.Module) if (VMSnok (status = InstanceUnLock (INSTANCE_NODE_WATCH))) ErrorExitVmsStatus (status, "InstanceUnLock()", FI_LI); } if (!(LocalWatchInUse || InstanceWatchInUse)) { if (ReserveWatch) Watch.RequestPtr = rqptr; else if (VMSnok (status = InstanceUnLock (INSTANCE_NODE_WATCH))) ErrorExitVmsStatus (status, "InstanceUnLock()", FI_LI); return (false); } vecptr = FaoVector; if (InstanceWatchInUse) *vecptr++ = "via another instance."; else if (Watch.RequestPtr) { *vecptr++ = "by !AZ"; *vecptr++ = UserAtClient(Watch.RequestPtr); } else *vecptr++ = "via /WATCH"; status = FaolToBuffer (Buffer, sizeof(Buffer), &Length, "WATCH is currently in use !&@", &FaoVector); if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); Buffer[Length] = '\0'; rqptr->rqResponse.HttpStatus = 403; ErrorGeneral (rqptr, Buffer, FI_LI); return (true); } #endif /* WATCH_CAT */ /*****************************************************************************/ /* Request using the WATCH facility drops the connection. Release WATCH. */ WatchEnd (REQUEST_STRUCT *rqptr) { #if WATCH_CAT static char BufferFao [] = "|!%T end|\n\0"; unsigned short Length; char Buffer [32]; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchEnd()\n"); if (Watch.RequestPtr != rqptr) ErrorExitVmsStatus (SS$_BUGCHECK, ErrorSanityCheck, FI_LI); FaoToBuffer (Buffer, sizeof(Buffer), &Length, BufferFao, 0); if (rqptr && rqptr->rqResponse.HttpStatus == 200) NetWrite (rqptr, 0, Buffer, Length-1); if (Watch.StdoutToo || Watch.StdoutOnly) fputs (Buffer, stdout); Watch.RequestPtr = NULL; Watch.FilterSet = Watch.StdoutOnly = Watch.StdoutToo = false; Watch.Category = Watch.Count = Watch.Module = 0; WatchFilterOutClient = WatchFilterOutPath = WatchFilterOutRealm = WatchFilterOutRequest = WatchFilterOutService = WatchFilterOutUser = false; WatchClientFilter[0] = WatchPathFilter[0] = WatchRealmFilter[0] = WatchRequestFilter[0] = WatchServiceFilter[0] = WatchUserFilter[0] = '\0'; WatchStatusFilter = -1; WatchInUse (NULL, false); #endif /* WATCH_CAT */ } /*****************************************************************************/ /* The WATCH client concluding the watching can only be detected via a break in connection which in a quiescent system (no requests being processed) can in turn only be detected by a broken network read I/O. This dummy read ASTs to here where the status can be checked and appropriate action taken. */ #if WATCH_CAT WatchDummyReadAst (REQUEST_STRUCT *rqptr) { static char DummyReadBuffer [32]; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchDummyReadAst() NetReadIOsb.Status %%X%08.08X .Count %d\n", rqptr->rqNet.ReadIOsb.Status, rqptr->rqNet.ReadIOsb.Count); if (VMSnok (rqptr->rqNet.ReadIOsb.Status)) { RequestEnd (rqptr); return; } /* just in case it wasn't an error! */ NetReadRaw (rqptr, &WatchDummyReadAst, DummyReadBuffer, sizeof(DummyReadBuffer)); } #endif /* WATCH_CAT */ /*****************************************************************************/ /* Filter first on the client host name or address, then second on the service (virtual host) name. If the filter begins with a scheme (i.e. "http:" or "https:") then filter on that as well. */ WatchFilterClientService (REQUEST_STRUCT *rqptr) { char *aptr, *cptr, *sptr; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchFilterClientService()\n"); #if WATCH_CAT if (!Watch.Category && !Watch.Module) { /* can occur if ASTs are delivered after WATCH use is discontinued */ rqptr->WatchItem = 0; return; } if (!Watch.FilterSet) { /* WATCH is enabled but no filters have been specified. Enable WATCH for *all* requests. Assign a unique number for the life of this request structure. */ if (!rqptr->WatchItem) rqptr->WatchItem = ++Watch.Count; return; } if (!WatchClientFilter[0] && !WatchServiceFilter[0]) return; if (WatchClientFilter[0]) { aptr = "CLIENT"; sptr = WatchClientFilter; if (isdigit(*sptr)) cptr = rqptr->rqClient.IpAddressString; else cptr = rqptr->rqClient.Lookup.HostName; if (Debug) fprintf (stdout, "|%s|%s|\n", cptr, sptr); if (StringMatchRegex (rqptr, cptr, sptr)) { if (WatchFilterOutClient) { WatchFilterDrop (rqptr, aptr); return; } } else if (!WatchFilterOutClient) return; } if (WatchServiceFilter[0]) { if (WatchClientFilter[0]) aptr = "CLIENT+SERVICE"; else aptr = "SERVICE"; sptr = WatchServiceFilter; /* filter on service */ if (Debug) fprintf (stdout, "ServerHostPort |%s|%s|\n", rqptr->ServicePtr->RequestSchemeNamePtr, rqptr->ServicePtr->ServerHostPort); if (MATCH5 (sptr, "http:")) { if (rqptr->ServicePtr->RequestScheme == SCHEME_HTTP) if (WatchFilterOutService) { WatchFilterDrop (rqptr, aptr); return; } sptr += 5; } else if (MATCH6 (sptr, "https:")) { if (rqptr->ServicePtr->RequestScheme == SCHEME_HTTPS) if (WatchFilterOutService) { WatchFilterDrop (rqptr, aptr); return; } sptr += 6; } while (*sptr == '/') sptr++; cptr = rqptr->ServicePtr->ServerHostPort; if (StringMatchRegex (rqptr, cptr, sptr)) { if (WatchFilterOutService) { WatchFilterDrop (rqptr, aptr); return; } } else if (!WatchFilterOutService) return; } if (rqptr->WatchItem) return; WatchFilterAdd (rqptr, aptr); #endif /* WATCH_CAT */ } /*****************************************************************************/ /* Filter on the request's path or URI if the path does not begin with a slash (e.g. if a proxy request). If the filter begins with a dollar and track IDs are being generated consider a track has been specified. */ WatchFilterPathTrack (REQUEST_STRUCT *rqptr) { char *aptr, *cptr, *sptr; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchFilterPathTrack()\n"); #if WATCH_CAT if (!Watch.Category && !Watch.Module) { /* can occur if ASTs are delivered after WATCH use is discontinued */ rqptr->WatchItem = 0; return; } if (!Watch.FilterSet) return; if (!WatchPathFilter[0]) return; /* if filtering-in and it's already being WATChed */ if (!WatchFilterOutPath && rqptr->WatchItem) return; sptr = WatchPathFilter; cptr = NULL; if (Config.cfTrack.Enabled) { if (*sptr == '$') if (rqptr->TrackId[0]) { aptr = "TRACK"; cptr = rqptr->TrackId; } } if (!cptr) { aptr = "PATH"; cptr = rqptr->rqHeader.PathInfoPtr; if (cptr && *cptr != '/') cptr = NULL; } if (!cptr) { aptr = "URI"; cptr = rqptr->rqHeader.RequestUriPtr; } if (!cptr) { if (WatchFilterOutPath) { WatchFilterDrop (rqptr, aptr); return; } } if (StringMatchRegex (rqptr, cptr, sptr)) { if (WatchFilterOutPath) { WatchFilterDrop (rqptr, aptr); return; } } else if (!WatchFilterOutPath) return; if (rqptr->WatchItem) return; WatchFilterAdd (rqptr, aptr); #endif /* WATCH_CAT */ } /*****************************************************************************/ /* Filter first on the *entire* request header (i.e. multiple, newline-separated lines). */ WatchFilterRequestHeader (REQUEST_STRUCT *rqptr) { char *aptr, *cptr, *sptr; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchFilterRequestHeader()\n"); #if WATCH_CAT if (!Watch.Category && !Watch.Module) { /* can occur if ASTs are delivered after WATCH use is discontinued */ rqptr->WatchItem = 0; return; } if (!Watch.FilterSet) return; if (!WatchRequestFilter[0]) return; /* if filtering-in and it's already being WATChed */ if (!WatchFilterOutRequest && rqptr->WatchItem) return; aptr = "REQUEST"; sptr = WatchRequestFilter; cptr = rqptr->rqHeader.RequestHeaderPtr; if (StringMatchRegex (rqptr, cptr, sptr)) { if (WatchFilterOutRequest) { WatchFilterDrop (rqptr, aptr); return; } } else if (!WatchFilterOutRequest) return; if (rqptr->WatchItem) return; WatchFilterAdd (rqptr, aptr); #endif /* WATCH_CAT */ } /*****************************************************************************/ /* Filter on the HTTP status value (late in the request I know). */ WatchFilterHttpStatus (REQUEST_STRUCT *rqptr) { char *aptr; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchFilterRequestHeader()\n"); #if WATCH_CAT if (!Watch.Category && !Watch.Module) { /* can occur if ASTs are delivered after WATCH use is discontinued */ rqptr->WatchItem = 0; return; } if (!Watch.FilterSet) return; if (WatchStatusFilter < 0) return; /* if it's already being WATChed */ if (rqptr->WatchItem) return; aptr = "STATUS"; if ((WatchStatusFilter && WatchStatusFilter <= 5 && rqptr->rqResponse.HttpStatus / 100 == WatchStatusFilter) || rqptr->rqResponse.HttpStatus == WatchStatusFilter) { if (WatchFilterOutRequest) { WatchFilterDrop (rqptr, aptr); return; } } else if (!WatchFilterOutRequest) return; if (rqptr->WatchItem) return; WatchFilterAdd (rqptr, aptr); /* as this occurs VERY late in request processing provide additional data */ if (WATCH_CATEGORY(WATCH_REQUEST)) WatchThis (rqptr, FI_LI, WATCH_REQUEST, "!AZ !&P", rqptr->rqHeader.MethodName, rqptr->rqHeader.RequestUriPtr); if (WATCH_CATEGORY(WATCH_REQUEST_HEADER)) { WatchThis (rqptr, FI_LI, WATCH_REQUEST_HEADER, "HEADER !UL bytes", rqptr->rqHeader.RequestHeaderLength); WatchData (rqptr->rqHeader.RequestHeaderPtr, rqptr->rqHeader.RequestHeaderLength); } if (WATCH_CATEGORY(WATCH_AUTH)) if (rqptr->RemoteUser[0]) WatchThis (rqptr, FI_LI, WATCH_AUTH, "user:\'!AZ\' details:\'!AZ\' can:!AZ remote:\'!AZ\' realm:\'!AZ\'", rqptr->RemoteUser, rqptr->rqAuth.UserDetailsPtr, AuthCanString (rqptr->rqAuth.RequestCan, AUTH_CAN_FORMAT_LONG), rqptr->rqAuth.RemoteUser, rqptr->rqAuth.RealmPtr); #endif /* WATCH_CAT */ } /*****************************************************************************/ /* Filter first on authentication realm (if applicable) then on authenticated (remote) user (if applicable). */ WatchFilterRealmUser (REQUEST_STRUCT *rqptr) { char *aptr, *cptr, *sptr; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchFilterRealmUser()\n"); #if WATCH_CAT if (!Watch.Category && !Watch.Module) { /* can occur if ASTs are delivered after WATCH use is discontinued */ rqptr->WatchItem = 0; return; } if (!Watch.FilterSet) return; if (!WatchRealmFilter[0] && !WatchUserFilter[0]) return; /* if filtering-in and it's already being WATChed */ if (!WatchFilterOutRealm && !WatchFilterOutUser && rqptr->WatchItem) return; if (WatchRealmFilter[0]) { aptr = "REALM"; sptr = WatchRealmFilter; cptr = rqptr->rqAuth.RealmPtr; if (StringMatchRegex (rqptr, cptr, sptr)) { if (WatchFilterOutRealm) { WatchFilterDrop (rqptr, aptr); return; } } else if (!WatchFilterOutRealm) return; } if (WatchUserFilter[0]) { if (WatchRealmFilter[0]) aptr = "REALM+USER"; else aptr = "USER"; sptr = WatchUserFilter; cptr = rqptr->RemoteUser; if (StringMatchRegex (rqptr, cptr, sptr)) { if (WatchFilterOutUser) { WatchFilterDrop (rqptr, aptr); return; } } else if (!WatchFilterOutUser) return; } if (rqptr->WatchItem) return; WatchFilterAdd (rqptr, aptr); /* as this occurs late in request processing provide additional data */ if (WATCHING(rqptr) && WATCH_CATEGORY(WATCH_REQUEST_HEADER)) { WatchThis (rqptr, FI_LI, WATCH_REQUEST_HEADER, "HEADER !UL bytes", rqptr->rqHeader.RequestHeaderLength); WatchData (rqptr->rqHeader.RequestHeaderPtr, rqptr->rqHeader.RequestHeaderLength); } #endif /* WATCH_CAT */ } /*****************************************************************************/ /* If the request is not already being WATCHED then allocate a WATCH item number and report it's addition. */ WatchFilterAdd ( REQUEST_STRUCT *rqptr, char *AddingThis ) { /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchFilterAdd()\n"); #if WATCH_CAT if (!rqptr->WatchItem) { /* assign a unique number for the life of this request structure */ rqptr->WatchItem = ++Watch.Count; if (isdigit(rqptr->rqClient.Lookup.HostName[0])) WatchThis (rqptr, FI_LI, WATCH_FILTER, "!AZ adding !AZ to WATCH", AddingThis, rqptr->rqClient.IpAddressString); else WatchThis (rqptr, FI_LI, WATCH_FILTER, "!AZ adding !AZ (!AZ) to WATCH", AddingThis, rqptr->rqClient.Lookup.HostName, rqptr->rqClient.IpAddressString); } #endif /* WATCH_CAT */ } /*****************************************************************************/ /* If the request is currently being WATCHED then report it's removal and reset the WATCH item number. */ WatchFilterDrop ( REQUEST_STRUCT *rqptr, char *DroppingThis ) { /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchFilterDrop()\n"); #if WATCH_CAT if (rqptr->WatchItem) WatchThis (rqptr, FI_LI, WATCH_FILTER, "!AZ dropping from WATCH", DroppingThis); rqptr->WatchItem = 0; #endif /* WATCH_CAT */ } /*****************************************************************************/ /* VARIABLE LENGTH ARGUMENT LIST. Function to provide a formatted WATCH entry, with trailing information from the caller. 'ReportFormat' parameter must be in a sys$fao() acceptable format and sufficient variable number parameters be supplied to satisfy any FAO directives in that format string. The report line is then generated and output to either 'stdout' (the server process log if /WATCH= qualifier was used) or to the request structure pointed to by the gloabl storage 'Watch.RequestPtr' (if a request-based WATCH is in use). */ WatchThis ( REQUEST_STRUCT *rqptr, char *SourceModuleName, int SourceLineNumber, int Category, char *ReportFormat, ... ) { #if WATCH_CAT static char BufferFao [] = "|!%T !8AZ !4ZL !4ZL !10AZ !&@|\n!AZ"; int status, argcnt; unsigned short Length; unsigned long *vecptr; unsigned long FaoVector [128]; char *cptr; char Buffer [2048]; va_list argptr; WATCH_STRUCT WatchBuffer; /*********/ /* begin */ /*********/ va_count (argcnt); if (Debug) fprintf (stdout, "WatchThis() %s %d |%s| %d\n", SourceModuleName, SourceLineNumber, ReportFormat, argcnt); /* this can occur if ASTs are delivered after WATCH use is discontinued */ if (!Watch.Category && !Watch.Module) return; /* can't have module watching active while using the same functions!! */ memcpy (&WatchBuffer, &Watch, sizeof(WatchBuffer)); Watch.Category = Watch.Module = 0; vecptr = FaoVector; *vecptr++ = 0; *vecptr++ = SourceModuleName; *vecptr++ = SourceLineNumber; if (!rqptr) *vecptr++ = -1; else if (!rqptr->WatchItem) *vecptr++ = -1; else *vecptr++ = rqptr->WatchItem % 10000; if (!(cptr = WatchWhat (Category))) cptr = "????????"; *vecptr++ = cptr; /* append the report format string and it's parameters */ *vecptr++ = ReportFormat; va_start (argptr, ReportFormat); for (argcnt -= 5; argcnt; argcnt--) *vecptr++ = va_arg (argptr, unsigned long); va_end (argptr); if (!(Category & WATCH__MODULE) && Category & WATCH_TIMER) *vecptr++ = WatchServerQuotas (); else *vecptr++ = ""; status = FaolToBuffer (Buffer, sizeof(Buffer), &Length, BufferFao, &FaoVector); if (VMSnok (status) || status == SS$_BUFFEROVF) fprintf (stdout, "%%HTTPD-W-NOTICED2, %s:%d FaolToBuffer() %%X%08.08X\n", FI_LI, status); if (Debug) fprintf (stdout, "|%s|\n", Buffer); if (!Watch.RequestPtr || Watch.StdoutToo || Watch.StdoutOnly) fputs (Buffer, stdout); if (Watch.RequestPtr && (!Watch.StdoutOnly || Category == WATCH_CONNECT)) NetWrite (Watch.RequestPtr, 0, Buffer, Length); /* restore previous values */ memcpy (&Watch, &WatchBuffer, sizeof(Watch)); #endif /* WATCH_CAT */ } /*****************************************************************************/ /* VARIABLE LENGTH ARGUMENT LIST. Function to provide a formatted data WATCH entry, with trailing information from the caller. 'DataFormat' parameter must be in a sys$fao() acceptable format and sufficient variable number parameters be supplied to satisfy any FAO directives in that format string. Should include appropriate carriage-control. */ WatchDataFormatted ( char *DataFormat, ... ) { #if WATCH_CAT int status, argcnt; unsigned short Length; unsigned long *vecptr; unsigned long FaoVector [64]; char Buffer [65535]; va_list argptr; /*********/ /* begin */ /*********/ va_count (argcnt); if (Debug) fprintf (stdout, "WatchDataFormatted() |%s| %d\n", DataFormat, argcnt); /* this can occur if ASTs are delivered after WATCH use is discontinued */ if (!Watch.Category && !Watch.Module) return; vecptr = FaoVector; va_start (argptr, DataFormat); for (argcnt -= 1; argcnt; argcnt--) *vecptr++ = va_arg (argptr, unsigned long); va_end (argptr); status = FaolToBuffer (Buffer, sizeof(Buffer), &Length, DataFormat, &FaoVector); if (VMSnok (status) || status == SS$_BUFFEROVF) ErrorNoticed (NULL, status, NULL, FI_LI); Buffer[Length] = '\0'; if (Debug) fprintf (stdout, "|%s|\n", Buffer); if (!Watch.RequestPtr || Watch.StdoutToo || Watch.StdoutOnly) fputs (Buffer, stdout); if (Watch.RequestPtr && !Watch.StdoutOnly) NetWrite (Watch.RequestPtr, 0, Buffer, Length); #endif /* WATCH_CAT */ } /*****************************************************************************/ /* Output the supplied, non-formatted data in the WATCH report. Allows any printable output to be included as a block in the WATCH output. */ WatchData ( char *DataPtr, int DataLength ) { #if WATCH_CAT /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchData()\n"); /* this can occur if ASTs are delivered after WATCH use is discontinued */ if (!Watch.Category && !Watch.Module) return; if (!DataPtr) return; if (DataLength == -1) DataLength = strlen(DataPtr); if (!Watch.RequestPtr || Watch.StdoutToo || Watch.StdoutOnly) fwrite (DataPtr, DataLength, 1, stdout); if (Watch.RequestPtr && !Watch.StdoutOnly) NetWrite (Watch.RequestPtr, 0, DataPtr, DataLength); if (DataLength && DataPtr[DataLength-1] == '\n') return; if (!Watch.RequestPtr || Watch.StdoutToo || Watch.StdoutOnly) fputs ("\n", stdout); if (Watch.RequestPtr && !Watch.StdoutOnly) NetWrite (Watch.RequestPtr, 0, "\n", 1); #endif /* WATCH_CAT */ } /*****************************************************************************/ /* Ouput the supplied data using WATCH as a hex and printable character dump. */ WatchDataDump ( char *DataPtr, int DataLength ) { #if WATCH_CAT /* 32 bytes by 128 lines comes out to 4096 bytes, the default buffer-full */ #define MAX_LINES 128 #define BYTES_PER_LINE 32 #define BYTES_PER_GROUP 4 #define GROUPS_PER_LINE (BYTES_PER_LINE / BYTES_PER_GROUP) #define CHARS_PER_LINE ((BYTES_PER_LINE * 3) + GROUPS_PER_LINE + 1) static char HexDigits [] = "0123456789ABCDEF"; int ByteCount, CurrentDataCount, DataCount; char *cptr, *sptr, *zptr, *CurrentDataPtr, *CurrentDumpPtr; char DumpBuffer [(CHARS_PER_LINE * MAX_LINES)+1]; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchDataDump() %d\n", DataLength); /* this can occur if ASTs are delivered after WATCH use is discontinued */ if (!Watch.Category && !Watch.Module) return; if (!DataPtr) return; zptr = (sptr = DumpBuffer) + sizeof(DumpBuffer)-1; cptr = DataPtr; DataCount = DataLength; while (DataCount) { CurrentDumpPtr = sptr; CurrentDataPtr = cptr; CurrentDataCount = DataCount; ByteCount = BYTES_PER_LINE; while (ByteCount && DataCount) { *sptr++ = HexDigits[*(unsigned char*)cptr >> 4]; *sptr++ = HexDigits[*(unsigned char*)cptr & 0xf]; cptr++; DataCount--; ByteCount--; if (!(ByteCount % BYTES_PER_GROUP)) *sptr++ = ' '; } while (ByteCount) { *sptr++ = ' '; *sptr++ = ' '; ByteCount--; if (!(ByteCount % BYTES_PER_GROUP)) *sptr++ = ' '; } cptr = CurrentDataPtr; DataCount = CurrentDataCount; ByteCount = BYTES_PER_LINE; while (ByteCount && DataCount) { if (isalnum(*cptr) || ispunct(*cptr) || *cptr == ' ') *sptr++ = *cptr++; else { *sptr++ = '.'; cptr++; } DataCount--; ByteCount--; } *sptr++ = '\n'; if (Debug) { *sptr = '\0'; /** fprintf (stdout, "|%s|\n", CurrentDumpPtr); **/ } if (!DataCount || !ByteCount) { *sptr = '\0'; WatchData (DumpBuffer, sptr - DumpBuffer); zptr = (sptr = DumpBuffer) + sizeof(DumpBuffer)-1; } } #endif /* WATCH_CAT */ } /*****************************************************************************/ /* Return a pointer to a static string containing current server process quotas compared to what the server originally started with. */ #if WATCH_CAT char* WatchServerQuotas () { static $DESCRIPTOR (QuotasFaoDsc, "AST:!UL/!UL BIO:!UL/!UL BYT:!UL/!UL DIO:!UL/!UL ENQ:!UL/!UL \ FIL:!UL/!UL PGFL:!UL/!UL PRC:!UL/!UL TQ:!UL/!UL\n\0"); static char Buffer [256]; static $DESCRIPTOR (BufferDsc, Buffer); static int JpiAstCnt, JpiBioCnt, JpiBytCnt, JpiDioCnt, JpiEnqCnt, JpiFilCnt, JpiPagFilCnt, JpiPrcCnt, JpiTqCnt; static struct { unsigned short BufferLength; unsigned short ItemCode; unsigned long BufferAddress; unsigned long ReturnLengthAddress; } JpiItem [] = { { sizeof(JpiAstCnt), JPI$_ASTCNT, &JpiAstCnt, 0 }, { sizeof(JpiBioCnt), JPI$_BIOCNT, &JpiBioCnt, 0 }, { sizeof(JpiBytCnt), JPI$_BYTCNT, &JpiBytCnt, 0 }, { sizeof(JpiDioCnt), JPI$_DIOCNT, &JpiDioCnt, 0 }, { sizeof(JpiEnqCnt), JPI$_ENQCNT, &JpiEnqCnt, 0 }, { sizeof(JpiFilCnt), JPI$_FILCNT, &JpiFilCnt, 0 }, { sizeof(JpiPagFilCnt), JPI$_PAGFILCNT, &JpiPagFilCnt, 0 }, { sizeof(JpiPrcCnt), JPI$_PRCCNT, &JpiPrcCnt, 0 }, { sizeof(JpiTqCnt), JPI$_TQCNT, &JpiTqCnt, 0 }, { 0,0,0,0 } }; int status; unsigned long *vecptr; unsigned long FaoVector [32]; IO_SB IOsb; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchServerQuotas()\n"); status = sys$getjpiw (EfnWait, 0, 0, &JpiItem, &IOsb, 0, 0); if (VMSok (status)) status = IOsb.Status; if (VMSnok (status)) { fprintf (stdout, "%%HTTPD-W-NOTICED2, %s:%d sys$getjpiw() %%X%08.08X\n", FI_LI, status); return ("sys$getjpiw() failed!"); } vecptr = &FaoVector; *vecptr++ = JpiAstCnt; *vecptr++ = HttpdProcess.AstLm; *vecptr++ = JpiBioCnt; *vecptr++ = HttpdProcess.BioLm; *vecptr++ = JpiBytCnt; *vecptr++ = HttpdProcess.BytLm; *vecptr++ = JpiDioCnt; *vecptr++ = HttpdProcess.DioLm; *vecptr++ = JpiEnqCnt; *vecptr++ = HttpdProcess.EnqLm; *vecptr++ = JpiFilCnt; *vecptr++ = HttpdProcess.FilLm; *vecptr++ = JpiPagFilCnt; *vecptr++ = HttpdProcess.PgFlQuo; *vecptr++ = JpiPrcCnt; *vecptr++ = HttpdProcess.PrcLm; *vecptr++ = JpiTqCnt; *vecptr++ = HttpdProcess.TqLm; status = sys$faol (&QuotasFaoDsc, NULL, &BufferDsc, &FaoVector); if (VMSnok (status) || status == SS$_BUFFEROVF) fprintf (stdout, "%%HTTPD-W-NOTICED2, %s:%d sys$faol() %%X%08.08X\n", FI_LI, status); return (Buffer); } #endif /* WATCH_CAT */ /*****************************************************************************/ /* Return a string corresponding to the function name of the address passed in 'FunctionPtr'. The '#include watchfunc.h" below provides a static array containing function address and name details that during module WATCHing can be used by the FAO.C ('!&F') '!&A' directive to provide function names rather than just address information. Returns NULL if the address is unknown. The 'watchfunc.h' file is generated by the BUILD_WATCHFUNC.COM procedure. */ char* WatchFunction (void *FunctionPtr) { int idx; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchFunction() 0x%08.08x\n", FunctionPtr); if (!FunctionPtr) return (NULL); for (idx = 0; WatchFunc[idx].Address; idx++) if (WatchFunc[idx].Address == FunctionPtr) break; return (WatchFunc[idx].Name); } /*****************************************************************************/ /* Return a string corresponding to the bit set in the 'Category' parameter. */ #if WATCH_CAT char* WatchWhat (int Category) { /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchWhat() %d\n", Category); if (!(Category & WATCH__MODULE)) { switch (Category) { case WATCH_AUTH : return ("AUTHORIZE"); case WATCH_CONNECT : return ("CONNECT"); case WATCH_CGI : return ("CGI"); case WATCH_DCL : return ("DCL"); case WATCH_DECNET : return ("DECNET"); case WATCH_ERROR : return ("ERROR"); case WATCH_FILTER : return ("FILTER"); case WATCH_LOG : return ("LOG"); case WATCH_MAPPING : return ("MAPPING"); case WATCH_MATCH : return ("MATCH"); case WATCH_NETWORK : return ("NETWORK"); case WATCH_NETWORK_OCTETS : return ("NET-OCTETS"); case WATCH_NOTICED : return ("NOTICED"); case WATCH_PROXY : return ("PROXY"); case WATCH_PROXY_CACHE : return ("PRO-CACHE"); case WATCH_PROXY_CACHE_MNT : return ("PRO-CAC-MAINTENANCE"); case WATCH_PROXY_REQU_HDR : return ("PRO-REQ-HEADER"); case WATCH_PROXY_REQU_BDY : return ("PRO-REQ-BODY"); case WATCH_PROXY_RESP_HDR : return ("PRO-RES-HEADER"); case WATCH_PROXY_RESP_BDY : return ("PRO-RES-BODY"); case WATCH_REQUEST : return ("REQUEST"); case WATCH_REQUEST_BODY : return ("REQ-BODY"); case WATCH_REQUEST_HEADER : return ("REQ-HEADER"); case WATCH_RESPONSE : return ("RESPONSE"); case WATCH_RESPONSE_BODY : return ("RES-BODY"); case WATCH_RESPONSE_HEADER : return ("RES-HEADER"); case WATCH_SCRIPT : return ("SCRIPT"); case WATCH_SESOLA : return ("SSL"); case WATCH_TIMER : return ("TIMER"); case WATCH_WEBDAV : return ("WEBDAV"); } } #if WATCH_MOD switch (Category) { case WATCH_MOD_AUTH : return ("_AUTH.."); case WATCH_MOD_BODY : return ("_BODY"); case WATCH_MOD_CACHE : return ("_CACHE"); case WATCH_MOD_CGI : return ("_CGI"); case WATCH_MOD_CONFIG : return ("_CONFIG"); case WATCH_MOD_DCL : return ("_DCL"); case WATCH_MOD_DECNET : return ("_DECNET"); case WATCH_MOD_DIR : return ("_DIR"); case WATCH_MOD_FAO : return ("_FAO"); case WATCH_MOD_FILE : return ("_FILE"); case WATCH_MOD_HTADMIN : return ("_HTADMIN"); case WATCH_MOD_INSTANCE : return ("_INSTANCE"); case WATCH_MOD_MAPURL : return ("_MAPURL"); case WATCH_MOD_METACON : return ("_METACON"); case WATCH_MOD_MSG : return ("_MSG"); case WATCH_MOD_NET : return ("_NET"); case WATCH_MOD_REQUEST : return ("_REQUEST"); case WATCH_MOD_ODS : return ("_ODS"); case WATCH_MOD_PUT : return ("_PUT"); case WATCH_MOD_PROXY : return ("_PROXY.."); case WATCH_MOD_RESPONSE : return ("_RESPONSE"); case WATCH_MOD_SERVICE : return ("_SERVICE"); case WATCH_MOD_SESOLA : return ("_SESOLA.."); case WATCH_MOD_SSI : return ("_SSI"); case WATCH_MOD_THROTTLE : return ("_THROTTLE"); case WATCH_MOD_UPD : return ("_UPD"); case WATCH_MOD_VM : return ("_VM"); case WATCH_MOD_WEBDAV : return ("_WEBDAV"); /* special cases (no pun intended) */ case WATCH_MOD__DETAIL : return ("_detail"); case WATCH_MOD__OTHER : return ("_other"); } #endif /* WATCH_MOD */ return (NULL); } #endif /* WATCH_CAT */ /*****************************************************************************/ /* Parse the /WATCH= qualifier string for command-line startup control. General format is "/WATCH=[NOSTARTUP,]items[,module][,client][,service][,path/track]". The first mandatory parameter, 'items', may be preceded by an optional NOSTARTUP keyword. This suppresses all WATCH output until the server is ready to accept requests (reducing the some WATCH item output considerably). The 'items' parameter can be one or two numbers representing the items to be displayed (these may be found in the WATCH report output) or more conveniently can be a parenthesized, comma-separated list of item names. For example, "/WATCH=ITEM=(MAPPING,REQUEST,RESPONSE)" and/or module names, "/WATCH=ITEM=(REQUEST,RESPONSE,_AUTH..,_MAPURL,_METACON)". The item names can be any found in WatchWhat() immediately above and must be supplied exactly as the strings appear in the switch() statement above (i.e. note some have trailing ".."). */ BOOL WatchCliParse (char *String) { #if WATCH_CAT BOOL EndItemList, NoItem; unsigned long Category; char *cptr, *sptr, *zptr; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchCliParse() |%s|\n", String); if (strsame (String, "/NOWATCH", 6)) { WatchCli.Disabled = -1; return (true); } if (WatchCli.Disabled < 0) return (true); cptr = String; while (*cptr && *cptr != '=') cptr++; while (*cptr == '=' || *cptr == '\"') cptr++; if (!*cptr) return (true); if (Debug) fprintf (stdout, "cptr |%s|\n", cptr); if (*cptr == '(') cptr++; if (strsame (cptr, "LIST", -1)) { char CategoryList [WATCH_CATEGORY_LIST_SIZE]; sptr = CategoryList; for (Category = 1; Category; Category = Category << 1) { cptr = WatchWhat (Category); if (cptr) { if (sptr > CategoryList) { *sptr++ = ','; *sptr++ = ' '; } while (*cptr) *sptr++ = TOLO(*cptr++); } } #if WATCH_MOD /* then any modules */ for (Category = 1; Category; Category = Category << 1) { cptr = WatchWhat (Category | WATCH__MODULE); if (cptr) { if (sptr > CategoryList) { *sptr++ = ','; *sptr++ = ' '; } while (*cptr) *sptr++ = TOLO(*cptr++); } } #endif /* WATCH_MOD */ *sptr = '\0'; FaoToStdout ("%HTTPD-I-WATCH, !AZ\n", CategoryList); exit (SS$_NORMAL); } if (strsame (cptr, "NOSTARTUP", 7)) { WatchCliNoStartup = true; while (isalpha(*cptr)) cptr++; if (*cptr == ',' || *cptr == '=') cptr++; } if (strsame (cptr, "ITEM=(", 6) || strsame (cptr, "ITEMS=(", 7)) { cptr += 6; if (*cptr == '(') cptr++; WatchCli.Category = WatchCli.Module = 0; EndItemList = false; while (*cptr && *cptr != ')' && !EndItemList) { sptr = cptr; while (*cptr && *cptr != ',' && *cptr != ')') cptr++; if (*cptr == ')') EndItemList = true; if (*cptr) *cptr++ = '\0'; if (strsame (sptr, "NO", 2) && !strsame (sptr, "NOTICED", -1)) { NoItem = true; sptr += 2; } else NoItem = false; if (Debug) fprintf (stdout, "sptr |%s|\n", sptr); for (Category = 1; Category; Category = Category << 1) { zptr = WatchWhat (Category); if (zptr && strsame (sptr, zptr, -1)) { if (NoItem) WatchCli.Category &= ~Category; else WatchCli.Category |= Category; break; } zptr = WatchWhat (Category | WATCH__MODULE); if (zptr && strsame (sptr, zptr, -1)) { if (NoItem) WatchCli.Module &= ~Category; else WatchCli.Module |= Category; break; } } if (!Category) { if (strsame (sptr, "ALLCAT", -1)) WatchCli.Category |= (Category = 0x7fffffff); else if (strsame (sptr, "ALLMOD", -1)) WatchCli.Module |= (Category = 0x7fffffff); } if (!Category) { FaoToStdout ("%HTTPD-E-WATCH, unknown item\n \\!AZ\\\n", sptr); return (false); } if (*cptr == ',') cptr++; } } else { if (!(WatchCli.Category = atoi(cptr))) { FaoToStdout ("%HTTPD-E-WATCH, invalid category number"); return (false); } while (*cptr && (*cptr == '-' || isdigit(*cptr))) cptr++; if (*cptr == ',') cptr++; if (*cptr == '-' || isdigit(*cptr)) { if (!(WatchCli.Module = atoi(cptr))) { FaoToStdout ("%HTTPD-E-WATCH, invalid module number"); return (false); } while (*cptr && (*cptr == '-' || isdigit(*cptr))) cptr++; if (*cptr == ',') cptr++; } } if (Debug) fprintf (stdout, "cptr |%s|\n", cptr); if (*cptr == ')') return (true); zptr = (sptr = WatchClientFilter) + sizeof(WatchClientFilter); while (*cptr && *cptr != ',' && *cptr != '\"' && sptr < zptr) *sptr++ = *cptr++; if (sptr >= zptr) { FaoToStdout ("%HTTPD-E-WATCH, invalid client filter"); return (false); } *sptr = '\0'; if (*cptr == ',') cptr++; if (Debug) fprintf (stdout, "cptr |%s|\n", cptr); if (*cptr == ')') return (true); zptr = (sptr = WatchServiceFilter) + sizeof(WatchServiceFilter); while (*cptr && *cptr != ',' && *cptr != '\"' && sptr < zptr) *sptr++ = *cptr++; if (sptr >= zptr) { FaoToStdout ("%HTTPD-E-WATCH, invalid service filter"); return (false); } *sptr = '\0'; if (*cptr == ',') cptr++; if (Debug) fprintf (stdout, "cptr |%s|\n", cptr); if (*cptr == ')') return (true); zptr = (sptr = WatchPathFilter) + sizeof(WatchPathFilter); while (*cptr && *cptr != ',' && *cptr != '\"' && sptr < zptr) *sptr++ = *cptr++; if (sptr >= zptr) { FaoToStdout ("%HTTPD-E-WATCH, invalid path/track filter"); return (false); } *sptr = '\0'; if (!WatchClientFilter[0]) strcpy (WatchClientFilter, "*"); if (!WatchPathFilter[0]) strcpy (WatchPathFilter, "*"); if (!WatchServiceFilter[0]) strcpy (WatchServiceFilter, "*"); return (true); #else /* WATCH_CAT */ FaoToStdout ("%HTTPD-E-WATCH, is not a compiled option"); return (false); #endif /* WATCH_CAT */ } /*****************************************************************************/ /* Just print out the current WATCH settings. */ WatchCliSettings () { #if WATCH_CAT unsigned long Category; char *cptr, *sptr; char CategoryList [WATCH_CATEGORY_LIST_SIZE]; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchCliSettings()\n"); if (WatchCli.Disabled) { FaoToStdout ("%HTTPD-I-WATCH, disabled\n"); return; } if (!WatchCli.Category && !WatchCli.Module) return; sptr = CategoryList; /* first any categories */ for (Category = 1; Category; Category = Category << 1) { cptr = WatchWhat (WatchCli.Category & Category); if (cptr) { if (sptr > CategoryList) { *sptr++ = ','; *sptr++ = ' '; } while (*cptr) *sptr++ = TOLO(*cptr++); } } /* then any modules */ for (Category = 1; Category; Category = Category << 1) { cptr = WatchWhat ((WatchCli.Module & Category) | WATCH__MODULE); if (cptr) { if (sptr > CategoryList) { *sptr++ = ','; *sptr++ = ' '; } while (*cptr) *sptr++ = TOLO(*cptr++); } } *sptr = '\0'; FaoToStdout ( "%HTTPD-I-WATCH, !&?NOSTARTUP \r\r(!SL,!SL) !AZ\n\ -WATCH-I-CLIENT, client filter \"!AZ\"\n\ -WATCH-I-SERVICE, service filter \"!AZ\"\n\ -WATCH-I-PATH, path/track filter \"!AZ\"\n", WatchCliNoStartup, WatchCli.Category, WatchCli.Module, CategoryList, WatchClientFilter, WatchServiceFilter, WatchPathFilter); #endif /* WATCH_CAT */ } /*****************************************************************************/ /* Generate a report page listing all of the processes belonging to the server process. */ /* seems a lot but I recall some site having a HUGE number of IDs */ #define JPI_PROCESS_RIGHTS_MAX 1024 #define PSCAN$_GETJPI_BUFFER_SIZE 24 WatchProcessReport ( REQUEST_STRUCT *rqptr, REQUEST_AST NextTaskFunction ) { static char BeginPage [] = "

\n\ \ \ \ \ \ \ \ \ \n\ \n"; /* the final column just adds a little white-space on the page far right */ static char ProcessFao [] = "\ \ !8XL  \ !AZ  \ !AZ  \ !AZ  \ !AZ  \ !AZ  \ \ \ \n"; static char EndPageFao [] = "
PID  User  Process Name  Image  Mode  State  Priority
!3ZL  !UL / !UL  
\n\


\n\ \n\ \n"; static char *StateNameArray [] = { "1234","COLPG","MWAIT","CEF","PFW","LEF","LEFO", "HIB","HIBO","SUSP","SUSPO","FPG","COM","COMO","CUR" }; static unsigned long GetJpiControlFlags = JPI$M_IGNORE_TARGET_STATUS; static unsigned long JpiMode, JpiPid, JpiPri, JpiPrib, JpiRightsSize, JpiState; static char JpiImagName [256], JpiNodeName [32], JpiPrcNam [16], JpiUserName [13]; static struct { unsigned short buf_len; unsigned short item; unsigned char *buf_addr; unsigned short *short_ret_len; } JpiItems [] = { { sizeof(GetJpiControlFlags), JPI$_GETJPI_CONTROL_FLAGS, &GetJpiControlFlags, 0 }, { sizeof(JpiPid), JPI$_PID, &JpiPid, 0 }, { sizeof(JpiPri), JPI$_PRI, &JpiPri, 0 }, { sizeof(JpiPrib), JPI$_PRIB, &JpiPrib, 0 }, { sizeof(JpiMode), JPI$_MODE, &JpiMode, 0 }, { sizeof(JpiImagName), JPI$_IMAGNAME, &JpiImagName, 0 }, { sizeof(JpiPrcNam), JPI$_PRCNAM, &JpiPrcNam, 0 }, { sizeof(JpiUserName), JPI$_USERNAME, &JpiUserName, 0 }, { sizeof(JpiState), JPI$_STATE, &JpiState, 0 }, { sizeof(JpiRightsSize), JPI$_RIGHTS_SIZE, &JpiRightsSize, 0 }, #define JPI_PROCESS_RIGHTS_ITEM 10 { 0, JPI$_PROCESS_RIGHTS, 0, 0 }, { 0,0,0,0 } }, ScanItems [] = { { 0, PSCAN$_GETJPI_BUFFER_SIZE, 2048, 0}, { 0,0,0,0 } }; int idx, status, IdentCount, ProcessCount, SetPrvStatus; unsigned long *vecptr; unsigned long ProcessContext; unsigned long FaoVector [32]; char *cptr, *sptr, *StateNamePtr; unsigned long JpiProcessRights [JPI_PROCESS_RIGHTS_MAX*2]; IO_SB IOsb; /*********/ /* begin */ /*********/ if (WATCH_MODULE(WATCH_MOD__OTHER)) WatchThis (NULL, FI_LI, WATCH_MOD__OTHER, "WatchProcessReport()"); JpiItems[JPI_PROCESS_RIGHTS_ITEM].buf_len = sizeof(JpiProcessRights); JpiItems[JPI_PROCESS_RIGHTS_ITEM].buf_addr = &JpiProcessRights; ProcessContext = 0; status = sys$process_scan (&ProcessContext, &ScanItems); if (Debug) fprintf (stdout, "sys$process_scan() %%X%08.08X\n", status); if (VMSnok (status)) { rqptr->rqResponse.ErrorTextPtr = "sys$process_scan()"; ErrorVmsStatus (rqptr, status, FI_LI); SysDclAst (NextTaskFunction, rqptr); return; } AdminPageTitle (rqptr, "Process Report", BeginPage); /* detached scripts (possibly executing as a non-server username) */ if (DclScriptDetachProcess) if (VMSnok (SetPrvStatus = sys$setprv (1, &MailboxMask, 0, 0))) ErrorExitVmsStatus (SetPrvStatus, "sys$setprv()", FI_LI); ProcessCount = 0; for (;;) { status = sys$getjpiw (EfnWait, &ProcessContext, 0, &JpiItems, &IOsb, 0, 0); if (VMSok (status)) status = IOsb.Status; if (VMSnok (status)) break; JpiPrcNam[15] = '\0'; for (cptr = JpiPrcNam; *cptr && *cptr != ' '; cptr++); *cptr = '\0'; JpiUserName[12] = '\0'; for (cptr = JpiUserName; *cptr && *cptr != ' '; cptr++); *cptr = '\0'; if (WATCH_MODULE(WATCH_MOD__OTHER)) WatchThis (NULL, FI_LI, WATCH_MOD__OTHER, "!8XL !&Z !&Z !UL", JpiPid, JpiUserName, JpiPrcNam, JpiRightsSize); if (DclScriptDetachProcess && JpiPid != HttpdProcess.Pid) { if (JpiRightsSize > sizeof(JpiProcessRights)) { char Buffer [32]; sprintf (Buffer, "sys$getjpiw() %08.08X", JpiPid); ErrorNoticed (rqptr, SS$_BUFFEROVF, Buffer, FI_LI); } /* look through each of the identifiers in the list */ idx = 0; for (IdentCount = JpiRightsSize / 8; IdentCount && JpiProcessRights[idx] != ProcessRightsIdent[0]; IdentCount--) idx += 2; /* if we didn't find the identifier then continue */ if (!IdentCount) continue; } ProcessCount++; if (ProcessCount % 2) sptr = ""; else sptr = " " ADMIN_REPORT_ALTHI; for (cptr = JpiImagName; *cptr && *cptr != ';'; cptr++); if (*cptr == ';') *cptr-- = '\0'; while (cptr > JpiImagName && *cptr != ']') cptr--; if (*cptr == ']') cptr++; if (JpiState > 0 && JpiState <= 14) StateNamePtr = StateNameArray[JpiState]; else sprintf (StateNamePtr = StateNameArray[0], "%04.04X", JpiState); vecptr = FaoVector; *vecptr++ = ADMIN_REPORT_SHOW_PROCESS; *vecptr++ = JpiPid; *vecptr++ = JpiUserName; *vecptr++ = ProcessCount; *vecptr++ = sptr; *vecptr++ = JpiPid; *vecptr++ = sptr; *vecptr++ = JpiUserName; *vecptr++ = sptr; *vecptr++ = JpiPrcNam; *vecptr++ = sptr; if (*cptr) *vecptr++ = cptr; else *vecptr++ = "[DCL]"; *vecptr++ = sptr; switch (JpiMode) { case JPI$K_BATCH : *vecptr++ = "BAT"; break; case JPI$K_INTERACTIVE : *vecptr++ = "INT"; break; case JPI$K_NETWORK : *vecptr++ = "NET"; break; case JPI$K_OTHER : *vecptr++ = "OTH"; break; default : *vecptr++ = "?"; } *vecptr++ = sptr; *vecptr++ = StateNamePtr; *vecptr++ = sptr; *vecptr++ = JpiPri; *vecptr++ = JpiPrib; status = FaolToNet (rqptr, ProcessFao, &FaoVector); if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); } if (DclScriptDetachProcess) if (VMSnok (SetPrvStatus = sys$setprv (0, &MailboxMask, 0, 0))) ErrorExitVmsStatus (SetPrvStatus, "sys$setprv()", FI_LI); if (status != SS$_NOMOREPROC) { rqptr->rqResponse.ErrorTextPtr = "sys$getjpiw()"; ErrorVmsStatus (rqptr, status, FI_LI); } status = FaolToNet (rqptr, EndPageFao, NULL); if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); rqptr->rqResponse.PreExpired = PRE_EXPIRE_ADMIN; ResponseHeader200 (rqptr, "text/html", &rqptr->NetWriteBufferDsc); SysDclAst (NextTaskFunction, rqptr); } /*****************************************************************************/ /* Using a scripting script process do a SHOW PROCESS /ALL on the specified process. Used from the DclReport() but actually could be used on any process the server has access to, including the server! */ WatchShowProcess ( REQUEST_STRUCT *rqptr, REQUEST_AST NextTaskFunction, char *ProcessIdString, char *ProcessIdUserName ) { static char DclCommand [512]; static unsigned long JpiServerPid; static $DESCRIPTOR (DclCommandDsc, DclCommand); static $DESCRIPTOR (DclCommandFaoDsc, "SHOW PROCESS /ALL /IDENT=!AZ\n\ SV=$SEVERITY\n\ IF SV THEN MO=F$GETJPI(\"!AZ\",\"MODE\")\n\ JT=\"\"\n\ IF SV THEN IF F$GETJPI(\"!AZ\",\"PID\").NES.F$GETJPI(\"!AZ\",\"MASTER_PID\") \ THEN JT=\" (subprocess)\"\n\ IF SV THEN IF JT.EQS.\"\".AND.F$GETJPI(\"!AZ\",\"JOBTYPE\").EQ.0 \ THEN JT=\" (detached)\"\n\ IF SV THEN IM=F$GETJPI(\"!AZ\",\"IMAGNAME\")\n\ IF SV THEN IF IM.EQS.\"\" THEN IM=\"[DCL]\"\n\ LF[0,8]=10\n\ IF SV THEN WRITE SYS$OUTPUT LF+\"Mode: \"+MO+JT+LF+LF+\"Image: \"+IM\n\ \0"); static char BeginPage [] = "

\n\ \n\
\n\ \n\ \n\
";

   int  status;
   unsigned long  *vecptr;
   unsigned long  ProcessId;
   unsigned long  FaoVector [32];
   char  *cptr, *sptr;
   REQUEST_AST EndPageFunction;

   /*********/
   /* begin */
   /*********/

   if (Debug) fprintf (stdout, "WatchShowProcess() %s\n", ProcessIdString);

   if (ProcessIdUserName[0])
   {
      if (strsame (ProcessIdUserName, HttpdScriptAsUserName, -1))
         rqptr->rqPathSet.ScriptAsPtr = HttpdScriptAsUserName;
      else
      if (strsame (ProcessIdUserName, HttpdProcess.UserName, -1))
         rqptr->rqPathSet.ScriptAsPtr = HttpdProcess.UserName;
      else
      {
         if (!DclPersonaServicesAvailable)
         {
            rqptr->rqResponse.HttpStatus = 403;
            ErrorGeneral (rqptr, ErrorWatchPersonaNeeded, FI_LI);
            SysDclAst (NextTaskFunction, rqptr);
            return;
         }
         rqptr->rqPathSet.ScriptAsPtr = cptr =
            VmGetHeap (rqptr, strlen(ProcessIdUserName)+1);
         strcpy (cptr, ProcessIdUserName);
      }
   }

   ProcessId = strtol (ProcessIdString, NULL, 16);
   if (Debug) fprintf (stdout, "ProcessId: %X08.08X\n", ProcessId);

   /* suppress the [delete] button for the main server process!! */
   if (ProcessId == HttpdProcess.Pid)
      EndPageFunction = &WatchShowEnd;
   else
      EndPageFunction = &WatchShowProcessDeleteEnd;

   rqptr->WatchShowNextTaskFunction = NextTaskFunction;

   vecptr = FaoVector;
   *vecptr++ = ProcessIdString;
   *vecptr++ = ProcessIdString;
   *vecptr++ = ProcessIdString;
   *vecptr++ = ProcessIdString;
   *vecptr++ = ProcessIdString;
   *vecptr++ = ProcessIdString;

   status = sys$faol (&DclCommandFaoDsc, 0, &DclCommandDsc, &FaoVector);
   if (VMSnok (status) || status == SS$_BUFFEROVF)
   {
      rqptr->rqResponse.ErrorTextPtr = "sys$faol()";
      ErrorVmsStatus (rqptr, status, FI_LI);
      SysDclAst (NextTaskFunction, rqptr);
      return;
   }
   if (Debug) fprintf (stdout, "|%s|\n", DclCommand);

   rqptr->rqResponse.PreExpired = PRE_EXPIRE_ADMIN;
   ResponseHeader200 (rqptr, "text/html", NULL);
   AdminPageTitle (rqptr, "Show Process", BeginPage);

   rqptr->rqCgi.BufferRecords =
      rqptr->NetWriteEscapeHtml = true;

   DclBegin (rqptr, EndPageFunction, DclCommand,
             NULL, NULL, NULL, NULL, NULL, NULL);
}

/*****************************************************************************/
/*
Called when the scripting script process is complete.  Output the last portion
of the report page and AST to wherever was the buffered end-of-report function.
*/

WatchShowProcessDeleteEnd (REQUEST_STRUCT *rqptr)

{
   static char  EndPageFao [] =
"
\n\
\n\

\n\ \n\ \n\
\n\ \n\ \n"; int status; unsigned long *vecptr; unsigned long FaoVector [8]; char ProcessIdString [32]; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchShowProcessDeleteEnd()\n"); rqptr->NetWriteEscapeHtml = false; if (!rqptr->rqHeader.QueryStringLength || !strsame (rqptr->rqHeader.QueryStringPtr, "pid=", 4)) { WatchShowEnd (rqptr); return; } strzcpy (ProcessIdString, rqptr->rqHeader.QueryStringPtr+4, sizeof(ProcessIdString)); vecptr = FaoVector; *vecptr++ = ADMIN_CONTROL_DELETE_PROCESS; *vecptr++ = ProcessIdString; status = FaolToNet (rqptr, EndPageFao, &FaoVector); if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); SysDclAst (rqptr->WatchShowNextTaskFunction, rqptr); } /*****************************************************************************/ /* Using a scripting script process to display relevant cluster details. */ WatchShowCluster ( REQUEST_STRUCT *rqptr, REQUEST_AST NextTaskFunction ) { static $DESCRIPTOR (DclFaoDsc, "HAR=F$SEARCH(\"CGI-BIN:[000000]HTTPD_ADMIN_REPORT_CLUSTER.COM\")\n\ IF HAR.NES.\"\" THEN @\'HAR\'\n\ SAY=\"WRITE SYS$OUTPUT\"\n\ H80=\"\'\'SAY\' F$FAO(\"\"!!/!80*-!!/\"\")\"\n\ V62=F$GETSYI(\"VERSION\").GES.\"V6.2\"\n\ SYS=\"SHOW SYSTEM/FULL/CLUSTER\"\n\ SYS\n\ H80\n\ SAY F$FAO(\"!!/Server Process(es):!!/!!/\")\n\ SYS/OWNER=!AZ\n\ SAY F$FAO(\"!!/(Default) Scripting Process(es):!!/!!/\")\n\ SYS/OWNER=!AZ\n\ H80\n\ SAY \"\"\n\ SHUSER=\"SHOW USER/CLUSTER/INT/NET/BAT/SUB\"\n\ SHUSERF=SHUSER+\"/FULL\"\n\ IF V62 THEN SHUSERF=SHUSERF+\"/NOHEAD\"\n\ SHUSER\n\ SAY \"\"\n\ SHUSERF\n"); static char BeginPage [] = "

\n\
\n\ \n\
";

   int  status;
   char  DclBuffer [1024];
   $DESCRIPTOR (DclBufferDsc, DclBuffer);

   /*********/
   /* begin */
   /*********/

   if (Debug) fprintf (stdout, "WatchShowCluster()\n");

   rqptr->WatchShowNextTaskFunction = NextTaskFunction;

   rqptr->rqResponse.PreExpired = PRE_EXPIRE_ADMIN;
   ResponseHeader200 (rqptr, "text/html", NULL);
   AdminPageTitle (rqptr, "Cluster Report", BeginPage);

   /* filter-null required, V7.3 (at least) SHOW CPU/FULL contains them!! */
   rqptr->rqCgi.BufferRecords = 
      rqptr->rqCgi.FilterStream =
      rqptr->NetWriteEscapeHtml = true;

   sys$fao (&DclFaoDsc, NULL, &DclBufferDsc,
            HttpdProcess.UserName,
            HttpdScriptAsUserName);

   DclBegin (rqptr, &WatchShowEnd, DclBuffer,
             NULL, NULL, NULL, NULL, NULL, NULL);
}

/*****************************************************************************/
/*
Using a scripting script process to display relevant system details.
*/

WatchShowSystem
(
REQUEST_STRUCT *rqptr,
REQUEST_AST NextTaskFunction
)
{
   static $DESCRIPTOR (DclFaoDsc,
"HAR=F$SEARCH(\"CGI-BIN:[000000]HTTPD_ADMIN_REPORT_SYSTEM.COM\")\n\
IF HAR.NES.\"\" THEN @\'HAR\'\n\
SAY=\"WRITE SYS$OUTPUT\"\n\
H80=\"\'\'SAY\' F$FAO(\"\"!!/!!80*-!!/\"\")\"\n\
V62=F$GETSYI(\"VERSION\").GES.\"V6.2\"\n\
SYI=F$FAO(\"!!AS, a !!AS with !!UL CPU and !!ULMB running VMS !!AS\",\
F$GETSYI(\"NODENAME\"),F$GETSYI(\"HW_NAME\"),F$GETSYI(\"AVAILCPU_CNT\"),\
(F$GETSYI(\"MEMSIZE\")*(F$GETSYI(\"PAGE_SIZE\")/512)/2048),\
F$EDIT(F$GETSYI(\"VERSION\"),\"COLLAPSE\"))\n\
HDR=\"\"\n\
IF V62 THEN \
HDR=F$FAO(\"  Pid    Process Name    State  Pri      I/O\
       CPU       Page flts  Pages!!/\")\n\
SAY SYI\n\
SAY F$FAO(\"!!#*-!!/!!/!!AS\",F$LENGTH(SYI),HDR)\n\
SYS=\"SHOW SYSTEM/FULL\"\n\
IF V62 THEN SYS=SYS+\"/NOHEAD\"\n\
SYS\n\
H80\n\
SAY F$FAO(\"!!/Server Process(es):!!/!!/\")\n\
SYS/OWNER=!AZ\n\
SAY F$FAO(\"!!/(Default) Scripting Process(es):!!/!!/\")\n\
SYS/OWNER=!AZ\n\
H80\n\
SAY \"\"\n\
SHUSER=\"SHOW USER/NODE/INT/NET/BAT/SUB\"\n\
SHUSERF=SHUSER+\"/FULL\"\n\
IF V62 THEN SHUSERF=SHUSERF+\"/NOHEAD\"\n\
SHUSER\n\
SAY \"\"\n\
SHUSERF\n\
H80\n\
SAY \"\"\n\
SHOW MEMORY/FULL\n\
H80\n\
SHOW CPU/FULL\n\
H80\n\
SHOW DEVICE D\n\
DEFINE/USER SYS$ERROR NL:\n\
DEFINE/USER SYS$OUTPUT NL:\n\
SHOW ERROR\n\
OK=F$INTEGER(F$EXTRACT(3,7,$STATUS)).EQ.1\n\
IF OK THEN SAY \"\"\n\
IF OK THEN SHOW ERROR\n\
SHNET=\"SHOW NET\"\n\
IF V62 THEN H80\n\
IF V62 THEN SHNET\n\
IF v62 THEN SHNET/FULL\0");

   static char  BeginPage [] =
"

\n\ \n\
\n\ \n\ \n\
";

   int  status;
   char  DclBuffer [2048];
   $DESCRIPTOR (DclBufferDsc, DclBuffer);

   /*********/
   /* begin */
   /*********/

   if (Debug) fprintf (stdout, "WatchShowSystem()\n");

   rqptr->WatchShowNextTaskFunction = NextTaskFunction;

   rqptr->rqResponse.PreExpired = PRE_EXPIRE_ADMIN;
   ResponseHeader200 (rqptr, "text/html", NULL);
   AdminPageTitle (rqptr, "System Report", BeginPage);

   /* filter-null required, V7.3 (at least) SHOW CPU/FULL contains them!! */
   rqptr->rqCgi.BufferRecords = 
      rqptr->rqCgi.FilterStream =
      rqptr->NetWriteEscapeHtml = true;

   sys$fao (&DclFaoDsc, NULL, &DclBufferDsc,
            HttpdProcess.UserName,
            HttpdScriptAsUserName);

   DclBegin (rqptr, &WatchShowEnd, DclBuffer,
             NULL, NULL, NULL, NULL, NULL, NULL);
}

/*****************************************************************************/
/*
Called when the scripting script process is complete.  Output the last portion
of the report page and AST to wherever was the buffered end-of-report function.
*/

WatchShowEnd (REQUEST_STRUCT *rqptr)

{
   static char  EndPageFao [] =
"
\n\
\n\ \n\ \n"; int status; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchShowEnd()\n"); rqptr->NetWriteEscapeHtml = false; status = FaolToNet (rqptr, EndPageFao, NULL); if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); SysDclAst (rqptr->WatchShowNextTaskFunction, rqptr); } /*****************************************************************************/ /* Just delete the process specified by 'ProcessIdString'. */ WatchDeleteProcess ( REQUEST_STRUCT *rqptr, REQUEST_AST NextTaskFunction ) { int status, SetPrvStatus; unsigned long ProcessId; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchDeleteProcess() |%s|\n", rqptr->rqHeader.QueryStringPtr); if (rqptr->rqHeader.QueryStringLength && strsame (rqptr->rqHeader.QueryStringPtr, "pid=", 4)) { ProcessId = strtol (rqptr->rqHeader.QueryStringPtr+4, NULL, 16); if (Debug) fprintf (stdout, "ProcessID: %08.08X\n", ProcessId); } else ProcessId = 0; if (ProcessId) { if (DclScriptDetachProcess) { /* detached scripts, possibly executing as a non-server username */ if (VMSnok (SetPrvStatus = sys$setprv (1, &WorldMask, 0, 0))) ErrorExitVmsStatus (SetPrvStatus, "sys$setprv()", FI_LI); status = sys$delprc (&ProcessId, 0); if (VMSnok (SetPrvStatus = sys$setprv (0, &WorldMask, 0, 0))) ErrorExitVmsStatus (SetPrvStatus, "sys$setprv()", FI_LI); } else status = sys$delprc (&ProcessId, 0); if (Debug) fprintf (stdout, "sys$dlprc %%X%08.08X\n", status); } else status = SS$_BUGCHECK; if (VMSnok (status)) { rqptr->rqResponse.HttpStatus = 409; rqptr->rqResponse.ErrorTextPtr = "when deleting"; ErrorVmsStatus (rqptr, status, FI_LI); SysDclAst (NextTaskFunction, rqptr); return; } rqptr->rqResponse.PreExpired = PRE_EXPIRE_ADMIN; ReportSuccess (rqptr, "Server !AZ deleted process !8XL.", ServerHostPort, ProcessId); SysDclAst (NextTaskFunction, rqptr); } /*****************************************************************************/ /* This function provides a WATCH request dump (via WatchPeek()) for use as a diagnostic aid, writing this information to SYS$OUTPUT (i.e. the server process log). It is called from ErrorNoticed(). This facility is enabled by defining a system-table logical name WASD_WATCH_NOTICED. */ WatchNoticed (REQUEST_STRUCT *rqptr) { static $DESCRIPTOR (LnmSystemDsc, "LNM$SYSTEM"); static $DESCRIPTOR (WatchNoticedDsc, "WASD_WATCH_NOTICED"); int status; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchNoticed()\n"); status = sys$trnlnm (0, &LnmSystemDsc, &WatchNoticedDsc, 0, 0); if (status == SS$_NOLOGNAM) return; FaoToStdout ("%HTTPD-W-WATCH, noticed!AZ\n", rqptr ? "" : " (request pointer NULL)"); if (!rqptr) return; WatchPeek (NULL, rqptr); FaoToStdout ("%HTTPD-W-WATCH, end\n"); } /*****************************************************************************/ /* Called from WatchBegin() or WatchNoticed(). Provide a plain-text dump displaying some of the essential fields from various data structures in an executing request. Intended as a diagnosis and development tool. If 'rqptr' is NULL then the information is written to SYS$OUTPUT (and in this case leaks a little memory). */ WatchPeek ( REQUEST_STRUCT *rqptr, REQUEST_STRUCT *rqeptr ) { #define WATCH_NULL_STRING "(null)" #define WATCH_NULL(string) (!string ? WATCH_NULL_STRING : string) static char ServiceFao [] = "\n\ !33 !UL\n\ !33 !&X\n\ !33<->ServerChannel!> !UL (!AZ)\n\ !33<->ServerHostPort!> !&Z\n\ !33<->ServerIpAddressString!> !&Z\n\ !33<->RequestSchemeNamePtr!> !&Z\n\ !33<->ProxyTunnel!> !UL\n\ !33<->SSLserverPtr!> !&X\n\ !33<->SSLclientPtr!> !&X\n\ \n\ !33<->NotePadPtr!> !&Z\n\ !33<->ProxyReverseLocationPtr!> !&Z\n\ \n\ !33 !UL (!AZ)\n\ !33 !&Z\n\ !33 !&I\n\ !33 !UL\n\ !33 !&I\n\ !33 !&A\n\ !33 !&X\n\ !33 !UL\n\ !33 !&S !UL\n\ !33 !UL\n\ !33 !&S\n\ !33 !&A\n\ !33 !&X\n\ !33 !UL\n\ !33 !&S !UL\n\ !33 !UL\n\ !33 !&S\n\ !33 !UL\n\ !33 !&A\n\ !33 !&X\n\ !33 !UL\n\ !33 !UL\n\ !33 !UL\n\ !33 !&X\n"; static char TimerFao [] = "!33 !@SQ\n\ !33 !@SQ\n\ !33 !@SQ\n\ !33 !@SQ\n\ !33 !&B\n\ !33 !&B\n\ !33 !&B\n\ !33 !UL\n\ !33 !UL\n\ !33 !UL!&@\n\ !33 !UL\n\ !33 !UL\n\ !33 !UL\n\ !33 !UL\n\ !33 !UL\n\ !33 !UL\n\ !33 !&B\n\ !33 !UL/!UL!AZ\n\ !33 !UL\n\ !33 !UL\n\ !33 !UL\n\ !33 !UL!&@\n\ !33 !&B\n\ \n\ !33 !%D (!AZ ago)\n\ !33 !&Z\n"; static char HeaderFao [] = "!33 |!#AZ|\n\ !33 !&Z\n\ !33 {!UL}!&P\n\ !33 !UL.!UL\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z no-cache:!&B no-store:!&B max-age=0:!&B\n\ !33 !&Z\n\ !33 !&Z (!UL)\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z (!&W)\n\ !33 !&Z (!&W)\n\ !33 !&Z (!&W)\n\ !33 !&Z\n\ !33 !&Z !UL\n\ !33 !&Z\n\ !33 !&Z no-cache:!&B\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z websocket:!&B\n\ !33 !&Z\n\ !33 !UL\n"; static char BodyFao [] = "!33 !&B\n\ !33 !UL\n\ !33 !UL\n\ !33 !UL\n\ !33 !&Z\n\ !33 !UL\n\ !33 !UL\n\ !33 !&X\n\ !33 !UL\n\ !33 !UL\n\ !33 !UL\n\ !33 !UL\n\ !33 0x!XL\n\ !33 !UL\n\ !33 !UL\n\ !33 !&S\n\ !33 !UL\n\ !33 !&A\n\ !33 !&A\n\ !33 !&X\n\ \n"; static char PathInfoFao [] = "!33 !&Z\n\ !33 !&Z\n\ !33 |!16&H|\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&B\n\ !33 !UL !AZ\n\ !33 !UL !AZ\n\ !33 !&B\n\ \n\ !33 |!#AZ|\n\ !33 !&B\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&B\n\ !33 !&B\n\ !33 !&X\n\ !33 !UL\n\ !33 !&B\n\ \n\ !33 !8XL\n\ !33 !UL\n\ !33 !UL (!AZ)\n\ !33 !&S !UL\n\ !33 !UL\n\ !33 !UL\n\ !33 !UL\n\ !33 !UL (!AZ)\n\ !33 !&S !UL\n\ !33 !UL\n\ !33 !UL\n\ \n\ !33 !&Z\n\ !33 |!#**|\n\ !33 !&B\n\ !33 !&S\n\ !33 0x!4XL (!AZ)\n\ !33 0x!4XL (!AZ)\n\ !33 0x!4XL (!AZ)\n\ !33 0x!4XL (!AZ)\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&B\n\ !33 !&B\n\ !33 !&B\n\ !33 !UL\n\ !33 0x!XL\n\ !33 !&B\n\ !33 !UL\n\ !33 0x!XL\n\ !33 !&B\n\ !33 !&Z\n\ !33 !&Z (!AZ)\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z (!AZ)\n\ !33 !&Z (!AZ)\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z\n\ \n\ !33 !UL\n\ !33 !UL\n\ !33 0x!XL\n\ !33 0x!XL\n\ !33 !&B\n\ !33 !UL\n\ !33 0x!XL !&Z\n\ !33 !UL\n\ !33 !&B\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&Z\n\ !33 !&B\n\ !33 !&B\n\ !33 !UL\n\ !33 !&B\n\ !33 !UL (!AZ)\n\ !33 !&B\n\ !33 !UL\n\ !33 !UL\n\ !33 !&B\n\ !33 !UL\n\ !33 !&B\n\ "; static char CacheFao [] = "\n\ !33 0x!XL\n\ !33 0x!XL\n\ "; static char DclTaskFao [] = "!33<->TaskType!> !UL (!AZ)\n\ !33<->ScriptProcessPid!> !8XL\n\ !33<->LifeTimeSecond!> !&@\n\ !33<->CrePrcTermMbxChannel!> !UL (!AZ)\n\ !33<->CrePrcDetachProcess!> !UL\n\ !33<->CrePrcDetachStarting!> !UL\n\ !33<->CrePrcUserName!> !&Z\n\ !33<->CgiPlusVarStruct!> !UL\n\ !33<->CgiPlusInChannel!> !UL (!AZ)\n\ !33<->CgiPlusInIOsb!> !&S !UL\n\ !33<->QueuedCgiPlusIn!> !UL\n\ !33<->HttpInputChannel!> !UL (!AZ)\n\ !33<->HttpInputIOsb!> !&S !UL\n\ !33<->QueuedHttpInput!> !UL\n\ !33<->ClientReadBufferSize!> !UL\n\ !33<->ClientReadStripCrLf!> !UL\n\ !33<->QueuedClientRead!> !UL\n\ !33<->SysCommandChannel!> !UL (!AZ)\n\ !33<->SysCommandIOsb!> !&S !UL\n\ !33<->QueuedSysCommand!> !UL\n\ !33<->QueuedSysCommandAllowed!> !UL\n\ !33<->SysOutputSize!> !UL\n\ !33<->SysOutputChannel!> !UL (!AZ)\n\ !33<->SysOutputIOsb!> !&S !UL\n\ !33<->QueuedSysOutput!> !UL\n\ !33<->BuildRecords!> !&B\n\ !33<->SysOutputBuildCount!> !UL\n\ !33<->ClientWriteErrorCount!> !UL\n\ !33<->ScriptProcessPid!> !8XL\n\ !33<->CrePrcTermRecord.acc$l_finalsts!> !&S\n\ !33<->ScriptProcessActivated!> !&B\n\ !33<->ScriptProcessResponded!> !&B\n\ !33<->TaskRunDown!> !&B\n\ !33<->DeleteProcess!> !&B\n\ !33<->ForceImageExit!> !&B\n\ !33<->ForceImageExitGetJpi!> !&B\n\ !33<->ForceImageExitIssued!> !&B\n\ !33<->ForceImageExitSecond!> !UL\n\ !33<->JpiImagNameIOsb.Status!> !&S\n\ !33<->JpiImagName!> |!#AZ|\n\ !33<->ScriptCpuMax!> !UL\n\ !33<->ScriptCpuTimGetJpi!> !UL\n\ !33<->JpiCpuTimIOsb.Status!> !&S\n\ !33<->JpiCpuTim!> !UL\n\ !33<->ScriptCpuTimMax!> !UL\n\ !33<->CalloutFunction!> !&A\n\ !33<->DclCommandPtr!> !&Z\n\ !33<->DclCommandSize!> !UL\n\ !33<->DclCommandLength!> !UL\n\ !33<->ScriptName!> !&Z\n\ !33<->ScriptFileName!> !&Z\n\ \n"; static char DECnetFao [] = "!33 !&X\n"; static char DECnetTaskFao [] = "!33<->DECnetChannel!> !UL\n\ !33<->DECnetConnectIOsb!> !&S !UL\n\ !33<->DECnetReadIOsb!> !&S !UL\n\ !33<->DECnetWriteIOsb!> !&S !UL\n\ !33<->QueuedDECnetIO!> !UL\n\ !33<->ScriptResponded!> !&B\n\ !33<->BuildRecords!> !&B\n\ !33<->BuildCount!> !UL\n\ !33<->CgiDialogState!> !UL\n\ !33<->OsuDialogState!> !UL\n\ !33<->OsuDnetCgi!> !&B\n\ \n"; static char DescrFao [] = "!33 !&X\n\ !33 !&X\n\ !33 !&X\n\ !33 !&X\n\ !33 !&X\n\ !33 !&X\n\ !33 !&X\n\ !33 !&X\n\ "; static char ProxyTaskFao [] = "!33<->ProxyChannel!> !UL (!AZ)\n\ !33<->ConnectIpAddress!> !&I\n\ !33<->RequestHostIpAddress!> !&I\n\ !33<->RequestHostPort!> !&Z\n\ !33<->RequestSchemeName!> !&Z\n\ !33<->ProxyTunnel!> !UL\n\ !33<->ProxyLookupRetryCount!> !UL\n\ !33<->ProxyConnectIOsb!> !&S !UL\n\ !33<->ProxyReadIOsb!> !&S !UL\n\ !33<->ProxyReadRawAstFunction!> !&A\n\ !33<->ProxyReadRawDataPtr!> !&X\n\ !33<->ProxyReadRawDataSize!> !UL\n\ !33<->ProxyWriteIOsb!> !&S !UL\n\ !33<->ProxyWriteRawAstFunction!> !&A\n\ !33<->ProxyWriteRawDataPtr!> !&X\n\ !33<->ProxyWriteRawDataCount!> !UL\n\ !33<->BytesRawRx!> !@SQ\n\ !33<->BytesRawTx!> !@SQ\n\ !33<->VerifyRecordPtr!> !&Z\n\ !33<->RebuiltRequestLength!> !UL\n\ !33<->RebuiltRequestPtr!> !&Z\n\ !33<->ResponseBodyLength!> !UL\n\ !33<->ResponseBufferNetCount!> !UL\n\ !33<->ResponseBufferNetPtr!> !&X\n\ !33<->ResponseCacheControlMaxAge!> !UL\n\ !33<->ResponseCacheControlMaxAgeZero!> !&B\n\ !33<->ResponseCacheControlMustReval!> !&B\n\ !33<->ResponseCacheControlNoCache!> !&B\n\ !33<->ResponseCacheControlNoStore!> !&B\n\ !33<->ResponseCacheControlNoTransform!> !&B\n\ !33<->ResponseCacheControlPrivate!> !&B\n\ !33<->ResponseCacheControlProxyReval!> !&B\n\ !33<->ResponseCacheControlPublic!> !&B\n\ !33<->ResponseCacheControlSMaxAge!> !UL\n\ !33<->ResponseChunkedCount!> !UL\n\ !33<->ResponseChunkedEnd!> !&B\n\ !33<->ResponseChunkedEol!> !&B\n\ !33<->ResponseChunkedEot!> !&B\n\ !33<->ResponseChunkedInit!> !&B\n\ !33<->ResponseChunkedSize!> !UL\n\ !33<->ResponseChunkedString!> !&Z\n\ !33<->ResponseChunkedNewlineCount!> !UL\n\ !33<->ResponseConsecutiveNewLineCount!> !UL\n\ !33<->ResponseContentEncodingGzip!> !&B\n\ !33<->ResponseContentEncodingUnknown!> !&B\n\ !33<->ResponseContentLength!> !SL\n\ !33<->ResponseExpires!> !&Z (!%D)\n\ !33<->ResponseHeaderLength!> !UL\n\ !33<->ResponseHeaderPtr!> |!#AZ|\n\ !33<->ResponseHeaderSent!> !&B\n\ !33<->ResponseLastModified!> !&Z (!%D)\n\ !33<->ResponseTransferEncodingChunked!> !&B\n\ !33<->ResponseUpgradeWebSocket!> !&B\n\ !33<->RebuiltResponseLength!> !UL\n\ !33<->RebuiltResponsePtr!> !&Z\n\ !33<->CannotCache!> !&B\n\ !33<->ProxyCacheFileName!> !&Z\n\ !33<->ProxyCacheSuitable!> !&B\n\ !33<->ProxyCacheFileSizeInBytes!> !UL\n\ !33<->ProxyCacheLastModifiedHours!> !UL\n\ !33<->ProxyCacheReadBytes!> !UL\n\ !33<->ProxyCacheFileCdt!> !%D\n\ "; static char PutFao [] = "!33 !&X\n\ !33 !&X\n\ !33 !&X\n\ \n"; int status, ConnectNumber; unsigned short Length; unsigned long Remainder, Seconds, SubSeconds, WatchModule; unsigned long BinaryTime [2], FaoVector [128], ResponseDuration [2], ResultTime [2]; unsigned long *vecptr; char *cptr; char Buffer [8192], ClientDevName [64], ProxyDevName [64], ServerDevName [64]; MAP_RULE_META *mrptr; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchPeek()\n"); WatchModule = Watch.Module; Watch.Module = 0; NetGetBgDevice (rqeptr->ServicePtr->ServerChannel, ServerDevName, sizeof(ServerDevName)); NetGetBgDevice (rqeptr->rqClient.Channel, ClientDevName, sizeof(ClientDevName)); sys$gettim (&BinaryTime); status = lib$sub_times (&BinaryTime, &rqeptr->rqTime.Vms64bit, &ResponseDuration); if (VMSnok (status)) PUT_ZERO_QUAD (ResponseDuration); vecptr = FaoVector; *vecptr++ = HttpdTickSecond; *vecptr++ = rqeptr->ServicePtr; *vecptr++ = rqeptr->ServicePtr->ServerChannel; *vecptr++ = ServerDevName+1; *vecptr++ = rqeptr->ServicePtr->ServerHostPort; *vecptr++ = rqeptr->ServicePtr->ServerIpAddressString; *vecptr++ = rqeptr->ServicePtr->RequestSchemeNamePtr; *vecptr++ = rqeptr->ServicePtr->ProxyTunnel; *vecptr++ = rqeptr->ServicePtr->SSLserverPtr; *vecptr++ = rqeptr->ServicePtr->SSLclientPtr; *vecptr++ = rqeptr->NotePadPtr; *vecptr++ = rqeptr->ProxyReverseLocationPtr; *vecptr++ = rqeptr->rqClient.Channel; *vecptr++ = ClientDevName+1; *vecptr++ = rqeptr->rqClient.Lookup.HostName; *vecptr++ = &rqeptr->rqClient.IpAddress; *vecptr++ = rqeptr->rqClient.IpPort; *vecptr++ = &rqeptr->rqClient.MultiHomeIpAddress; *vecptr++ = rqeptr->rqNet.ReadRawAstFunction; *vecptr++ = rqeptr->rqNet.ReadRawDataPtr; *vecptr++ = rqeptr->rqNet.ReadRawDataSize; *vecptr++ = rqeptr->rqNet.ReadIOsb.Status; *vecptr++ = rqeptr->rqNet.ReadIOsb.Count; *vecptr++ = rqeptr->rqNet.ReadErrorCount; *vecptr++ = rqeptr->rqNet.ReadErrorStatus; *vecptr++ = rqeptr->rqNet.WriteRawAstFunction; *vecptr++ = rqeptr->rqNet.WriteRawDataPtr; *vecptr++ = rqeptr->rqNet.WriteRawDataLength; *vecptr++ = rqeptr->rqNet.WriteIOsb.Status; *vecptr++ = rqeptr->rqNet.WriteIOsb.Count; *vecptr++ = rqeptr->rqNet.WriteErrorCount; *vecptr++ = rqeptr->rqNet.WriteErrorStatus; *vecptr++ = rqeptr->rqNet.GzipDataLength; *vecptr++ = rqeptr->rqNet.GzipAstFunction; *vecptr++ = rqeptr->rqNet.PipelineBufferPtr; *vecptr++ = rqeptr->rqNet.PipelineBufferCount; *vecptr++ = rqeptr->rqNet.PipelineRequestCount; *vecptr++ = rqeptr->rqNet.ConnectionCount; *vecptr++ = rqeptr->rqNet.SesolaPtr; status = FaolToBuffer (Buffer, sizeof(Buffer), &Length, ServiceFao, &FaoVector); if (VMSnok (status) || status == SS$_BUFFEROVF) ErrorNoticed (rqptr, status, NULL, FI_LI); if (rqptr) NetWrite (rqptr, 0, Buffer, Length); else fputs (Buffer, stdout); SesolaWatchPeek (rqptr, rqeptr); vecptr = FaoVector; *vecptr++ = &rqeptr->BytesRx; *vecptr++ = &rqeptr->BytesTx; *vecptr++ = &rqeptr->BytesRawRx; *vecptr++ = &rqeptr->BytesRawTx; *vecptr++ = rqeptr->PersistentRequest; *vecptr++ = rqeptr->PersistentResponse; *vecptr++ = rqeptr->NotFromCache; *vecptr++ = rqeptr->rqTmr.InputSecond; *vecptr++ = rqeptr->rqTmr.PersistentSecond; *vecptr++ = rqeptr->rqTmr.ListIndex; if (rqeptr->rqTmr.ListIndex) { *vecptr++ = " (!UL seconds)"; *vecptr++ = SupervisorListArray[rqeptr->rqTmr.ListIndex].ChunkSeconds; } else *vecptr++ = ""; *vecptr++ = rqeptr->rqTmr.NoProgressBytesTx; *vecptr++ = rqeptr->rqTmr.NoProgressSecond; *vecptr++ = rqeptr->rqTmr.NoProgressPeriod; *vecptr++ = rqeptr->rqTmr.OutputSecond; *vecptr++ = rqeptr->rqTmr.TerminatedCount; *vecptr++ = rqeptr->rqTmr.ThrottleSecond; *vecptr++ = rqeptr->rqPathSet.ThrottleSet; *vecptr++ = rqeptr->rqPathSet.ThrottleFrom; *vecptr++ = rqeptr->rqPathSet.ThrottlePerUser; if (rqeptr->rqPathSet.ThrottleFrom) { if (!rqeptr->ThrottleListEntry.DataPtr) *vecptr++ = " (QUEUED)"; else *vecptr++ = " (PROCESSING)"; } else *vecptr++ = ""; *vecptr++ = rqeptr->rqPathSet.ThrottleTo; *vecptr++ = rqeptr->rqPathSet.ThrottleResume; *vecptr++ = rqeptr->rqPathSet.ThrottleBusy; *vecptr++ = rqeptr->rqPathSet.ThrottleIndex; /* if throttled get the path rule using the index number */ if (rqeptr->rqPathSet.ThrottleIndex) mrptr = MapUrl_ThrottleRule (rqeptr->rqPathSet.ThrottleIndex); else mrptr = NULL; if (mrptr) { *vecptr++ = " (!AZ throttle=!UL,!UL,!UL,!UL,!AZ,!AZ)"; *vecptr++ = mrptr->TemplatePtr; *vecptr++ = mrptr->mpPathSet.ThrottleFrom; *vecptr++ = mrptr->mpPathSet.ThrottleTo; *vecptr++ = mrptr->mpPathSet.ThrottleResume; *vecptr++ = mrptr->mpPathSet.ThrottleBusy; *vecptr++ = MetaConShowSeconds (rqptr, mrptr->mpPathSet.ThrottleTimeoutQueue); *vecptr++ = MetaConShowSeconds (rqptr, mrptr->mpPathSet.ThrottleTimeoutBusy); } else *vecptr++ = ""; *vecptr++ = rqeptr->ThrottlePerUser; *vecptr++ = rqeptr->rqTime.Vms64bit; *vecptr++ = DurationString (rqptr, &ResponseDuration); *vecptr++ = rqeptr->rqTime.GmDateTime; FaoVectorCheck (sizeof(FaoVector), &FaoVector, vecptr, FI_LI); status = FaolToBuffer (Buffer, sizeof(Buffer), &Length, TimerFao, &FaoVector); if (VMSnok (status) || status == SS$_BUFFEROVF) ErrorNoticed (rqptr, status, NULL, FI_LI); if (rqptr) NetWrite (rqptr, 0, Buffer, Length); else fputs (Buffer, stdout); vecptr = FaoVector; if (rqeptr->rqHeader.RequestHeaderPtrInvalid) *vecptr++ = sizeof("(invalid)")-1; else if (rqeptr->rqHeader.RequestHeaderPtr) *vecptr++ = rqeptr->rqHeader.RequestHeaderLength; else *vecptr++ = sizeof(WATCH_NULL_STRING)-1; if (rqeptr->rqHeader.RequestHeaderPtrInvalid) *vecptr++ = "(invalid)"; else *vecptr++ = WATCH_NULL(rqeptr->rqHeader.RequestHeaderPtr); *vecptr++ = rqeptr->rqHeader.MethodName; if (rqeptr->rqHeader.RequestUriPtr) *vecptr++ = strlen(rqeptr->rqHeader.RequestUriPtr); else *vecptr++ = 0; *vecptr++ = rqeptr->rqHeader.RequestUriPtr; *vecptr++ = rqeptr->rqHeader.HttpVersion / 10; *vecptr++ = rqeptr->rqHeader.HttpVersion % 10; *vecptr++ = rqeptr->rqHeader.AcceptPtr; *vecptr++ = rqeptr->rqHeader.AcceptCharsetPtr; *vecptr++ = rqeptr->rqHeader.AcceptEncodingPtr; *vecptr++ = rqeptr->rqHeader.AcceptLangPtr; *vecptr++ = rqeptr->rqHeader.AuthorizationPtr; *vecptr++ = rqeptr->rqHeader.CacheControlPtr; *vecptr++ = rqeptr->rqHeader.CacheControlNoCache; *vecptr++ = rqeptr->rqHeader.CacheControlNoStore; *vecptr++ = rqeptr->rqHeader.CacheControlMaxAgeZero; *vecptr++ = rqeptr->rqHeader.ConnectionPtr; *vecptr++ = rqeptr->rqHeader.ContentLengthPtr; *vecptr++ = rqeptr->rqHeader.ContentLength; *vecptr++ = rqeptr->rqHeader.ContentTypePtr; *vecptr++ = rqeptr->rqHeader.CookiePtr; *vecptr++ = rqeptr->rqHeader.ETagPtr; *vecptr++ = rqeptr->rqHeader.ExpectPtr; *vecptr++ = rqeptr->rqHeader.ForwardedPtr; *vecptr++ = rqeptr->rqHeader.HostPtr; *vecptr++ = rqeptr->rqHeader.IfMatchPtr; *vecptr++ = rqeptr->rqHeader.IfNoneMatchPtr; *vecptr++ = rqeptr->rqHeader.IfModifiedSincePtr; *vecptr++ = rqeptr->rqTime.IfModifiedSinceVMS64bit; *vecptr++ = rqeptr->rqHeader.IfRangePtr; *vecptr++ = rqeptr->rqTime.IfRangeVMS64bit; *vecptr++ = rqeptr->rqHeader.IfUnModifiedSincePtr; *vecptr++ = rqeptr->rqTime.IfUnModifiedSinceVMS64bit; *vecptr++ = rqeptr->rqHeader.KeepAlivePtr; *vecptr++ = rqeptr->rqHeader.MaxForwardsPtr; *vecptr++ = rqeptr->rqHeader.MaxForwards; *vecptr++ = rqeptr->rqHeader.OriginPtr; *vecptr++ = rqeptr->rqHeader.PragmaPtr; *vecptr++ = rqeptr->rqHeader.PragmaNoCache; *vecptr++ = rqeptr->rqHeader.ProxyAuthorizationPtr; *vecptr++ = rqeptr->rqHeader.ProxyConnectionPtr; *vecptr++ = rqeptr->rqHeader.RangePtr; *vecptr++ = rqeptr->rqHeader.RefererPtr; *vecptr++ = rqeptr->rqHeader.SecWebSocketKeyPtr; *vecptr++ = rqeptr->rqHeader.SecWebSocketProtocolPtr; *vecptr++ = rqeptr->rqHeader.SecWebSocketVersionPtr; *vecptr++ = rqeptr->rqHeader.UpgradePtr; *vecptr++ = rqeptr->rqHeader.UpgradeWebSocket; *vecptr++ = rqeptr->rqHeader.UserAgentPtr; *vecptr++ = rqeptr->rqHeader.XForwardedForPtr; *vecptr++ = rqeptr->rqHeader.UnknownFieldsCount; FaoVectorCheck (sizeof(FaoVector), &FaoVector, vecptr, FI_LI); status = FaolToBuffer (Buffer, sizeof(Buffer), &Length, HeaderFao, &FaoVector); if (VMSnok (status) || status == SS$_BUFFEROVF) ErrorNoticed (rqptr, status, NULL, FI_LI); if (rqptr) NetWrite (rqptr, 0, Buffer, Length); else fputs (Buffer, stdout); vecptr = FaoVector; *vecptr++ = rqeptr->rqBody.UnEncodeStream; *vecptr++ = rqeptr->rqBody.ChunkState; *vecptr++ = rqeptr->rqBody.ChunkCount; *vecptr++ = rqeptr->rqBody.ChunkSize; *vecptr++ = rqeptr->rqBody.ChunkSizeString; *vecptr++ = rqeptr->rqBody.ChunkedTrailerBufferCount; *vecptr++ = rqeptr->rqBody.ChunkedTrailerBufferSize; *vecptr++ = rqeptr->rqBody.ChunkedTrailerBufferPtr; *vecptr++ = rqeptr->rqBody.ChunkedTrailerNewLineCount; *vecptr++ = rqeptr->rqBody.ContentLength; *vecptr++ = rqeptr->rqBody.ContentCount; *vecptr++ = rqeptr->rqBody.DataVBN; *vecptr++ = rqeptr->rqBody.DataPtr; *vecptr++ = rqeptr->rqBody.DataCount; *vecptr++ = rqeptr->rqBody.DataSize; *vecptr++ = rqeptr->rqBody.DataStatus; *vecptr++ = rqeptr->rqBody.DiscardReadCount; *vecptr++ = rqeptr->rqBody.AstFunction; *vecptr++ = rqeptr->rqBody.ProcessFunction; *vecptr++ = rqeptr->rqBody.ProcessPtr; FaoVectorCheck (sizeof(FaoVector), &FaoVector, vecptr, FI_LI); status = FaolToBuffer (Buffer, sizeof(Buffer), &Length, BodyFao, &FaoVector); if (VMSnok (status) || status == SS$_BUFFEROVF) ErrorNoticed (rqptr, status, NULL, FI_LI); if (rqptr) NetWrite (rqptr, 0, Buffer, Length); else fputs (Buffer, stdout); vecptr = FaoVector; *vecptr++ = rqeptr->rqHeader.PathInfoPtr; *vecptr++ = rqeptr->rqHeader.QueryStringPtr; *vecptr++ = &rqeptr->Md5HashPath; *vecptr++ = rqeptr->MappedPathPtr; *vecptr++ = rqeptr->RequestMappedFile; *vecptr++ = rqeptr->ParseOds.ExpFileName; *vecptr++ = rqeptr->ScriptName; *vecptr++ = rqeptr->RequestMappedScript; *vecptr++ = rqeptr->RequestMappedRunTime; *vecptr++ = rqeptr->IsCgiPlusScript; *vecptr++ = rqeptr->rqPathSet.PathOds; switch (rqeptr->rqPathSet.PathOds) { case MAPURL_PATH_ODS_2 : *vecptr++ = "ODS-2"; break; case MAPURL_PATH_ODS_5 : *vecptr++ = "ODS-5"; break; case MAPURL_PATH_ODS_ADS : *vecptr++ = "ADS"; break; case MAPURL_PATH_ODS_PWK : *vecptr++ = "PWK"; break; case MAPURL_PATH_ODS_SMB : *vecptr++ = "SMB"; break; case MAPURL_PATH_ODS_SRI : *vecptr++ = "SRI"; break; default : *vecptr++ = "ods-2"; } *vecptr++ = rqeptr->PathOds; switch (rqeptr->PathOds) { case MAPURL_PATH_ODS_2 : *vecptr++ = "ODS-2"; break; case MAPURL_PATH_ODS_5 : *vecptr++ = "ODS-5"; break; case MAPURL_PATH_ODS_ADS : *vecptr++ = "ADS"; break; case MAPURL_PATH_ODS_PWK : *vecptr++ = "PWK"; break; case MAPURL_PATH_ODS_SMB : *vecptr++ = "SMB"; break; case MAPURL_PATH_ODS_SRI : *vecptr++ = "SRI"; break; default : *vecptr++ = "ods-2"; } *vecptr++ = rqeptr->PathOdsExtended; if (!rqeptr->rqResponse.HeaderPtr) *vecptr++ = sizeof(WATCH_NULL_STRING)-1; else *vecptr++ = rqeptr->rqResponse.HeaderLength; *vecptr++ = WATCH_NULL(rqeptr->rqResponse.HeaderPtr); *vecptr++ = rqeptr->rqResponse.HeaderSent; *vecptr++ = rqeptr->rqResponse.ErrorReportPtr; *vecptr++ = rqeptr->rqResponse.LocationPtr; *vecptr++ = rqeptr->rqResponse.ContentEncodeAsGzip; *vecptr++ = rqeptr->rqResponse.ContentIsEncodedGzip; *vecptr++ = rqeptr->rqResponse.ChunkedBufferPtr; *vecptr++ = rqeptr->rqResponse.ChunkedBufferSize; *vecptr++ = rqeptr->rqResponse.TransferEncodingChunked; *vecptr++ = rqeptr->rqWebSocket.ScriptProcessPid; *vecptr++ = rqeptr->rqWebSocket.InputSize; *vecptr++ = rqeptr->rqWebSocket.InputChannel; *vecptr++ = rqeptr->rqWebSocket.InputDevName; *vecptr++ = rqeptr->rqWebSocket.InputIOsb.Status; *vecptr++ = rqeptr->rqWebSocket.InputIOsb.Count; *vecptr++ = rqeptr->rqWebSocket.QueuedInput; *vecptr++ = rqeptr->rqWebSocket.QueuedNetRead; *vecptr++ = rqeptr->rqWebSocket.OutputSize; *vecptr++ = rqeptr->rqWebSocket.OutputChannel; *vecptr++ = rqeptr->rqWebSocket.OutputDevName; *vecptr++ = rqeptr->rqWebSocket.OutputIOsb.Status; *vecptr++ = rqeptr->rqWebSocket.OutputIOsb.Count; *vecptr++ = rqeptr->rqWebSocket.QueuedOutput; *vecptr++ = rqeptr->rqWebSocket.QueuedNetWrite; *vecptr++ = rqeptr->RemoteUser; *vecptr++ = strlen(rqeptr->RemoteUserPassword); *vecptr++ = rqeptr->rqAuth.ResolvedRemoteUser; *vecptr++ = rqeptr->rqAuth.FinalStatus; *vecptr++ = rqeptr->rqAuth.RequestCan; *vecptr++ = AuthCanString (rqeptr->rqAuth.RequestCan, AUTH_CAN_FORMAT_LONG); *vecptr++ = rqeptr->rqAuth.UserCan; *vecptr++ = AuthCanString (rqeptr->rqAuth.UserCan, AUTH_CAN_FORMAT_LONG); *vecptr++ = rqeptr->rqAuth.GroupCan; *vecptr++ = AuthCanString (rqeptr->rqAuth.GroupCan, AUTH_CAN_FORMAT_LONG); *vecptr++ = rqeptr->rqAuth.WorldCan; *vecptr++ = AuthCanString (rqeptr->rqAuth.WorldCan, AUTH_CAN_FORMAT_LONG); *vecptr++ = rqeptr->rqAuth.Type; *vecptr++ = rqeptr->rqAuth.UserDetailsPtr; *vecptr++ = rqeptr->rqAuth.HttpsOnly; *vecptr++ = rqeptr->rqAuth.SkelKeyAuthenticated; *vecptr++ = rqeptr->rqAuth.SysUafAuthenticated; *vecptr++ = rqeptr->rqAuth.VmsIdentifiersCount; *vecptr++ = rqeptr->rqAuth.VmsIdentifiersPtr; *vecptr++ = rqeptr->rqAuth.VmsUserProfile; *vecptr++ = rqeptr->rqAuth.VmsUserProfileLength; *vecptr++ = rqeptr->rqAuth.VmsUserProfilePtr; *vecptr++ = rqeptr->rqAuth.VmsUserScriptAs; *vecptr++ = rqeptr->rqAuth.DirectoryPtr; *vecptr++ = rqeptr->rqAuth.RealmPtr; *vecptr++ = AuthSourceString (rqeptr->rqAuth.RealmPtr, rqeptr->rqAuth.SourceRealm); *vecptr++ = rqeptr->rqAuth.RealmDescrPtr; *vecptr++ = rqeptr->rqAuth.PathParameterPtr; *vecptr++ = rqeptr->rqAuth.GroupWritePtr; *vecptr++ = AuthSourceString (rqeptr->rqAuth.GroupWritePtr, rqeptr->rqAuth.SourceGroupWrite); *vecptr++ = rqeptr->rqAuth.GroupReadPtr; *vecptr++ = AuthSourceString (rqeptr->rqAuth.GroupReadPtr, rqeptr->rqAuth.SourceGroupRead); *vecptr++ = rqeptr->rqAuth.GroupRestrictListPtr; *vecptr++ = rqeptr->rqAuth.WorldRestrictListPtr; *vecptr++ = rqeptr->rqAuth.ProxyStringPtr; *vecptr++ = rqeptr->rqAuth.RemoteUser; *vecptr++ = rqeptr->rqCgi.BufferLength; *vecptr++ = rqeptr->rqCgi.BufferRemaining; *vecptr++ = rqeptr->rqCgi.BufferPtr; *vecptr++ = rqeptr->rqCgi.BufferCurrentPtr; *vecptr++ = rqeptr->rqCgi.CalloutInProgress; *vecptr++ = rqeptr->rqCgi.CalloutOutputCount; *vecptr++ = rqeptr->rqCgi.CalloutOutputPtr; *vecptr++ = rqeptr->rqCgi.CalloutOutputPtr; *vecptr++ = rqeptr->rqCgi.ContentEncodingGzip; *vecptr++ = rqeptr->rqCgi.ContentTypeText; *vecptr++ = rqeptr->rqCgi.EofStr; *vecptr++ = rqeptr->rqCgi.EotStr; *vecptr++ = rqeptr->rqCgi.EscStr; *vecptr++ = rqeptr->rqCgi.Header100Continue; *vecptr++ = rqeptr->rqCgi.Header100ContinueDone; *vecptr++ = rqeptr->rqCgi.HeaderLineCount; *vecptr++ = rqeptr->rqCgi.IsCliDcl; *vecptr++ = rqeptr->rqCgi.OutputMode; switch (rqeptr->rqCgi.OutputMode) { case CGI_OUTPUT_MODE_STREAM : *vecptr++ = "STREAM"; break; case CGI_OUTPUT_MODE_RECORD : *vecptr++ = "RECORD"; break; case CGI_OUTPUT_MODE_CRLF : *vecptr++ = "CRLF"; break; default : *vecptr++ = "?"; } *vecptr++ = rqeptr->rqCgi.ProcessingBody; *vecptr++ = rqeptr->rqCgi.RecordCount; *vecptr++ = rqeptr->rqCgi.ScriptRetryCount; *vecptr++ = rqeptr->rqCgi.TransferEncoding; *vecptr++ = rqeptr->rqCgi.TransferEncodingChunked; *vecptr++ = rqeptr->rqCgi.XVMSRecordMode; FaoVectorCheck (sizeof(FaoVector), &FaoVector, vecptr, FI_LI); status = FaolToBuffer (Buffer, sizeof(Buffer), &Length, PathInfoFao, &FaoVector); if (VMSnok (status) || status == SS$_BUFFEROVF) ErrorNoticed (rqptr, status, NULL, FI_LI); if (rqptr) NetWrite (rqptr, 0, Buffer, Length); else fputs (Buffer, stdout); if ((cptr = rqeptr->rqCgi.BufferPtr)) { /*****************/ /* CGI variables */ /*****************/ for (;;) { if (!(Length = *(USHORTPTR)cptr)) break; status = FaoToBuffer (Buffer, sizeof(Buffer), &Length, "!&Z\n", cptr + sizeof(short)); if (VMSnok (status) || status == SS$_BUFFEROVF) ErrorNoticed (rqptr, status, NULL, FI_LI); if (rqptr) NetWrite (rqptr, 0, Buffer, Length); else fputs (Buffer, stdout); cptr += *(USHORTPTR)cptr + sizeof(short); } } vecptr = FaoVector; *vecptr++ = rqeptr->rqCache.EntryPtr; *vecptr++ = rqeptr->DclTaskPtr; status = FaolToBuffer (Buffer, sizeof(Buffer), &Length, CacheFao, &FaoVector); if (VMSnok (status) || status == SS$_BUFFEROVF) ErrorNoticed (rqptr, status, NULL, FI_LI); if (rqptr) NetWrite (rqptr, 0, Buffer, Length); else fputs (Buffer, stdout); if (rqeptr->DclTaskPtr) { /************/ /* DCL task */ /************/ vecptr = FaoVector; *vecptr++ = rqeptr->DclTaskPtr->TaskType; switch (rqeptr->DclTaskPtr->TaskType) { case DCL_TASK_TYPE_NONE : *vecptr++ = "none"; break; case DCL_TASK_TYPE_CLI : *vecptr++ = "CLI"; break; case DCL_TASK_TYPE_CGI_SCRIPT : *vecptr++ = "CGI"; break; case DCL_TASK_TYPE_CGIPLUS_SCRIPT : *vecptr++ = "CGIplus"; break; case DCL_TASK_TYPE_RTE_SCRIPT : *vecptr++ = "RTE"; break; default : *vecptr++ = "?"; } *vecptr++ = rqeptr->DclTaskPtr->ScriptProcessPid; if (rqeptr->DclTaskPtr->LifeTimeSecond == DCL_DO_NOT_DISTURB) *vecptr++ = "DO-NOT-DISTURB"; else { *vecptr++ = "!UL"; *vecptr++ = rqeptr->DclTaskPtr->LifeTimeSecond; } *vecptr++ = rqeptr->DclTaskPtr->CrePrcTermMbxChannel; *vecptr++ = rqeptr->DclTaskPtr->CrePrcTermMbxDevName+1; *vecptr++ = rqeptr->DclTaskPtr->CrePrcDetachProcess; *vecptr++ = rqeptr->DclTaskPtr->CrePrcDetachStarting; *vecptr++ = rqeptr->DclTaskPtr->CrePrcUserName; *vecptr++ = rqeptr->DclTaskPtr->CgiPlusVarStruct; *vecptr++ = rqeptr->DclTaskPtr->CgiPlusInChannel; *vecptr++ = rqeptr->DclTaskPtr->CgiPlusInDevName+1; *vecptr++ = rqeptr->DclTaskPtr->CgiPlusInIOsb.Status; *vecptr++ = rqeptr->DclTaskPtr->CgiPlusInIOsb.Count; *vecptr++ = rqeptr->DclTaskPtr->QueuedCgiPlusIn; *vecptr++ = rqeptr->DclTaskPtr->HttpInputChannel; *vecptr++ = rqeptr->DclTaskPtr->HttpInputDevName+1; *vecptr++ = rqeptr->DclTaskPtr->HttpInputIOsb.Status; *vecptr++ = rqeptr->DclTaskPtr->HttpInputIOsb.Count; *vecptr++ = rqeptr->DclTaskPtr->QueuedHttpInput; *vecptr++ = rqeptr->DclTaskPtr->ClientReadBufferSize; *vecptr++ = rqeptr->DclTaskPtr->ClientReadStripCrLf; *vecptr++ = rqeptr->DclTaskPtr->QueuedClientRead; *vecptr++ = rqeptr->DclTaskPtr->SysCommandChannel; *vecptr++ = rqeptr->DclTaskPtr->SysCommandDevName+1; *vecptr++ = rqeptr->DclTaskPtr->SysCommandIOsb.Status; *vecptr++ = rqeptr->DclTaskPtr->SysCommandIOsb.Count; *vecptr++ = rqeptr->DclTaskPtr->QueuedSysCommand; *vecptr++ = rqeptr->DclTaskPtr->QueuedSysCommandAllowed; *vecptr++ = rqeptr->DclTaskPtr->SysOutputSize; *vecptr++ = rqeptr->DclTaskPtr->SysOutputChannel; *vecptr++ = rqeptr->DclTaskPtr->SysOutputDevName+1; *vecptr++ = rqeptr->DclTaskPtr->SysOutputIOsb.Status; *vecptr++ = rqeptr->DclTaskPtr->SysOutputIOsb.Count; *vecptr++ = rqeptr->DclTaskPtr->QueuedSysOutput; *vecptr++ = rqeptr->DclTaskPtr->BuildRecords; *vecptr++ = rqeptr->DclTaskPtr->SysOutputBuildCount; *vecptr++ = rqeptr->DclTaskPtr->ClientWriteErrorCount; *vecptr++ = rqeptr->DclTaskPtr->ScriptProcessPid; *vecptr++ = rqeptr->DclTaskPtr->CrePrcTermRecord.acc$l_finalsts; *vecptr++ = rqeptr->DclTaskPtr->ScriptProcessActivated; *vecptr++ = rqeptr->DclTaskPtr->ScriptProcessResponded; *vecptr++ = rqeptr->DclTaskPtr->TaskRunDown; *vecptr++ = rqeptr->DclTaskPtr->DeleteProcess; *vecptr++ = rqeptr->DclTaskPtr->ForceImageExit; *vecptr++ = rqeptr->DclTaskPtr->ForceImageExitGetJpi; *vecptr++ = rqeptr->DclTaskPtr->ForceImageExitIssued; *vecptr++ = rqeptr->DclTaskPtr->ForceImageExitSecond; *vecptr++ = rqeptr->DclTaskPtr->JpiImagNameIOsb.Status; *vecptr++ = rqeptr->DclTaskPtr->JpiImagNameLength; *vecptr++ = rqeptr->DclTaskPtr->JpiImagName; *vecptr++ = rqeptr->DclTaskPtr->ScriptCpuMax; *vecptr++ = rqeptr->DclTaskPtr->ScriptCpuTimGetJpi; *vecptr++ = rqeptr->DclTaskPtr->JpiCpuTimIOsb.Status; *vecptr++ = rqeptr->DclTaskPtr->JpiCpuTim; *vecptr++ = rqeptr->DclTaskPtr->ScriptCpuTimMax; *vecptr++ = rqeptr->DclTaskPtr->CalloutFunction; *vecptr++ = rqeptr->DclTaskPtr->DclCommandPtr; *vecptr++ = rqeptr->DclTaskPtr->DclCommandSize; *vecptr++ = rqeptr->DclTaskPtr->DclCommandLength; *vecptr++ = rqeptr->DclTaskPtr->ScriptName; *vecptr++ = rqeptr->DclTaskPtr->ScriptFileName; status = FaolToBuffer (Buffer, sizeof(Buffer), &Length, DclTaskFao, &FaoVector); if (VMSnok (status) || status == SS$_BUFFEROVF) ErrorNoticed (rqptr, status, NULL, FI_LI); if (rqptr) NetWrite (rqptr, 0, Buffer, Length); else fputs (Buffer, stdout); } vecptr = FaoVector; *vecptr++ = rqeptr->DECnetTaskPtr; status = FaolToBuffer (Buffer, sizeof(Buffer), &Length, DECnetFao, &FaoVector); if (VMSnok (status) || status == SS$_BUFFEROVF) ErrorNoticed (rqptr, status, NULL, FI_LI); if (rqptr) NetWrite (rqptr, 0, Buffer, Length); else fputs (Buffer, stdout); if (rqeptr->DECnetTaskPtr) { /***************/ /* DECnet task */ /***************/ vecptr = FaoVector; *vecptr++ = rqeptr->DECnetTaskPtr->DECnetChannel; *vecptr++ = rqeptr->DECnetTaskPtr->DECnetConnectIOsb.Status; *vecptr++ = rqeptr->DECnetTaskPtr->DECnetConnectIOsb.Count; *vecptr++ = rqeptr->DECnetTaskPtr->DECnetReadIOsb.Status; *vecptr++ = rqeptr->DECnetTaskPtr->DECnetReadIOsb.Count; *vecptr++ = rqeptr->DECnetTaskPtr->DECnetWriteIOsb.Status; *vecptr++ = rqeptr->DECnetTaskPtr->DECnetWriteIOsb.Count; *vecptr++ = rqeptr->DECnetTaskPtr->QueuedDECnetIO; *vecptr++ = rqeptr->DECnetTaskPtr->ScriptResponded; *vecptr++ = rqeptr->DECnetTaskPtr->BuildRecords; *vecptr++ = rqeptr->DECnetTaskPtr->BuildCount; *vecptr++ = rqeptr->DECnetTaskPtr->CgiDialogState; *vecptr++ = rqeptr->DECnetTaskPtr->OsuDialogState; *vecptr++ = rqeptr->DECnetTaskPtr->OsuDnetCgi; status = FaolToBuffer (Buffer, sizeof(Buffer), &Length, DECnetTaskFao, &FaoVector); if (VMSnok (status) || status == SS$_BUFFEROVF) ErrorNoticed (rqptr, status, NULL, FI_LI); if (rqptr) NetWrite (rqptr, 0, Buffer, Length); else fputs (Buffer, stdout); } vecptr = FaoVector; *vecptr++ = rqeptr->DescrTaskPtr; *vecptr++ = rqeptr->DirTaskPtr; *vecptr++ = rqeptr->FileTaskPtr; *vecptr++ = rqeptr->GraphTaskPtr; *vecptr++ = rqeptr->HTAdminTaskPtr; *vecptr++ = rqeptr->IsMapTaskPtr; *vecptr++ = rqeptr->MenuTaskPtr; *vecptr++ = rqeptr->ProxyTaskPtr; status = FaolToBuffer (Buffer, sizeof(Buffer), &Length, DescrFao, &FaoVector); if (VMSnok (status) || status == SS$_BUFFEROVF) ErrorNoticed (rqptr, status, NULL, FI_LI); if (rqptr) NetWrite (rqptr, 0, Buffer, Length); else fputs (Buffer, stdout); if (rqeptr->ProxyTaskPtr) { /**************/ /* proxy task */ /**************/ NetGetBgDevice (rqeptr->ProxyTaskPtr->ProxyChannel, ProxyDevName, sizeof(ProxyDevName)); vecptr = FaoVector; *vecptr++ = rqeptr->ProxyTaskPtr->ProxyChannel; *vecptr++ = ProxyDevName+1; *vecptr++ = &rqeptr->ProxyTaskPtr->ConnectIpAddress; *vecptr++ = &rqeptr->ProxyTaskPtr->RequestHostIpAddress; *vecptr++ = rqeptr->ProxyTaskPtr->RequestHostPort; *vecptr++ = rqeptr->ProxyTaskPtr->RequestSchemeName; *vecptr++ = rqeptr->ProxyTaskPtr->ProxyTunnel; *vecptr++ = rqeptr->ProxyTaskPtr->ProxyLookupRetryCount; *vecptr++ = rqeptr->ProxyTaskPtr->ProxyConnectIOsb.Status; *vecptr++ = rqeptr->ProxyTaskPtr->ProxyConnectIOsb.Count; *vecptr++ = rqeptr->ProxyTaskPtr->ProxyReadIOsb.Status; *vecptr++ = rqeptr->ProxyTaskPtr->ProxyReadIOsb.Count; *vecptr++ = rqeptr->ProxyTaskPtr->ProxyReadRawAstFunction; *vecptr++ = rqeptr->ProxyTaskPtr->ProxyReadRawDataPtr; *vecptr++ = rqeptr->ProxyTaskPtr->ProxyReadRawDataSize; *vecptr++ = rqeptr->ProxyTaskPtr->ProxyWriteIOsb.Status; *vecptr++ = rqeptr->ProxyTaskPtr->ProxyWriteIOsb.Count; *vecptr++ = rqeptr->ProxyTaskPtr->ProxyWriteRawAstFunction; *vecptr++ = rqeptr->ProxyTaskPtr->ProxyWriteRawDataPtr; *vecptr++ = rqeptr->ProxyTaskPtr->ProxyWriteRawDataCount; *vecptr++ = rqeptr->ProxyTaskPtr->BytesRawRx; *vecptr++ = rqeptr->ProxyTaskPtr->BytesRawTx; *vecptr++ = rqeptr->ProxyTaskPtr->VerifyRecordPtr; *vecptr++ = rqeptr->ProxyTaskPtr->RebuiltRequestLength; *vecptr++ = rqeptr->ProxyTaskPtr->RebuiltRequestPtr; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseBodyLength; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseBufferNetCount; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseBufferNetPtr; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseCacheControlMaxAge; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseCacheControlMaxAgeZero; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseCacheControlMustReval; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseCacheControlNoCache; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseCacheControlNoStore; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseCacheControlNoTransform; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseCacheControlPrivate; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseCacheControlProxyReval; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseCacheControlPublic; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseCacheControlSMaxAge; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseChunkedCount; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseChunkedEnd; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseChunkedEol; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseChunkedEot; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseChunkedInit; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseChunkedSize; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseChunkedString; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseChunkedNewlineCount; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseConsecutiveNewLineCount; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseContentEncodingGzip; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseContentEncodingUnknown; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseContentLength; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseExpires; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseExpiresBinTime; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseHeaderLength; if (!rqeptr->ProxyTaskPtr->ResponseHeaderPtr) { *vecptr++ = sizeof(WATCH_NULL_STRING)-1; *vecptr++ = WATCH_NULL_STRING; } else if (rqeptr->ProxyTaskPtr->ResponseConsecutiveNewLineCount < 2) { *vecptr++ = rqeptr->ProxyTaskPtr->ResponseHeaderLength; *vecptr++ = WATCH_NULL(rqeptr->ProxyTaskPtr->ResponseHeaderPtr); } else { *vecptr++ = sizeof(WATCH_NULL_STRING)-1; *vecptr++ = WATCH_NULL_STRING; } *vecptr++ = rqeptr->ProxyTaskPtr->ResponseHeaderSent; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseLastModified; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseLastModifiedBinTime; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseTransferEncodingChunked; *vecptr++ = rqeptr->ProxyTaskPtr->ResponseUpgradeWebSocket; *vecptr++ = rqeptr->ProxyTaskPtr->RebuiltResponseLength; *vecptr++ = rqeptr->ProxyTaskPtr->RebuiltResponsePtr; *vecptr++ = rqeptr->ProxyTaskPtr->CannotCache; *vecptr++ = rqeptr->ProxyTaskPtr->ProxyCacheFileName; *vecptr++ = rqeptr->ProxyTaskPtr->ProxyCacheSuitable; *vecptr++ = rqeptr->ProxyTaskPtr->ProxyCacheFileSizeInBytes; *vecptr++ = rqeptr->ProxyTaskPtr->ProxyCacheLastModifiedHours; *vecptr++ = rqeptr->ProxyTaskPtr->ProxyCacheReadBytes; *vecptr++ = &rqeptr->ProxyTaskPtr->ProxyCacheFileCdt; status = FaolToBuffer (Buffer, sizeof(Buffer), &Length, ProxyTaskFao, &FaoVector); if (VMSnok (status) || status == SS$_BUFFEROVF) ErrorNoticed (rqptr, status, NULL, FI_LI); if (rqptr) NetWrite (rqptr, 0, Buffer, Length); else fputs (Buffer, stdout); } vecptr = FaoVector; *vecptr++ = rqeptr->PutTaskPtr; *vecptr++ = rqeptr->SsiTaskPtr; *vecptr++ = rqeptr->UpdTaskPtr; status = FaolToBuffer (Buffer, sizeof(Buffer), &Length, PutFao, &FaoVector); if (VMSnok (status) || status == SS$_BUFFEROVF) ErrorNoticed (rqptr, status, NULL, FI_LI); if (rqptr) NetWrite (rqptr, 0, Buffer, Length); else fputs (Buffer, stdout); Watch.Module = WatchModule; } /*****************************************************************************/ /* Display the size of selected data structures. */ WatchReportStruct ( REQUEST_STRUCT *rqptr, REQUEST_AST NextTaskFunction ) { #if WATCH_MOD static char ResponseFao [] = "!25 !6UL (bytes)\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n\ !25 !6UL\n"; int status; unsigned long FaoVector [32]; unsigned long *vecptr; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "WatchReportStruct()\n"); if (!rqptr->RemoteUser[0]) { rqptr->rqResponse.HttpStatus = 403; ErrorGeneral (rqptr, ErrorWatchAuthNeeded, FI_LI); SysDclAst (NextTaskFunction, rqptr); return; } vecptr = FaoVector; *vecptr++ = sizeof(struct AccountingStruct); *vecptr++ = sizeof(struct ActivityGblSecStruct); *vecptr++ = sizeof(struct AuthCacheRecordStruct); *vecptr++ = sizeof(struct AuthConfigStruct); *vecptr++ = sizeof(struct AuthGblSecStruct); *vecptr++ = sizeof(struct AuthHtaRecordStruct); *vecptr++ = sizeof(struct AuthPathRecordStruct); *vecptr++ = sizeof(struct AuthRealmRecordStruct); *vecptr++ = sizeof(struct BodyProcessStruct); *vecptr++ = sizeof(struct CacheStruct); *vecptr++ = sizeof(struct DclTaskStruct); *vecptr++ = sizeof(struct DclScriptNameCacheStruct); *vecptr++ = sizeof(struct DirTaskStruct); *vecptr++ = sizeof(struct DECnetConnectStruct); *vecptr++ = sizeof(struct DECnetTaskStruct); *vecptr++ = sizeof(HTTPD_GBLSEC); *vecptr++ = sizeof(struct MonRequestStruct); *vecptr++ = sizeof(struct OdsStruct); *vecptr++ = sizeof(struct ProxyTaskStruct); *vecptr++ = sizeof(PROXY_ACCOUNTING_STRUCT); *vecptr++ = sizeof(struct ProxyVerifyGblSecStruct); *vecptr++ = sizeof(struct PutTaskStruct); *vecptr++ = sizeof(struct RequestStruct); *vecptr++ = sizeof(struct ServiceStruct); *vecptr++ = SesolaGblSecStructSize; *vecptr++ = sizeof(struct SsiTaskStruct); *vecptr++ = sizeof(struct StrDscStruct); *vecptr++ = sizeof(struct UpdTaskStruct); *vecptr++ = sizeof(struct WebDavTaskStruct); status = FaolToNet (rqptr, ResponseFao, &FaoVector); if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); ResponseHeader200 (rqptr, "text/plain", &rqptr->NetWriteBufferDsc); SysDclAst (NextTaskFunction, rqptr); #else /* WATCH_MOD */ rqptr->rqResponse.HttpStatus = 403; ErrorGeneral (rqptr, ErrorWatchNoModule, FI_LI); SysDclAst (NextTaskFunction, rqptr); #endif /* WATCH_MOD */ } /****************************************************************************/