/*****************************************************************************/ /* hdisk.c This application links to the Gift.c application's GIF and graphic code! Functions begining Gift...() and storage beginning Graphic... is Gift.c code. HyperDisk! Provides disk details, including a usage bar graph, for one or more disks specified as part of the path or as a CGI form variable "DISKS=". Disk device names may be specified separated by commas, forward-slashes, or (probably most simply) just with a full-colon (which is used by VMS as a device name separator). Disk details include blocks and Mbytes total, used and free, as well as error count. Component devices of volumes sets are displayed individually. Variations allowed in specifying disks: http://host/disk/device http://host/disk/device1:device2:device3 http://host/disk/device1,device2,device3 http://host/disk/device1/device2/device3 http://host/disk?disk=device http://host/disk?disk=device1:device2:device3 http://host/disk?disk=device1,device2,device3 http://host/disk?disk=device1/device2/device3 If the string "graphiconly" occurs in the query string only a bar-graph GIF for the specified device is generated and sent. This allows documents to include a tag such as to include the usage bar-graph for any given device (of course only one may be specified with each use). Page colouration and "button" labels may be specified via the appropriate command-line qualifiers (or corresponding logical name). Defaults for any not specified. Specifiy as /WHATEVER="" to NOT specify the corresponding colour (i.e. leave it to the browser). See "Qualifiers" section below, and also about the logical name "HDISK$PARAM". An example of changing the page colour to white and the banner to red! /PBGCOLOR="#ffffff" /PHBGCOLOR="#ff0000" The script can format a page in either of two layouts. 1. Tables are used to create a coloured header and button bar (DEFAULT). Default colours are white page with grey heading and button outlines. 2. Textual header, horizontal rules and a textual button bar. No default colours. ACKNOWLEDGEMENT --------------- Although the graphic generation and GIF header code is mine the actual GIF compression code employed is derived from the PBM suite, is copyright, and used within the owner's guidelines: * GIF Image compression - LZW algorithm implemented with Trie type * structure. * Written by Bailey Brown, Jr. * last change May 24, 1990 * file: compgif.c * * You may use or modify this code as you wish, as long as you mention * my name in your documentation. * * - Bailey Brown, Jr. QUALIFIERS ---------- /DBUG turns on all "if (Debug)" statements /PBACKGROUND=
background image path /PBGCOLOR= background colour /PBBGCOLOR= button background color /PBBORDER= width of button border /PHBGCOLOR= heading background color /PHBORDER= width of heading and button-bar border /PHLOCAL= local information to be included in header /PHTEXT= heading text colour /PLAYOUT= 1 is coloured header & buttons, 2 is text & horizontal rules /PLINK= link colour /PTEXT= text colour /PVLINK= visited link colour CGI VARIABLES ------------- WWW_FORM_BRIEF if the word brief occurs in the query string only the bar graph is generated, no device details WWW_FORM_DISK one of more disk device names WWW_FORM_DISKS ditto WWW_FORM_HEIGHT height in pixels of the bar-graph WWW_FORM_GRAPHICONLY if the word graphiconly occurs in the query string a gif representing the device is generated and returned WWW_FORM_HELP if the word help occurs in the query string it results in a redirection to the help document WWW_FORM_PERCENTAGE results in a bar graph GIF being returned WWW_FORM_WIDTH width in pixels of the bar-graph WWW_SCRIPT_NAME script name WWW_SERVER_NAME server host name WWW_SERVER_PORT server IP port WWW_QUERY_STRING query string WWW_PATH_INFO document path (everything following the script name) OSU ENVIRONMENT --------------- Script responses are returned in OSU "raw" mode; the script taking care of the full response header and correctly carriage-controlled data stream, text or binary!! The script standard output stream is reopened in binary mode (no translation of '\n') with a maximum record size set to 4096 bytes (failure to set this results in the OSU server reporting %SYSTEM-F-DATAOVERUN errors). The binary output is enclosed by suitably fflushed() "\n",
PageScheme[PS_HEADBORDER],
PageScheme[PS_HEADBORDER],
PageScheme[PS_HEADBGCOLOR]);
if (ButtonCount == 0 || !Top1Bottom2)
fprintf (stdout, " \n");
else
{
fprintf (stdout,
"
|
\n\
\n\
%s\n\
\n\ \n\ *hyperDISK\n\ \n\ | %s
\n", CgiServerSoftwarePtr, ContentTypeCharset, SoftwareID, CgiTypePtr, DiskName, PageScheme[PS_BODYTAG], PageScheme[PS_HEADBORDER], PageScheme[PS_HEADPADDING], PageScheme[PS_HEADBGCOLOR], PageScheme[PS_HEADTEXT], DayDateTime, PageScheme[PS_HEADTEXT], PageScheme[PS_HEADLOCAL]); HttpHasBeenOutput = true; cptr = DiskName; while (*cptr) { sptr = cptr; while (*cptr && isspace(*cptr)) cptr++; while (*cptr && *cptr != ':' && *cptr != ',' && *cptr != '/') cptr++; if (*cptr) *cptr++ = '\0'; if (!*sptr) continue; OneDiskInfo (sptr); } fprintf (stdout, "\n\
\n"); ButtonBar (2); fprintf (stdout, "\n\ \n"); } /*****************************************************************************/ /* */ OneDiskInfo (char *DiskName) { int status, ErrorCount, VolumeCount; unsigned long TotalMaxBlock, TotalFreeBlocks, TotalUsedBlocks; double dGBytesFree, dGBytesMax, dGBytesUsed, dPercentUsed, dPercentFree; struct DiskInfoStruct *DiskInfoPtr, *FirstDiskInfoPtr, *NextDiskInfoPtr; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "OneDiskInfo()\n"); if ((FirstDiskInfoPtr = calloc (sizeof(struct DiskInfoStruct), 1)) == NULL) exit (ErrorVmsStatus (vaxc$errno, "allocating memory", "", __FILE__, __LINE__)); if (VMSnok (status = GetDiskInfo (DiskName, FirstDiskInfoPtr))) { free (FirstDiskInfoPtr); if (status == SS$_NOSUCHDEV) { if (DoGraphicOnly) GiftUsageBar (0, 100, "NO SUCH DEVICE!"); else fprintf (stdout, "
This device was in a mount verify state, but that has now \ timed-out. It could have been off-line, had the wrong volume on-line, \ had excessive errors or a corrupted file system. In short ... \ there is a major problem that should investigated ASAP.\n", DiskName); return; } /* mount verify bit should normally be 0 */ if (FirstDiskInfoPtr->UcbStatus.lo32 & UCB$V_MNTVERIP) { free (FirstDiskInfoPtr); if (DoGraphicOnly) GiftUsageBar (0, 100, "IN MOUNT VERIFY!"); else fprintf (stdout, "
This device is in a mount verify state. It could be off-line, \ have the wrong volume on-line, have excessive errors or a corrupted \ file system. In short ... there is a major problem that should \ investigated ASAP.\n", DiskName); return; } if (FirstDiskInfoPtr->VolSetMem && FirstDiskInfoPtr->VolNumber > 1) { free (FirstDiskInfoPtr); if (DoGraphicOnly) GiftUsageBar (0, 100, "NOT PRIMARY VOLUME SET MEMBER!"); else fprintf (stdout, "
This device is part of a volume set, but is not the primary member \ of that set. Specify only the primary member!\n", DiskName); return; } /***************************************/ /* additional devices for a volume set */ /***************************************/ DiskInfoPtr = FirstDiskInfoPtr; while (DiskInfoPtr->NextDevName[0]) { if ((DiskInfoPtr->NextPtr = calloc (sizeof(struct DiskInfoStruct), 1)) == NULL) exit (ErrorVmsStatus (vaxc$errno, "allocating memory", "", __FILE__, __LINE__)); GetDiskInfo (DiskInfoPtr->NextDevName, DiskInfoPtr->NextPtr); DiskInfoPtr = DiskInfoPtr->NextPtr; } /********************/ /* calculate totals */ /********************/ dGBytesFree = dGBytesMax = dGBytesUsed = 0.0; ErrorCount = TotalMaxBlock = TotalFreeBlocks = TotalUsedBlocks = VolumeCount = 0; DiskInfoPtr = FirstDiskInfoPtr; while (DiskInfoPtr != NULL) { VolumeCount++; ErrorCount += DiskInfoPtr->ErrCnt; dGBytesMax += (double)DiskInfoPtr->MaxBlock * 512.0 / 1000000000.0; TotalMaxBlock += DiskInfoPtr->MaxBlock; dGBytesFree += (double)DiskInfoPtr->FreeBlocks * 512.0 / 1000000000.0; TotalFreeBlocks += DiskInfoPtr->FreeBlocks; dGBytesUsed += (double)DiskInfoPtr->UsedBlocks * 512.0 / 1000000000.0; TotalUsedBlocks += DiskInfoPtr->UsedBlocks; DiskInfoPtr = DiskInfoPtr->NextPtr; } dPercentUsed = dGBytesUsed * 100.0 / dGBytesMax; dPercentFree = dGBytesFree * 100.0 / dGBytesMax; /****************/ /* graphic only */ /****************/ if (DoGraphicOnly) { /* local storage */ char String [256]; if (dPercentUsed == 100.0) sprintf (String, "%s %.*fGB %.0f%% used", DiskName, GBytesPrecision(dGBytesMax), dGBytesMax, dPercentUsed); else if (dPercentUsed > 0.1) sprintf (String, "%s %.*fGB %.0f%% used %.0f%% free", DiskName, GBytesPrecision(dGBytesMax), dGBytesMax, dPercentUsed, dPercentFree); else sprintf (String, "%s %.*fGB %.0f%% free", DiskName, GBytesPrecision(dGBytesMax), dGBytesMax, dPercentFree); GiftUsageBar ((int)dPercentUsed, 85, String); /* no need to deallocate memory, will be exit()ing shortly */ return; } /*********************/ /* graphic image tag */ /*********************/ fprintf (stdout, "
\n"); else fprintf (stdout, "
Volume set comprising %d devices.\n
\n",
VolumeCount);
fprintf (stdout,
"\n\
\n\
|
Reported by server.\n\
%s\n\ \n\ \n", SoftwareID, cptr, SourceLineNumber, Text); } else { fprintf (stdout, "HTTP/1.0 404 Error\r\n\ Server: %s\r\n\ Content-Type: text/html%s\r\n\ \r\n\ \n\
\n\ \n\ \n\ \n\Reported by server.\n\
%s\n\ \n\ \n", CgiServerSoftwarePtr, ContentTypeCharset, SoftwareID, cptr, SourceLineNumber, Text); } return (SS$_NORMAL); } /*****************************************************************************/ /* */ ErrorVmsStatus ( int StatusValue, char *Text, char *HiddenText, char *SourceFileName, int SourceLineNumber ) { static char Message [256]; static $DESCRIPTOR (MessageDsc, Message); register char *cptr; int status; short int Length; /*********/ /* begin */ /*********/ if (VMSok (status = sys$getmsg (StatusValue, &Length, &MessageDsc, 1, 0))) { Message[Length] = '\0'; Message[0] = toupper(Message[0]); } else strcpy (Message, ""sys$getmsg() failed""); /* The source file format provided by the "__FILE__" macro will be "device:[directory]name.type;ver". Reduce that to "name.type". */ for (cptr = SourceFileName; *cptr && *cptr != ';'; cptr++); if (*cptr) { while (*cptr != '.') cptr--; *cptr-- = '\0'; } while (*cptr != ']') cptr--; cptr++; if (HttpHasBeenOutput) { fprintf (stdout, "
Reported by server.\n\
%s ... %s\n\ \n\ \n\ \n", SoftwareID, cptr, SourceLineNumber, Message, Text, StatusValue, HiddenText); } else { fprintf (stdout, "HTTP/1.0 404 Error\r\n\ Server: %s\r\n\ Content-Type: text/html%s\r\n\ \r\n\ \n\
\n\ \n\ \n\ \n\Reported by server.\n\
%s ... %s\n\ \n\ \n\ \n", CgiServerSoftwarePtr, ContentTypeCharset, SoftwareID, cptr, SourceLineNumber, Message, Text, StatusValue, HiddenText); } return (SS$_NORMAL); } /****************************************************************************/ /* Does a case-insensitive, character-by-character string compare and returns true if two strings are the same, or false if not. If a maximum number of characters are specified only those will be compared, if the entire strings should be compared then specify the number of characters as 0. */ boolean strsame ( register char *sptr1, register char *sptr2, register int count ) { while (*sptr1 && *sptr2) { if (toupper (*sptr1++) != toupper (*sptr2++)) return (false); if (count) if (!--count) return (true); } if (*sptr1 || *sptr2) return (false); else return (true); } /*****************************************************************************/