From 5c3d4aea27de408cb7b04f5aab83558efbf841f4 Mon Sep 17 00:00:00 2001 From: Ton Voon Date: Mon, 2 Jun 2008 16:22:35 +0000 Subject: Optimised pst3 for systems with large number of processes (Duncan Ferguson) git-svn-id: https://nagiosplug.svn.sourceforge.net/svnroot/nagiosplug/nagiosplug/trunk@2010 f882894a-f735-0410-b71e-b25c423dba1c diff --git a/NEWS b/NEWS index 67bbac2..439a850 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,7 @@ This file documents the major additions and syntax changes between releases. 1.4.?? ??th ??? 200? Fix Debian bug #460097: check_http --max-age broken (Hilko Bengen) + Optimised pst3 for systems with large number of processes (Duncan Ferguson) Updated Nagios::Plugin to 0.27 1.4.12 27th May 2008 diff --git a/plugins-root/pst3.c b/plugins-root/pst3.c index 5b0e9d7..ee1d180 100644 --- a/plugins-root/pst3.c +++ b/plugins-root/pst3.c @@ -1,16 +1,36 @@ -/* pst3.c +/***************************************************************************** +* +* pst3 +* +* License: GPL +* Copyright (c) 2008 Nagios Plugin Development Team +* +* Description: +* +* This file contains the pst3 executable. This is a replacement ps command +* for Solaris to get output which provides a long argument listing, which +* is not possible with the standard ps command (due to truncation). /usr/ucb/ps +* also has issues where some fields run into each other. +* +* This executable works by reading the kernel memory structures, so needs +* to be executed as root * -* Third version to get process arg info; this time by using -* a combination of reading the /proc//psinfo structures -* and reading the complete arg vector from kernel memory structures. -* -* Developed and tested under Solaris 5.8 (both 32 and 64 bit modes). -* -* NOTE: This program must be setuid-root (or run by root) to work! -* -* Written: 2005-04-28 R.W.Ingraham -*/ - +* Originally written by R.W.Ingraham +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* +*****************************************************************************/ #define _KMEMUSER 1 @@ -37,6 +57,8 @@ #define PROC_DIR "/proc" #define MAX_PATH 1024 +#define OK 0 +#define FAIL NULL /* @@ -59,12 +81,9 @@ static char ** myArgv; * Prototypes */ -static int HandleFile (struct dirent *pDent); -static int HandlePsInfo (char *szPath, psinfo_t *pPsInfo); -static int GetArgVectors (pid_t pid); -static void ShowArgVectors (void); -static void ReleaseArgVectors(); - +static int output_info(struct proc *proc_kvm, psinfo_t procinfo,char **proc_argv); +static psinfo_t get_procinfo(struct proc *proc); +static int HandleProc(struct proc *proc); /*----------------------------------------------------------------------------*/ @@ -73,7 +92,8 @@ int main (int argc, char **argv) DIR *pDir; struct dirent *pDent; int retcode = 0; - + struct proc *proc; + struct pid pid; /* Set our program name global */ if ((szProg = strrchr(argv[0], '/')) != NULL) @@ -95,26 +115,28 @@ int main (int argc, char **argv) exit(2); } - /* Open the /proc directory */ - if ((pDir = opendir(PROC_DIR)) != NULL) - { - /* Display column headings */ - printf("S UID PID PPID VSZ RSS %%CPU COMMAND ARGS\n"); - - /* Zip through all of the process entries */ - while ((pDent = readdir(pDir)) != NULL) - { - /* Handle each pid sub-directory */ - HandleFile(pDent); - } - - /* Close the directory */ - closedir(pDir); - } - else /* ERROR: Failure to open PROC_DIR */ - { - fprintf(stderr, "%s: Failed to open \"%s\": %s\n", szProg, PROC_DIR, strerror(errno)); - retcode = 3; + /* reset to first proc in list */ + if(kvm_setproc(kd) == -1) { + perror("kvm_setproc"); + exit(2); + } + + /* Display column headings */ + printf("%c %5s %5s %5s %6s %6s %4s %s %s\n", + 'S', + "UID", + "PID", + "PPID", + "VSZ", + "RSS", + "%CPU", + "COMMAND", + "ARGS" + ); + + /* Zip through all of the process entries */ + while((proc = kvm_nextproc(kd)) != 0) { + HandleProc(proc); } /* Close the handle to the running kernel image */ @@ -125,129 +147,76 @@ int main (int argc, char **argv) /*----------------------------------------------------------------------------*/ -static int HandleFile (struct dirent *pDent) +static int HandleProc(struct proc *proc) { - char szPath[MAX_PATH]; - psinfo_t sPsInfo; - int fd, len; - int rc = 0; - - /* Skip files beginning with a "." */ - if (pDent->d_name[0] == '.') - return 0; - - /* Cosntruct the path to the psinfo file */ - len = sprintf(szPath, "%s/%s/psinfo", PROC_DIR, pDent->d_name); - - /* Open the psinfo file for this pid and print out its arg vectors */ - if ((fd = open(szPath, O_RDONLY)) >= 0) - { - /* Read the psinfo struct */ - if ((len = read(fd, &sPsInfo, sizeof(sPsInfo))) != sizeof(sPsInfo)) - { - rc = errno; - fprintf(stderr, "%s: Read error of psinfo structure (%d)\n", szPath, len); - return rc; - } - - /* Close the psinfo file */ - close(fd); + struct pid pid; + struct user *user; + psinfo_t procinfo; + char **proc_argv = 0; - /* Pass psinfo struct to reporting function */ - HandlePsInfo(szPath, &sPsInfo); - } - else if (errno != ENOENT) - { - rc = errno; - fprintf(stderr, "%s: %s\n", szPath, strerror(errno)); + if(kvm_kread(kd, (unsigned long) proc->p_pidp, (char *) &pid, sizeof pid) == -1) { + perror("kvm_read error"); + exit(2); } + proc->p_pidp = &pid; + user = kvm_getu(kd, proc); - return 0; -} - -/*----------------------------------------------------------------------------*/ - -static int HandlePsInfo (char *szPath, psinfo_t *pPsInfo) -{ - int retcode; - char *thisProg; - - /* Make sure that the process is still there */ - if ((retcode = GetArgVectors(pPsInfo->pr_pid)) == 0) - { - /* We use the program name from the kvm argv[0] instead - * of pr_fname from the psinfo struct because pr_fname - * may be truncated. - * - * Also, strip-off leading path information. - */ - if ((thisProg = strrchr(myArgv[0], '/')) != NULL) - thisProg++; - else - thisProg = myArgv[0]; - - /* Display the ps columns (except for argv) */ - printf("%c %5d %5d %5d %6lu %6lu %4.1f %s ", - pPsInfo->pr_lwp.pr_sname, - (int)(pPsInfo->pr_euid), - (int)(pPsInfo->pr_pid), - (int)(pPsInfo->pr_ppid), - (unsigned long)(pPsInfo->pr_size), - (unsigned long)(pPsInfo->pr_rssize), - ((float)(pPsInfo->pr_pctcpu) / 0x8000 * 100.0), - thisProg); - - /* Display the arg vectors associated with this pid */ - ShowArgVectors(); - - /* Release the arg vector buffer memory */ - ReleaseArgVectors(); + if(kvm_getcmd(kd, proc, user, &proc_argv, NULL) == -1) { + return FAIL; } - return retcode; + procinfo = get_procinfo(proc); + return output_info(proc, procinfo, proc_argv); } -/*----------------------------------------------------------------------------*/ - -static int GetArgVectors (pid_t pid) +static psinfo_t get_procinfo(struct proc *proc) { - int retcode = 1; + char procpath[MAX_PATH]; + psinfo_t procinfo; + int fd, len; + + sprintf(procpath, "/proc/%d/psinfo", proc->p_pidp->pid_id); - /* Get the proc structure for the specified PID */ - if ((pProc = kvm_getproc(kd, pid)) != NULL) + if ((fd = open(procpath, O_RDONLY)) >= 0) { - /* Save a copy of the process' u-area */ - if ((pUser = kvm_getu(kd, pProc)) != NULL) + if ((len = read(fd, &procinfo, sizeof(procinfo))) != sizeof(procinfo)) { - /* Reconstruct the process' argv vector array */ - if (kvm_getcmd(kd, pProc, pUser, &myArgv, NULL) == 0) - { - retcode = 0; - } + fprintf(stderr,"%s: Read error of psingo structure (%d)\n", procpath, len); + exit(2); } + close(fd); } + return procinfo; - return retcode; } -/*----------------------------------------------------------------------------*/ - -static void ShowArgVectors (void) +static int output_info(struct proc *proc_kvm, psinfo_t procinfo, char **proc_argv) { + char *procname; int i; - for (i=0; myArgv[i]; i++) - { - printf(" %s", myArgv[i]); + if((procname = strrchr(proc_argv[0], '/')) != NULL) + procname++; + else + procname = proc_argv[0]; + + printf("%c %5d %5d %5d %6lu %6lu %4.1f %s ", + procinfo.pr_lwp.pr_sname, + (int)(procinfo.pr_euid), + (int)proc_kvm->p_pidp->pid_id, + (int)proc_kvm->p_ppid, + (unsigned long)(procinfo.pr_size), + (unsigned long)(procinfo.pr_rssize), + ((float)(procinfo.pr_pctcpu) / 0x8000 * 100.0), + procname + ); + + for(i=0;proc_argv[i];i++) { + printf(" %s", proc_argv[i]); } - printf("\n"); -} -/*----------------------------------------------------------------------------*/ + printf("\n"); -static void ReleaseArgVectors() -{ - /* NOOP */ + return OK; } -/*----------------------------------------------------------------------------*/ -- cgit v0.10-9-g596f