1 /*****************************************************************************
2 *
3 * pst3
4 *
5 * License: GPL
6 * Copyright (c) 2008 Nagios Plugin Development Team
7 *
8 * Description:
9 *
10 * This file contains the pst3 executable. This is a replacement ps command
11 * for Solaris to get output which provides a long argument listing, which
12 * is not possible with the standard ps command (due to truncation). /usr/ucb/ps
13 * also has issues where some fields run into each other.
14 *
15 * This executable works by reading the kernel memory structures, so needs
16 * to be executed as root
17 *
18 * Originally written by R.W.Ingraham
19 *
20 * This program is free software: you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation, either version 3 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program. If not, see <http://www.gnu.org/licenses/>.
32 *
33 *****************************************************************************/
35 #define _KMEMUSER 1
37 #include <kvm.h>
38 #include <sys/param.h>
39 #include <sys/user.h>
40 #include <sys/time.h>
41 #include <sys/proc.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <unistd.h>
47 #include <string.h>
48 #include <procfs.h>
49 #include <fcntl.h>
50 #include <dirent.h>
51 #include <errno.h>
54 /*
55 * Constants
56 */
58 #define PROC_DIR "/proc"
59 #define MAX_PATH 1024
60 #define OK 0
61 #define FAIL NULL
64 /*
65 * Structures
66 */
69 /*
70 * Globals
71 */
73 static char * szProg;
74 static kvm_t * kd;
75 static struct proc * pProc;
76 static struct user * pUser;
77 static char ** myArgv;
80 /*
81 * Prototypes
82 */
84 static void output_info(struct proc *proc_kvm,char **proc_argv);
85 static void HandleProc(struct proc *proc);
87 /*----------------------------------------------------------------------------*/
89 int main (int argc, char **argv)
90 {
91 DIR *pDir;
92 struct dirent *pDent;
93 int retcode = 0;
94 struct proc *proc;
95 struct pid pid;
97 /* Set our program name global */
98 if ((szProg = strrchr(argv[0], '/')) != NULL)
99 szProg++;
100 else
101 szProg = argv[0];
103 /* Make sure that our euid is root */
104 if (geteuid() != 0)
105 {
106 fprintf(stderr, "%s: This program can only be run by the root user!\n", szProg);
107 exit(1);
108 }
110 /* Get a handle to the running kernel image */
111 if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, argv[0])) == NULL)
112 {
113 fprintf(stderr, "%s: Failed to open kernel memory: %s\n", szProg, strerror(errno));
114 exit(2);
115 }
117 /* reset to first proc in list */
118 if(kvm_setproc(kd) == -1) {
119 perror("kvm_setproc");
120 exit(2);
121 }
123 /* Display column headings */
124 printf("%c %5s %5s %5s %6s %6s %4s %s %s\n",
125 'S',
126 "UID",
127 "PID",
128 "PPID",
129 "VSZ",
130 "RSS",
131 "%CPU",
132 "COMMAND",
133 "ARGS"
134 );
136 /* Zip through all of the process entries */
137 while((proc = kvm_nextproc(kd)) != 0) {
138 HandleProc(proc);
139 }
141 /* Close the handle to the running kernel image */
142 kvm_close(kd);
144 return retcode;
145 }
147 /*----------------------------------------------------------------------------*/
149 static void HandleProc(struct proc *proc)
150 {
151 struct pid pid;
152 struct user *user;
153 char **proc_argv = NULL;
155 if(kvm_kread(kd, (unsigned long) proc->p_pidp, (char *) &pid, sizeof pid) == -1) {
156 perror("kvm_read error");
157 exit(2);
158 }
159 proc->p_pidp = &pid;
160 user = kvm_getu(kd, proc);
162 if(kvm_getcmd(kd, proc, user, &proc_argv, NULL) == -1) {
163 return;
164 }
166 if(proc_argv == NULL) {
167 return;
168 }
170 output_info(proc, proc_argv);
171 free(proc_argv);
172 }
174 static void output_info(struct proc *proc_kvm, char **proc_argv)
175 {
176 char procpath[MAX_PATH];
177 psinfo_t procinfo;
178 int fd, len;
179 char *procname;
180 int i;
182 sprintf(procpath, "/proc/%d/psinfo", proc_kvm->p_pidp->pid_id);
184 if ((fd = open(procpath, O_RDONLY)) >= 0)
185 {
186 if ((len = read(fd, &procinfo, sizeof(procinfo))) != sizeof(procinfo))
187 {
188 fprintf(stderr,"%s: Read error of psinfo structure (%d)\n", procpath, len);
189 exit(2);
190 }
191 close(fd);
192 }
194 if((procname = strrchr(proc_argv[0], '/')) != NULL)
195 procname++;
196 else
197 procname = proc_argv[0];
199 printf("%c %5d %5d %5d %6lu %6lu %4.1f %s ",
200 procinfo.pr_lwp.pr_sname,
201 (int)(procinfo.pr_euid),
202 (int)proc_kvm->p_pidp->pid_id,
203 (int)proc_kvm->p_ppid,
204 (unsigned long)(procinfo.pr_size),
205 (unsigned long)(procinfo.pr_rssize),
206 ((float)(procinfo.pr_pctcpu) / 0x8000 * 100.0),
207 procname
208 );
210 for(i=0;proc_argv[i];i++) {
211 printf(" %s", proc_argv[i]);
212 }
214 printf("\n");
215 }