From 25f0e9f4f09c7d161fbc1e3483501a9f3e7e5b3f Mon Sep 17 00:00:00 2001 From: Ton Voon Date: Wed, 2 Jul 2008 20:00:08 +0000 Subject: Change pst3 again, this time to remove use of kvm which is not available in Solaris 10 non-global zones. Uses /proc, which is not available in older versions of Solaris. git-svn-id: https://nagiosplug.svn.sourceforge.net/svnroot/nagiosplug/nagiosplug/trunk@2016 f882894a-f735-0410-b71e-b25c423dba1c diff --git a/plugins-root/Makefile.am b/plugins-root/Makefile.am index bca3ceb..107d993 100644 --- a/plugins-root/Makefile.am +++ b/plugins-root/Makefile.am @@ -71,7 +71,6 @@ check_icmp_LDADD = @LTLIBINTL@ $(NETLIBS) $(SOCKETLIBS) # -m64 needed at compiler and linker phase pst3_CFLAGS = @PST3CFLAGS@ pst3_LDFLAGS = @PST3CFLAGS@ -pst3_LDADD = -lkvm check_dhcp_DEPENDENCIES = check_dhcp.c $(NETOBJS) $(DEPLIBS) check_icmp_DEPENDENCIES = check_icmp.c $(NETOBJS) diff --git a/plugins-root/pst3.c b/plugins-root/pst3.c index 641a9b8..3954ec5 100644 --- a/plugins-root/pst3.c +++ b/plugins-root/pst3.c @@ -12,10 +12,19 @@ * 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 +* This executable works by reading process address structures, so needs * to be executed as root * * Originally written by R.W.Ingraham +* Rewritten by Duncan Ferguson (Altinity Ltd, June 2008) +* The rewrite was necessary as /dev/kmem is not available within +* non-global zones on Solaris 10 +* +* Details for rewrite came from +* source of /usr/ucb/ps on Solaris: +* http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/ucbcmd/ps/ps.c#argvoff +* usenet group posting +* http://groups.google.com/group/comp.unix.solaris/tree/browse_frm/month/2001-09/bfa40c08bac819a2?rnum=141&_done=%2Fgroup%2Fcomp.unix.solaris%2Fbrowse_frm%2Fmonth%2F2001-09%3F * * 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 @@ -32,185 +41,216 @@ * *****************************************************************************/ -#define _KMEMUSER 1 - -#include -#include -#include -#include -#include -#include -#include #include #include -#include -#include -#include -#include #include #include - - -/* - * Constants - */ - -#define PROC_DIR "/proc" -#define MAX_PATH 1024 -#define OK 0 -#define FAIL NULL - +#include +#include +#include +#include /* - * Structures + * Constants */ +#define PROC_DIR "/proc" +#define ARGS 30 /* - * Globals + * Globals */ static char * szProg; -static kvm_t * kd; -static struct proc * pProc; -static struct user * pUser; -static char ** myArgv; - /* - * Prototypes + * Prototypes */ - -static void output_info(struct proc *proc_kvm,char **proc_argv); -static void HandleProc(struct proc *proc); +void usage(); /*----------------------------------------------------------------------------*/ 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) - szProg++; - else - szProg = argv[0]; - - /* Make sure that our euid is root */ - if (geteuid() != 0) - { - fprintf(stderr, "%s: This program can only be run by the root user!\n", szProg); - exit(1); - } - - /* Get a handle to the running kernel image */ - if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, argv[0])) == NULL) - { - fprintf(stderr, "%s: Failed to open kernel memory: %s\n", szProg, strerror(errno)); - exit(2); - } - - /* 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 */ - kvm_close(kd); - - return retcode; + DIR *procdir; + struct dirent *proc; + char ps_name[ARGS]; + char as_name[ARGS]; + psinfo_t psinfo; + + /* Set our program name global */ + if ((szProg = strrchr(argv[0], '/')) != NULL) + szProg++; + else + szProg = argv[0]; + + /* if given any parameters, print out help */ + if(argc > 1) { + (void)usage(); + exit(1); + } + + /* Make sure that our euid is root */ + if (geteuid() != 0) + { + fprintf(stderr, "%s: This program can only be run by the root user!\n", szProg); + exit(1); + } + + if ((procdir = opendir(PROC_DIR)) == NULL) { + fprintf(stderr, "%s: cannot open PROC directory %s\n", szProg, PROC_DIR); + exit(1); + } + + /* 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 = readdir(procdir))) { + int ps_fd; + int as_fd; + off_t argoff; + int i; + char *args; + char *procname; + char *ptr; + int argslen; + uintptr_t args_addr;; + uintptr_t *args_vecs;; + int args_count; + + if(proc->d_name[0] == '.') + continue; + + sprintf(ps_name,"%s/%s/%s",PROC_DIR,proc->d_name,"psinfo"); + sprintf(as_name,"%s/%s/%s",PROC_DIR,proc->d_name,"as"); +try_again: + if((ps_fd = open(ps_name, O_RDONLY)) == -1) + continue; + + if((as_fd = open(as_name, O_RDONLY)) == -1) + continue; + + if(read(ps_fd, &psinfo, sizeof(psinfo)) != sizeof(psinfo)) { + int err = errno; + close(ps_fd); + close(as_fd); + if(err == EAGAIN) goto try_again; + if(err != ENOENT) + fprintf(stderr, "%s: read() on %s: %s\n", szProg, + ps_name, strerror(err)); + continue; + } + close(ps_fd); + + /* system process, ignore since the previous version did */ + if( + psinfo.pr_nlwp == 0 || + strcmp(psinfo.pr_lwp.pr_clname, "SYS") == 0 + ) { + continue; + } + + /* get the procname to match previous versions */ + procname = strdup(psinfo.pr_psargs); + if((ptr = strchr(procname, ' ')) != NULL) + *ptr = '\0'; + if((ptr = strrchr(procname, '/')) != NULL) + ptr++; + else + ptr = procname; + + /* + * print out what we currently know + */ + printf("%c %5d %5d %5d %6lu %6lu %4.1f %s ", + psinfo.pr_lwp.pr_sname, + psinfo.pr_euid, + psinfo.pr_pid, + psinfo.pr_ppid, + psinfo.pr_size, + psinfo.pr_rssize, + ((float)(psinfo.pr_pctcpu) / 0x8000 * 100.0), + ptr + ); + free(procname); + + /* + * and now for the command line stuff + */ + + args_addr = psinfo.pr_argv; + args_count = psinfo.pr_argc; + args_vecs = malloc(args_count * sizeof(uintptr_t)); + + if(psinfo.pr_dmodel == PR_MODEL_NATIVE) { + /* this process matches target process */ + pread(as_fd,args_vecs, args_count * sizeof(uintptr_t), + args_addr); + } else { + /* this process is 64bit, target process is 32 bit*/ + caddr32_t *args_vecs32 = (caddr32_t *)args_vecs; + pread(as_fd,args_vecs32,args_count * sizeof(caddr32_t), + args_addr); + for (i=args_count-1;i>=0;--i) + args_vecs[i]=args_vecs32[i]; + } + + /* + * now read in the args - if what we read in fills buffer + * resize buffer and reread that bit again + */ + argslen=ARGS; + args=malloc(argslen+1); + for(i=0;ip_pidp, (char *) &pid, sizeof pid) == -1) { - perror("kvm_read error"); - exit(2); - } - proc->p_pidp = &pid; - user = kvm_getu(kd, proc); - - if(kvm_getcmd(kd, proc, user, &proc_argv, NULL) == -1) { - return; - } - - if(proc_argv == NULL) { - return; - } - - output_info(proc, proc_argv); - free(proc_argv); +void usage() { + printf("%s: Help output\n\n", szProg); + printf("If this program is given any arguments, this help is displayed.\n"); + printf("This command is used to print out the full command line for all\n"); + printf("running processes because /usr/bin/ps is limited to 80 chars and\n"); + printf("/usr/ucb/ps can merge columns together.\n\n"); + printf("Columns are:\n"); + printf("\tS - State of process - see 'ps' man page\n"); + printf("\tUID - UID of the process owner\n"); + printf("\tPID - PID of the process\n"); + printf("\tPPID - PID of the parent process\n"); + printf("\tVSZ - Virtual memory usage (kilobytes)\n"); + printf("\tRSS - Real memory usage (kilobytes)\n"); + printf("\t%%CPU - CPU usage\n"); + printf("\tCOMMAND - Command being run\n"); + printf("\tARGS - Full command line with arguements\n"); + return; } - -static void output_info(struct proc *proc_kvm, char **proc_argv) -{ - char procpath[MAX_PATH]; - psinfo_t procinfo; - int fd, len; - char *procname; - int i; - - sprintf(procpath, "/proc/%d/psinfo", proc_kvm->p_pidp->pid_id); - - if ((fd = open(procpath, O_RDONLY)) >= 0) - { - if ((len = read(fd, &procinfo, sizeof(procinfo))) != sizeof(procinfo)) - { - fprintf(stderr,"%s: Read error of psinfo structure (%d)\n", procpath, len); - exit(2); - } - close(fd); - } - - 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"); -} - -- cgit v0.10-9-g596f