/***************************************************************************** * * pst3 * * License: GPL * Copyright (c) 2008 Monitoring Plugins 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 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 * 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 . * *****************************************************************************/ #include #include #include #include #include #include #include #include #include /* * Constants */ #define PROC_DIR "/proc" #define ARGS 30 /* * Globals */ static char * szProg; /* * Prototypes */ void usage(); /*----------------------------------------------------------------------------*/ int main (int argc, char **argv) { 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) { close(ps_fd); 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;i