From: HENRY::IN%"bruceb%telesoft.UUCP%sdcsvax.ucsd.edu%sri-kl.ARPA%relay.cs.net@rca.com" 18-MAR-1987 09:40 To: sri-kl.arpa!info-vax@sdcsvax.ucsd.edu Subj: An enhanced SHOW SYSTEM utility It occurred to me the other day that I have been using this neat utility for viewing processes (similar to SHOW SYSTEM), and that there are others who may like this program. Enclosed you will find a DCL archive which contains two files: bigsis.c bigsis.man The .c file should be compiled with DEC C V2.0 or greater, on VMS V4.2 or greater. I wrote this to run on that configuration, and since I no longer have access to a C compiler, I can't tell you if it compiles on anything else. However, if you get it to compile, it will tell you all sorts of useful information about the jobs currently running on your system (not cluster). It was written as a quick hak, and I never got around to putting in all the features I wanted (like ability to work on 80 column displays, selective process info, etc). It has one bug. If you run it on a non-clustered environment, it won't display the sub process parent information correctly. This can be fixed easily as it is in a small routine at the bottom of the code. Other than that, there are no known bugs. Read the man page to get an idea of what it will tell you. I'd be interested in hearing from you if you like the program!! I've got a bunch of other nifty utilities I wrote, which I may post at a later date. I'd like to see how this one goes over first, though. Oh yes, the means of collecting the files into one 'archive' is my own design. I didn't have any of the shar programs running around, so I wrote my own. Hope it works okay. Comments, suggestions, flames, etc., can be sent to me. bruce bergman $ !------------------------------ cut here ------------------------------ $ set noon $ on control then goto YOU_QUIT $ on error then goto I_QUIT $ file = "BIGSIS.C" $ chksum = 309885657 $ pass_fail = "FAILED" $ write sys$output "Extracting ""''file'"" - original checksum was: ''chksum'" $ create/nolog 'file' $ deck/dollars="EoF@11:34:11.17" /************************************************************************ * * * B I G S I S * * * ************************************************************************ ** PURPOSE -------------------------------------------------------------- Show VMS system/process information concisely. ** PACKAGE -------------------------------------------------------------- VAX/VMS BIGSIS ** HISTORY -------------------------------------------------------------- 1.0 01-Jun-85 Creation (Bruce A. Bergman) 1.1 27-Jun-85 Added ability to see process children and parent id's. (Bruce A. Bergman) 1.1a 10-Sep-85 Suspended processes were hanging the program so added code to display them and continue. (Bruce A. Bergman) ** NON-DISCLOSURE ------------------------------------------------------- This program can be copied or modified, not for profit, as long as this disclosure notice and author/edit information remain with the source code at all times. No use of this software or its associated source is permitted for commercial or personal monetary gain (profit) in any form. The author of this software is not responsible for any repercussions that may arise from use of this software. Bugs and/or suggestions may be sent to the author at: Bruce A. Bergman 460 East Washington Avenue, #109 Escondido, CA. 92025-2958 (619) 489-8195 fido: 103/203 uucp: ...sdcsvax!telesoft!bruceb ** CODE -------------------------------------------------------------- */ #include #include #include #include /* | These weren't identified in the sys$library:jpidef.h | files so they MUST be included. */ globalvalue JPI$_CLINAME; globalvalue JPI$_MODE; globalvalue JPI$K_OTHER; globalvalue JPI$K_INTERACTIVE; globalvalue JPI$K_BATCH; globalvalue JPI$K_NETWORK; globalvalue JPI$_MASTER_PID; globalvalue JPI$_MAXDETACH; globalvalue JPI$_MAXJOBS; #include #include main(argc, argv) /* show vms system/process information */ int argc; char *argv[]; { struct _itmlst { unsigned short int buf_len; unsigned short int item_code; unsigned int buf_addr; unsigned int ret_len; } item_list[20]; char username[13], procname[16], terminal[9], cliname[128], states[6], subs[6], cputime[10], imag_name[132], image_name[50]; float fcputim; unsigned int ret_flag, pid, cur_pid, mem, pri, prib, cputim, susp_flag, ppgcnt, sts, state, mode, master_pid, jobprccnt, owner, all_p, net_w, iosb; unsigned short int maxjobs; /* | Set our options to none (until we evauluate | them and determine that some are wanted. */ all_p = net_w = FALSE; /* | Check arguments for all possible info (a) | or just network info (n). If no options | just display the normal stuff. 'ALL' assumes | user wants network info also. */ if (argc > 1 && argv[1][0] == '-') { if (argv[1][1] == 'a' || argv[1][1] == 'A') all_p = net_w = TRUE; if (argv[1][1] == 'n' || argv[1][1] == 'N') net_w = TRUE; } /* | Set up item list with the information | we want. This includes: | Username | Process name | Process identification | Amount of memory used | Priority (current) | Priority (base) | CPU time | Page count for image | Virtual terminal id | Mode | CLI name | Job status | Job state | Process parent's PID | Sub-process count (current) | Sub-process count (max) | PID of owner of job | Image name */ item_list[0].buf_len = 12; item_list[0].item_code = JPI$_USERNAME; item_list[0].buf_addr = username; item_list[0].ret_len = 0; item_list[1].buf_len = 15; item_list[1].item_code = JPI$_PRCNAM; item_list[1].buf_addr = procname; item_list[1].ret_len = 0; item_list[2].buf_len = 4; item_list[2].item_code = JPI$_PID; item_list[2].buf_addr = &pid; item_list[2].ret_len = 0; item_list[3].buf_len = 4; item_list[3].item_code = JPI$_MEM; item_list[3].buf_addr = &mem; item_list[3].ret_len = 0; item_list[4].buf_len = 4; item_list[4].item_code = JPI$_PRI; item_list[4].buf_addr = &pri; item_list[4].ret_len = 0; item_list[5].buf_len = 4; item_list[5].item_code = JPI$_PRIB; item_list[5].buf_addr = &prib; item_list[5].ret_len = 0; item_list[6].buf_len = 4; item_list[6].item_code = JPI$_CPUTIM; item_list[6].buf_addr = &cputim; item_list[6].ret_len = 0; item_list[7].buf_len = 4; item_list[7].item_code = JPI$_PPGCNT; item_list[7].buf_addr = &ppgcnt; item_list[7].ret_len = 0; item_list[8].buf_len = 8; item_list[8].item_code = JPI$_TERMINAL; item_list[8].buf_addr = terminal; item_list[8].ret_len = 0; item_list[9].buf_len = 4; item_list[9].item_code = JPI$_MODE; item_list[9].buf_addr = &mode; item_list[9].ret_len = 0; item_list[10].buf_len = 39; item_list[10].item_code = JPI$_CLINAME; item_list[10].buf_addr = cliname; item_list[101].ret_len = 0; item_list[11].buf_len = 4; item_list[11].item_code = JPI$_STS; item_list[11].buf_addr = &sts; item_list[11].ret_len = 0; item_list[12].buf_len = 4; item_list[12].item_code = JPI$_STATE; item_list[12].buf_addr = &state; item_list[12].ret_len = 0; item_list[13].buf_len = 4; item_list[13].item_code = JPI$_MASTER_PID; item_list[13].buf_addr = &master_pid; item_list[13].ret_len = 0; item_list[14].buf_len = 4; item_list[14].item_code = JPI$_JOBPRCCNT; item_list[14].buf_addr = &jobprccnt; item_list[14].ret_len = 0; item_list[15].buf_len = 2; item_list[15].item_code = JPI$_MAXJOBS; item_list[15].buf_addr = &maxjobs; item_list[15].ret_len = 0; item_list[16].buf_len = 4; item_list[16].item_code = JPI$_OWNER; item_list[16].buf_addr = &owner; item_list[16].ret_len = 0; item_list[17].buf_len = 132; item_list[17].item_code = JPI$_IMAGNAME; item_list[17].buf_addr = imag_name; item_list[17].ret_len = 0; /* | Signal no more information required. */ item_list[18].buf_len = 0; /* | Print formatted headers. */ printf("%-8s %-12s %-15s %-8s ", "PID", "Username", "Process name", "Terminal"); printf("%-5s %-7s %-9s %-5s %-5s ", "Sub's", "Pri's", "CPU time", "State", "Size"); printf("%-11s\n", "Image name"); printf("-------- ------------ --------------- -------- "); printf("----- ------- --------- ----- ----- "); printf("-------------------------------------------------\n"); /* | We want information from all processes. */ cur_pid = -1; while (1) { /* | Set a flag saying we this process is | NOT suspended (we handle this special). */ susp_flag = FALSE; /* | Call $GETJPI to obtain the actual info. */ ret_flag = sys$getjpi(32, &cur_pid, 0, &item_list, &iosb, 0, 0); /* | If $GETJPI says this process is suspended, mark | it as such and pretend like it is okay - we will | deal with it later. */ if (ret_flag == SS$_SUSPENDED) { ret_flag |= SS$_NORMAL; susp_flag = TRUE; } /* | If $GETJPI says everything was 'queued' okay, | let's wait until VMS says it has given us all | the info we requested (we're being nice | to VMS since we could have not waited). */ if (ret_flag & SS$_NORMAL) { if (susp_flag == FALSE) { ret_flag = sys$waitfr(32); if (!ret_flag & SS$_NORMAL) sys$exit(ret_flag); } /* | Everything is okay, so now check and see | if this job is at a terminal. */ if (terminal[0] == 0) /* | If this job is a batch job, check | its pid with its parent pid. If they | match, then this is a spawned job. | If they don't match, it must be batch. */ if (mode & PCB$V_BATCH) if (master_pid == pid) strcpy(terminal, "*BATCH*"); else strcpy(terminal, "Spawned"); else /* | This job is interactive (not batch). | If this job is a network server | and the user wants to know about | networks, say so. If we aren't | network then if the user wants to | know about all jobs, then announce | system jobs too. */ if (net_w && mode & PCB$V_NETWRK) strcpy(terminal, "Network"); else if (all_p) strcpy(terminal, "[System]"); else continue; /* | If this job has no children, set a value indicating | how many children are possible out of the max allowed. */ if (master_pid == pid) if (jobprccnt > 0) sprintf(subs, "%2d/%-2d", jobprccnt, maxjobs); else strcpy(subs, " "); else /* | If this job has children, place the last 4 characters | of the parent pid into the process count area instead | of indicating how many the job could have. This makes | it easier to track down children processes. */ set_sub(subs, owner); /* | Set process state. */ set_state(states, state); /* | If user is not running an image, then | check to see if it has a CLI, if not, | it must be a dead system process so place | defunct into image slot. | Otherwise display the CLI name when appropriate. */ if (imag_name[0] == 0) if (cliname[0] == 0) sprintf(image_name, ""); else sprintf(image_name, "(%s)", cliname); else /* | Now we see if the job was suspended. | If it was, make it obvious to all and | change state to relfect type of MWAIT. | Otherwise just copy the image name into | the slot (truncating and parsing as necessary). */ if (susp_flag == TRUE) { strcpy(states, "SUSP"); sprintf(image_name, "[Out To Lunch]"); } else set_name(image_name, imag_name); /* | Change CPU time to float so we can display | it as a decimal value rather than time; its | easier to see change that way (who says?!). */ fcputim = cputim; /* | If no username, just defunct it also. */ if (username[0] == 0) strcpy(username, ""); /* | At long last, time to print the info. | Format everything so my sense of taste is not | offended and make sure all process id's are in | hexadecimal and hope the CPU time never gets HUGE. */ printf("%-8x %-12s %-15s %-8s ", pid, username, procname, terminal); printf("%-5s %3d/%-3d %9.2f %-5s %-5d ", subs, pri, prib, fcputim/100, states, ppgcnt); printf("%-49s\n", image_name); /* | Go get another process until done. */ continue; } /* | Hooray we're done! Let's clean up and get outta here. */ if (ret_flag == SS$_NOMOREPROC) break; /* | The user has no oper priv so we must just | skip over this process like a good little program. */ if (ret_flag == SS$_NOPRIV) continue; /* | Some unknown nasty has interrupted our | session (how rude!). Let VMS handle it. */ sys$exit(ret_flag); } } set_state(destin, state) /* turn process state code into readable form */ char *destin; unsigned int state; { /* | Assume we don't know what state we are in. */ strcpy(destin, "?????"); /* Start evaluating states until we find a match. | Note: we could have done this with a switch() had | these not been gloabalvalues. We're really better | off this way and we don't loose any functionality. */ if (state == SCH$C_CEF) strcpy(destin, "CEF"); if (state == SCH$C_COM) strcpy(destin, "COM"); if (state == SCH$C_COMO) strcpy(destin, "COMO"); if (state == SCH$C_CUR) strcpy(destin, "CUR"); if (state == SCH$C_COLPG) strcpy(destin, "COLPG"); if (state == SCH$C_FPG) strcpy(destin, "FPG"); if (state == SCH$C_HIB) strcpy(destin, "HIB"); if (state == SCH$C_HIBO) strcpy(destin, "HIBO"); if (state == SCH$C_LEF) strcpy(destin, "LEF"); if (state == SCH$C_LEFO) strcpy(destin, "LEFO"); if (state == SCH$C_MWAIT) strcpy(destin, "MWAIT"); if (state == SCH$C_PFW) strcpy(destin, "PFW"); if (state == SCH$C_SUSP) strcpy(destin, "SUSP"); if (state == SCH$C_SUSPO) strcpy(destin, "SUSPO"); /* | Return pointer to state */ return (destin); } set_sub(destin, pid) /* evaulate and set parent process id */ char *destin; unsigned int pid; { char temp[9]; int i; /* | Print the parent process id into | a holding region and put 'P' at | first char position so user knows that | the number following is a PARENT! */ sprintf(temp, "%-8x", pid); *destin = 'P'; /* | Copy the last 4 characters in the parent pid | into destination. If pid was 0, just blank | out (occurs in some defunct system processes). */ for (i = 1; i <= 4; i++) *(destin+i) = temp[i+3]; *(destin+i) = '\0'; if (pid == 0) *destin = '\0'; /* | Return pointer to process string. */ return (destin); } set_name(destin, source) /* parse and truncate image name */ char *destin, *source; { int pos; /* | Search for first occurence of a directory spec | searching from the end backwards. This will | get rid of long (like in VMS 4.x) disk pathnames. | Note: look to "SHOW DEVICE/FILES/NOSYSTEM" to see what | is on which disk. */ pos = strrchr(source, '['); /* | Only copy the next 49 characters (so won't run | off end of 132 col screen). */ strncpy(destin, pos, 49); /* | Return pointer to the image name. */ return (destin); } EoF@11:34:11.17 $ checksum 'file' $ if 'chksum' .eq. 'checksum$checksum' then pass_fail = "PASSED" $ write sys$output " Computed checksum is: ''checksum$checksum' (''pass_fail')" $ file = "BIGSIS.MAN" $ chksum = 979708107 $ pass_fail = "FAILED" $ write sys$output "Extracting ""''file'"" - original checksum was: ''chksum'" $ create/nolog 'file' $ deck/dollars="EoF@11:35:48.99" BIGSIS(1) VAX/VMS Utilities BIGSIS(1) NAME bigsis - display system and process information SYNOPSIS bigsis [ -an ] DESCRIPTION Bigsis displays VAX/VMS system and process information. The information taken is a 'snapshot' of the system at the moment the request was given. The -a option asks for information about all processes, including defunct ones. The -n option asks that network processes be included as part of the display (they are not normally). Specifying the -a option includes the -n option automatically. Bigsis is formatted for a 132 column screen. The information returned to the user includes: PID The process id of the current process. The PID is in hexadecimal notation. USERNAME The username is the actual login name that was used. It will never change, whereas the process name CAN change during the process' session. The username may appear as "" if the process is a defunct system process (e.g. NULL or SWAPPER). NAME The process name can be changed by the user, but initially is identical to the username unless more than one process already share the same username. TERMINAL The terminal name (a virtual keyboard id under VMS V4.x) will appear if the process is an active job connected to a physical terminal. If the job is a _b_a_t_c_h job, the special identifier "*BATCH*" will be shown in place of the terminal name. If the process belongs to the system (created by the system), "[SYSTEM]" appears in this column. If the process is _s_p_a_w_n_e_d from another process, "Spawned" is displayed and the user is shown the parent process in the adjecent column (see SUBS for more detail). SUBS If a job has been spawned by this process, a count appears that shows how many processes have been spawned and how many processes CAN be spawned. The two pieces of information are separated by a slash (/). If the maximum number of possible sub-processes is zero, then unlimited processes may be spawned. Note that this information appears for the _p_a_r_e_n_t of the spawned process only. If the process is a _c_h_i_l_d of another process, then the special identifier "Pxxxx" is displayed in this column, where xxxx refers to the last four (4) characters of the parent process. The characters are also hexadecimal. PRIORITY The priority of the current process is shown in this column, in the form xx/xx. The first xx refers to the process' CURRENT priority. The second xx refers to the - 1 - BIGSIS(1) VAX/VMS Utilities BIGSIS(1) process' BASE priority. CPUTIME The amount of CPU time the process has accumulated is displayed as an integer rather than an actual 'time' value. The decimal place separates seconds from hundredth's of seconds. Later, when cows fly, the value may be converted to an actual time. STATE The current state that the process was in at the moment the 'snapshot' was taken is displayed as an abbreviation. Refer to the VAX/VMS System Routines manual for a complete description of each state. The special state, "SUSP" appears when a process has been suspended for some reason. If this is the case, the image name will appear as "[Out To Lunch]" to bring attention to the process. SIZE The size (in pages) of the image that the current process is executing is displayed. This is an approximate value and should not be construed as an accurate reflection of the image size. IMAGE The image name is displayed for the current process, if it is executing an image. Otherwise, if the process is not suspended (see the STATE column for more detail), and if it is not a defunct system process, the CLI (Command Language Interpreter) for the current process is displayed enclosed in parenthesis. If the process is a defunct system process, "" will appear in this column. The image name, if displayed, is parsed and truncated to show only the _l_a_s_t directory specification and the next 49 characters (e.g. [SYSEXE]BIGSIS.EXE;1 rather than DUA0:[SYSEXE]BIGSIS.EXE;1). BUGS Bigsis requires that the user have appropriate privileges to obtain information about other processes. If the user does not have these privileges, only the user's process information is displayed. The CPU time value is really not perfect, but it is easier to see a change in the value in this form. I hope the process time never exceeds the what can be stored as a 32 bit longword! Finally, the parsing of the image name to fit on the screen can be deceptive, in that an image from one directory can be on several disks and never appear different from the bigsis display. I suggest using "SHOW DEVICE/FILES/NOSYSTEM" for process-disk information. - 2 - EoF@11:35:48.99 $ checksum 'file' $ if 'chksum' .eq. 'checksum$checksum' then pass_fail = "PASSED" $ write sys$output " Computed checksum is: ''checksum$checksum' (''pass_fail')" $ write sys$output "Finished." $ exit $YOU_QUIT: $ write sys$output "Aborting upon request of user..." $ exit $I_QUIT: $ write sys$output "Encountered a fatal condition - aborting..." $ exit $ !------------------------------ cut here ------------------------------