#!/bin/sh # This is a shell archive (shar 3.32) # made 10/08/1997 19:50 UTC by dcoburn@matt # Source directory /users/dcoburn/dm # # existing files WILL be overwritten # This format requires very little intelligence at unshar time. # "echo" and "sed" will be needed. # # This shar contains: # length mode name # ------ ---------- ------------------------------------------ # 10764 -rw-rw-r-- dm.ec # 3345 -rw-rw-r-- dm.h # 6730 -rw-rw-r-- README # # ============= dm.ec ============== echo "x - extracting dm.ec (Text)" sed 's/^X//' << 'SHAR_EOF' > dm.ec && X/*----------------------------------------------------------------------------- XModule: dm.ec XAuthor: David Coburn XDate: 07 September 1997 XComments: X This program is designed to make some of the disk administration X chores for Informix OnLine a bit easier, especially those dealing X with disk sizing and space allocation. Some of the summary X information is designed for regular reports to forewarn of possible X sizing problems (running out of space, etc.). Others provide more X detailed look on a chunk by chunk basis of disk information. X XContents: X dm.ec - Main program X dm.h - Header for main program X XWarnings: X Tested with Informix OnLine 7.22 only. Compiles fine and runs on HPUX X 10.20. Has been tested with other compilers, but I don't have access X to an ANSI compiler, so if you use that sort of thing you're on your X own. X XComments: X Please send comments and problems to coburn@scn.org. X XCopyright: X Copyright 1997, David Coburn. Permission is granted to use this X however you really want, short of selling it. Or using it in a book X about how NOT to write code. X X---------------------------------------------------------------------------- */ X#include X#include X#include X#include X#include X XEXEC SQL include dm.h; X Xint main(); Xvoid setopts(); Xchar *center(); Xchar *get_time(); Xvoid disk_free(); Xvoid disk_map(); Xvoid disk_free_header(); Xvoid usage(); Xvoid sql_errors(); X XEXEC SQL BEGIN DECLARE SECTION; X char query_str [ MAXQUERY ]; XEXEC SQL END DECLARE SECTION; X Xint Xmain( argc, argv) Xint argc; Xchar *argv[]; X{ X int arg_val, c; X X EXEC SQL WHENEVER SQLERROR call sql_errors; X setopts(argc,argv); X if ( help ) X { X usage(argv[0]); X } X else X { X stmt_str = "Establishing connection."; X EXEC SQL connect to "sysmaster"; X if ( maponly ) X disk_map(); X else X disk_free(); X } X return ( 0 ); X} X Xvoid Xdisk_map() X{ X EXEC SQL BEGIN DECLARE SECTION; X struct s_sysdbspaces dbspaces; X struct s_syschunks chunks; X EXEC SQL END DECLARE SECTION; X char last_space[21]; X X memset(last_space,0, sizeof(last_space)); X X stmt_str = "Preparing disk map queries."; X sprintf(query_str,"select %s %s %s %s from syschunks order by %s", X "chknum, dbsnum, nxchknum, chksize, offset, nfree,", X "is_offline, is_recovering, is_blobchunk, is_inconsistent,", X "flags, fname, mfname, moffset, mis_offline, mis_recovering,", X "mflags", X "fname, offset"); X EXEC SQL prepare chunk_query2 from $query_str; X X sprintf(query_str,"select %s %s %s from sysdbspaces where dbsnum = ?", X "dbsnum, name, owner, fchunk, nchunks,", X "is_mirrored, is_blobspace, is_temp,", X "flags"); X EXEC SQL prepare space_query2 from $query_str; X X stmt_str = "Declaring cursors for disk map queries."; X EXEC SQL declare chunk_curs2 cursor for chunk_query2; X EXEC SQL declare space_curs2 cursor for space_query2; X X stmt_str = "Opening outer disk map query."; X EXEC SQL open chunk_curs2; X X if ( namert ) X printf("%3s %3s %-20s %8s %8s %8s %s\n", "Chk","Dbs", X " Name","Start","End","Free", "Space Name"); X else X printf("%-20s %3s %3s %-20s %8s %8s %8s\n", "Space Name","Chk","Dbs", X " Name","Start","End","Free"); X X for ( ;; ) X { X stmt_str = "Fetching outer disk map query."; X EXEC SQL fetch chunk_curs2 into :chunks; X if ( strncmp(SQLSTATE,"00",2) ) break; X stmt_str = "Opening inner disk map cursor."; X EXEC SQL open space_curs2 using :chunks.dbsnum; X stmt_str = "Fetching inner disk map cursor."; X EXEC SQL fetch space_curs2 into :dbspaces; X if ( strncmp(SQLSTATE,"00",2) ) X { X printf("Error reading dbspace info for chunk %d.\n",chunks.dbsnum); X } X else X if ( strncmp ( chunks.fname, last_space, sizeof ( chunks.fname ) ) ) X { X if ( namert ) X printf("\n%3d %3d %20s %8d %8d %8d %s\n", X chunks.chknum, chunks.dbsnum, X dbspaces.name, chunks.offset, X chunks.chksize + chunks.offset - 1, X chunks.nfree, chunks.fname); X else X printf("\n%20s %3d %3d %20s %8d %8d %8d\n", X chunks.fname, chunks.chknum, chunks.dbsnum, X dbspaces.name, chunks.offset, X chunks.chksize + chunks.offset - 1, chunks.nfree); X sprintf(last_space, "%s", chunks.fname ); X } X else X { X if ( namert ) X printf("%3d %3d %20s %8d %8d %8d\n", X chunks.chknum, chunks.dbsnum, dbspaces.name, X chunks.offset, chunks.chksize + chunks.offset - 1, X chunks.nfree); X else X printf("%20s %3d %3d %20s %8d %8d %8d\n", " ", X chunks.chknum, chunks.dbsnum, dbspaces.name, X chunks.offset, chunks.chksize + chunks.offset - 1, X chunks.nfree); X } X } X} X Xvoid Xdisk_free() X{ X short new_space=0; X int num_spaces = 0; X long num_pages, pages_free; X float pct_used; X X EXEC SQL BEGIN DECLARE SECTION; X struct s_sysdbspaces dbspaces; X struct s_syschunks chunks; X EXEC SQL END DECLARE SECTION; X X disk_free_header(); X X stmt_str = "Preparing first disk free query."; X sprintf(query_str,"select %s %s %s from sysdbspaces ", X "dbsnum, name, owner, fchunk, nchunks,", X "is_mirrored, is_blobspace, is_temp,", X "flags"); X EXEC SQL prepare space_query from $query_str; X stmt_str = "Preparing second disk free query."; X sprintf(query_str,"select %s %s %s %s from %s where %s order by %s", X "chknum, dbsnum, nxchknum, chksize, offset, nfree,", X "is_offline, is_recovering, is_blobchunk, is_inconsistent,", X "flags, fname, mfname, moffset, mis_offline, mis_recovering,", X "mflags", X "syschunks", X "dbsnum = ?", X "chknum" X ); X X EXEC SQL prepare chunk_query from $query_str; X X stmt_str = "Declaring cursors for disk free queries."; X EXEC SQL declare space_curs cursor for space_query; X EXEC SQL declare chunk_curs cursor for chunk_query; X X stmt_str = "Opening outer cursor for disk free queries."; X EXEC SQL open space_curs; X X for ( ;; ) X { X stmt_str = "Fetching inner disk free data."; X EXEC SQL fetch space_curs into :dbspaces.dbsnum, :dbspaces.name, X :dbspaces.owner, :dbspaces.fchunk, :dbspaces.nchunks, X :dbspaces.is_mirrored, :dbspaces.is_blobspace, :dbspaces.is_temp, X :dbspaces.flags; X X if ( strncmp(SQLSTATE,"00",2) ) break; X num_spaces++; X new_space = 1; X if ( summary == TRUE ) X { X if ( num_spaces == 1 ) X printf(" ID Space Name Size Free\n"); X } X else X printf(" ID Space Name Chunk Offset Size "); X printf("Free Device\n"); X printf("%4d %s", dbspaces.dbsnum, dbspaces.name); X num_pages = 0; X pages_free = 0; X X stmt_str = "Opening chunk cursor"; X EXEC SQL open chunk_curs using :dbspaces.dbsnum; X for ( ;; ) X { X stmt_str = "Fetching chunk cursor."; X EXEC SQL fetch chunk_curs into :chunks; X if ( strncmp(SQLSTATE,"00",2) ) break; X num_pages += chunks.chksize; X pages_free += chunks.nfree; X if ( summary == FALSE ) X { X if ( new_space == 0 ) X { X printf("%27d %8d %8d %8d %s\n", chunks.chknum, X chunks.offset, chunks.chksize, X chunks.nfree, chunks.fname); X } X else X { X new_space = 0; X printf("%4d %8d %8d %8d %s\n", X chunks.chknum, chunks.offset, chunks.chksize, X chunks.nfree, chunks.fname); X } X } X } X if ( summary == TRUE ) X { X pct_used = (float) (num_pages-pages_free)*100/num_pages; X printf("%15ld %8ld (%5.2f%%)",num_pages,pages_free,pct_used); X if ( pct_used >= FLAG_PCT ) printf("***\n"); X else printf("\n"); X } X else X { X printf("Total: %38ld %8ld\n\n",num_pages,pages_free); X } X EXEC SQL close chunk_curs; X } X} X Xchar * Xget_time ( ) X{ X struct tm *time_struct; X time_t curr_time; X static char time_line[MAXLINE+1]; X X curr_time = time( &curr_time ); X if ( curr_time == -1 ) X { X return (char *) "Error reading time.\n" ; X } X else X { X time_struct = localtime ( &curr_time ); X if ( clockval == 12 ) X time_fmt = "%A %d-%b-%Y @ %I:%M:%S %p"; X strftime ( time_line, MAXLINE, time_fmt, time_struct ); X return time_line; X } X} X Xvoid Xdisk_free_header() X{ X char print_line[MAXLINE+1]; X char *toprint; X struct utsname name; X X toprint = center("D I S K U T I L I Z A T I O N R E P O R T"); X printf("%s\n\n",toprint); X toprint = center( get_time ( ) ); X printf("%s\n\n",toprint); X X uname ( &name ); X sprintf(print_line," SERVER = %s", name.nodename); X printf("%s\n",print_line); X sprintf(print_line," ONCONFIG = %s", getenv("ONCONFIG")); X printf("%s\n",print_line); X sprintf(print_line,"INFORMIXSERVER = %s", getenv("INFORMIXSERVER")); X printf("%s\n",print_line); X sprintf(print_line," INFORMIXDIR = %s", getenv("INFORMIXDIR")); X printf("%s\n",print_line); X printf("\n"); X} X Xchar * Xcenter ( text_string ) Xchar *text_string; X{ X static char fmt_str[MAXLINE+1]; X int i; X X for ( i = 0; i < MAXLINE; i++ ) fmt_str[i] = ' '; X fmt_str[MAXLINE+1] = '0'; X X i = ( int ) ( ( MAXLINE-strlen ( text_string ) ) / 2 ); X for ( ; *text_string != '\0'; text_string++,i++ ) X fmt_str[i] = *text_string; X fmt_str[i] = 0; X return fmt_str; X} X Xvoid Xsetopts(argc, argv) Xint argc; Xchar *argv[]; X{ X int c; X int errflg=0; X X extern char *optarg; X extern int optind, optopt; X X if ( argc < 2 ) X { X usage(argv[0]); X exit ( 3 ); X } X X while ((c = getopt(argc,argv, "hsdmMt:T:")) != -1 ) X switch(c) X { X case 'h': X help = TRUE; X break; X case 's': X summary = TRUE; X break; X case 'd': X summary = FALSE; X break; X case 'm': X maponly = TRUE; X namert = FALSE; X break; X case 'M': X maponly = TRUE; X namert = TRUE; X break; X case 't': X clockval = atoi ( optarg ); X if ( clockval != 12 && clockval != 24 ) X { X fprintf(stderr,"Argument -t reqires an argument of either "); X fprintf(stderr,"12 or 24. (Default is 24.)\n"); X clockval = 12; X } X break; X case 'T': X time_fmt = optarg; X break; X case ':': X fprintf(stderr,"Option -%c requires an argument\n", X optopt); X errflg++; X break; X case '?': X fprintf(stderr,"Unrecognized option: -%c\n",optopt); X errflg++; X } X X if ( errflg ) X { X usage(argv[0]); X exit (2); X } X} X Xvoid Xusage(progname) Xchar *progname; X{ X short i; X X if ( progname == NULL ) progname = "dm"; X for ( i=0; helpdoc[i] != 0; i++ ) printf(helpdoc[i],progname); X} X Xvoid Xsql_errors() X{ X EXEC SQL BEGIN DECLARE SECTION; X int exception_count; X int i; X char sqlstate[6]; X char msg_txt[255]; X EXEC SQL END DECLARE SECTION; X X EXEC SQL WHENEVER ERROR goto errm_error; X EXEC SQL get diagnostics :exception_count = NUMBER; X X fprintf(stderr,"\nERROR PROCESSING SQL: %s\n", stmt_str); X for ( i = 1; i <= exception_count; i++ ) X { X EXEC SQL get diagnostics exception :i X :sqlstate = RETURNED_SQLSTATE, X :msg_txt = MESSAGE_TEXT; X X fprintf(stderr,"\nItem %2d:\t%s %s\n",i,sqlstate,msg_txt); X } X fprintf(stderr,"\n"); X EXEC SQL WHENEVER SQLERROR call sql_errors; X exit (4); Xerrm_error: X fprintf(stderr,"Error processing error: terminating program.\n"); X exit (5); X} SHAR_EOF # ============= dm.h ============== echo "x - extracting dm.h (Text)" sed 's/^X//' << 'SHAR_EOF' > dm.h && X/*----------------------------------------------------------------------------- XModule: dm.h XAuthor: David Coburn XDate: 07 September 1997 XComments: X Header file to use with dm.ec. See that one for details. X XContents: X dm.ec - Main program X dm.h - Header for main program X XWarnings: X Tested with Informix OnLine 7.22 only. Compiles fine and runs on HPUX X 10.20. Has been tested with other compilers, but I don't have access X to an ANSI compiler, so if you use that sort of thing you're on your X own. X XComments: X Please send comments and problems to coburn@scn.org. X XCopyright: X Copyright 1997, David Coburn. Permission is granted to use this X however you really want, short of selling it. Or using it in a book X about how NOT to write code. X X---------------------------------------------------------------------------- */ XEXEC SQL BEGIN DECLARE SECTION; X X typedef struct s_sysdbspaces { X short dbsnum; /* smallint */ X char name[19]; /* char(18) */ X char owner[9]; /* char(8) */ X short fchunk; /* smallint */ X short nchunks; /* smallint */ X int is_mirrored; /* integer */ X int is_blobspace; /* integer */ X int is_temp; /* integer */ X short flags; /* smallint */ X } dbspaceinfo; X X typedef struct s_syschunks { X short chknum; /* smallint */ X short dbsnum; /* smallint */ X short nxchknum; /* smallint */ X int chksize; /* integer */ X int offset; /* integer */ X int nfree; /* integer */ X int is_offline; /* integer */ X int is_recovering; /* integer */ X int is_blobchunk; /* integer */ X int is_inconsistent; /* integer */ X short flags; /* smallint */ X string fname[129]; /* char(128 */ X char mfname[129]; /* char(128 */ X int moffset; /* integer */ X int mis_offline; /* integer */ X int mis_recovering; /* integer */ X short mflags; /* smallint */ X } chunkinfo; X XEXEC SQL END DECLARE SECTION; X Xchar *helpdoc[] = { X "Usage:\n", X "\t%s [-h | -s | -d | -m | -M | -t {12|24} | -T]\n", X "\n", X "Where:\r", X "\t-h\tprint this help file;\n", X "\t-s\tprint summary data only (suitable for cron report);\n", X "\t-d\tdetail report;\n", X "\t-m\tdisk layout mappings\n", X "\t-M\tdisk layout mappings (Physical name on right)\n", X "\t-t\ttime format; valid values are 12 and 24\n", X "\t-T\ttime format; requires string argument as follows\n", X "\n", X "Time formats for the -T option follow arguments for strftime(3c). See\n", X "your man pages for details. Some common arguments are:\n\n", X " %%a Abbreviated weekday name %%I Hour as a number [01,12]\n", X " %%A Full weekday name %%m Month as a number [01,12]\n", X " %%b Abbreviated month name %%M Minute as a number [00,59]\n", X " %%B Full month name %%p Local AM or PM\n", X " %%C The century number [00,99] %%T The time (%%H:%%M:%%S)\n", X " %%d Numeric day of month [01,31] %%Y 4 digit year (e.g., 1997)\n", X " %%e Numeric day of month [1,31] %%C 2 digit year (e.g., 97)\n", X " %%H Hour as a number [00,23] %%Z Time zone name\n", X 0 X}; X X#ifndef TRUE X#define TRUE (1) X#define FALSE (0) X#endif X X#define MAXLINE 80 X#define MAXQUERY 2048 X#define FLAG_PCT 80 X Xshort summary = TRUE; Xshort maponly = FALSE; Xshort help = FALSE; Xshort clockval = 24; Xshort namert = FALSE; X Xchar *stmt_str; Xchar *time_fmt = "%A %d-%b-%Y @ %H:%M:%S"; SHAR_EOF # ============= README ============== echo "x - extracting README (Text)" sed 's/^X//' << 'SHAR_EOF' > README && Xdm Version 0.01a X Xdm - DiskMonitor is copyright 1996, 1997 by David Coburn. Permission X is granted to freely distribute this product provided all copyright X information is included intact. X Xdm is written for use with Informix OnLine Dynamic Server (ODS) version X7.2. It has not been tested with any versions prior to this, Xalthough it should work with any version 6.00 and above. X Xdm was written, compiled, and tested with the default C compiler tools Xfor HPUX 10.20. THIS IS NOT AN ANSI COMPILER; USER ASSUMES ANY AND ALL XPORTING WILL BE THEIR RESPONSIBILITY. If somebody goes through this Xtrouble, I will be happy to include this with future distributions. X XSpecial thanks to Jonathan Leffler for his kind words and overview of the Xcode and several suggestions for enhancements. X XOVERVIEW X Xdm is intended to be a synopsis view of information already available from Xvarious onstat commands. The intent is to provide a "summary" view of this Xdata, rather than provide the user with the details that onstat is so good Xat providing. X XUSAGE X X dm [-h | -s | -d | -m | -M | -t {12|24} | -T] X XWhere: X -h print this help file; X -s print summary data only (suitable for cron report); X -d detail report; X -m disk layout mappings X -M disk layout mappings (Physical name on right) X -t time format; valid values are 12 and 24 X -T time format; requires string argument as follows X XTime formats for the -T option follow arguments for strftime(3c). See Xyour man pages for details. Some common arguments are: X X %a Abbreviated weekday name %I Hour as a number [01,12] X %A Full weekday name %m Month as a number [01,12] X %b Abbreviated month name %M Minute as a number [00,59] X %B Full month name %p Local AM or PM X %C The century number [00,99] %T The time (%H:%M:%S) X %d Numeric day of month [01,31] %Y 4 digit year (e.g., 1997) X %e Numeric day of month [1,31] %C 2 digit year (e.g., 97) X %H Hour as a number [00,23] %Z Time zone name X XSummary Reports X XThis output format of this report is similar to the following: X X$dm -s X D I S K U T I L I Z A T I O N R E P O R T X X Monday 08-Sep-1997 @ 16:31:26 X X SERVER = israel X ONCONFIG = onconfig.prod XINFORMIXSERVER = wvms_prod_shm X INFORMIXDIR = /opt/informix/prod X X ID Space Name Size Free X 1 dss_root 150000 146219 ( 2.52%) X 2 tempdbs 750000 749855 ( 0.02%) X 3 phy_logs 10000 4947 (50.53%) X 4 log_logs 100000 89697 (10.30%) X 5 dm_1 250000 49947 (80.02%)*** X 6 dm_2 250000 49947 (80.02%)*** X 7 dm_3 250000 49947 (80.02%)*** X ... X ... X ... X 52 index5 750000 236450 (68.47%) X 53 index6 750000 217389 (71.01%) X XAfter the date and time stamps, information about the current engine is Xlisted. (dm always uses the current settings for Informix variables.) XFollowing this is the actual data: Space number, name, total size of the Xspace (in pages), amount free (again in pages), and percentage filled. You Xwill notice a flag ("***") following spaces five thru 7. These indicate a Xspace that is more than 80% full. This is configurable in the header dm.h Xby changing the value for FLAG_PCT. X XDetail Reports X XThe output of a detail report will appear similar to the following. X X D I S K U T I L I Z A T I O N R E P O R T X X Monday 08-Sep-1997 @ 16:36:43 X X SERVER = israel X ONCONFIG = onconfig.prod XINFORMIXSERVER = wvms_prod_shm X INFORMIXDIR = /opt/informix/prod X X ID Space Name Chunk Offset Size Free Device X 1 dss_root 1 0 150000 146219 /dev/rdsk/dss_da2c_1 XTotal: 150000 146219 X X ID Space Name Chunk Offset Size Free Device X 2 tempdbs 2 0 50000 49897 /dev/rdsk/dss_da2d_1 X 3 0 50000 49997 /dev/rdsk/dss_da2e_1 X 4 0 50000 49997 /dev/rdsk/dss_da2f_1 X ... X ... X ... X 14 0 50000 49997 /dev/rdsk/dss_da15d_1 X 15 0 50000 49997 /dev/rdsk/dss_da15e_1 X 16 0 50000 49997 /dev/rdsk/dss_da15f_1 XTotal: 750000 749855 X X ID Space Name Chunk Offset Size Free Device X ... X ... X ... X ID Space Name Chunk Offset Size Free Device X 52 index5 75 0 750000 236450 /dev/rdsk/dss_da2d_2 XTotal: 750000 236450 X X ID Space Name Chunk Offset Size Free Device X 53 index6 76 0 750000 217389 /dev/rdsk/dss_da14f_2 XTotal: 750000 217389 X XNote that now we again have data by dbspace, but with chunk information Xas well. X XDisk Maps X XThe -m and -M options produce disk maps by logical device, showing chunk Xand dbspace information. This data is useful in laying out disks in an Xorderly fashion. There are two options. The first, -m, places the space Xname on the left. The second places it on the right, if you find that more Xreadable. (Space names could be longer than the space allowed; on the Xright they are more readable.) X XExample output is shown below: X XSpace Name Chk Dbs Name Start End Free X X/dev/rdsk/dss_da14c_1 9 2 tempdbs 0 49999 49997 X 18 4 log_logs 50000 149999 89697 X 73 50 index3 150000 899999 331797 X X/dev/rdsk/dss_da14d_1 10 2 tempdbs 0 49999 49997 X 22 8 dm_4 50000 299999 49947 X 27 13 child_3 300000 399999 66447 X 69 47 misc_c 400000 449999 49997 X 39 22 ph_7 600000 999999 137447 X ... X ... X ... X X/dev/rdsk/dss_da3f_1 8 2 tempdbs 0 49999 49997 X 21 7 dm_3 50000 299999 49947 X 26 12 child_2 300000 399999 66447 X 68 47 misc_c 400000 449999 49997 X 38 21 ph_6 600000 999999 137447 X XBUGS X X There are currently no known bugs with dm. X XCOMMENTS X X Please forward comments to coburn@scn.org. SHAR_EOF exit 0