diff options
Diffstat (limited to 'plugins-root/pst3.c')
-rw-r--r-- | plugins-root/pst3.c | 354 |
1 files changed, 197 insertions, 157 deletions
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 @@ | |||
12 | * is not possible with the standard ps command (due to truncation). /usr/ucb/ps | 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. | 13 | * also has issues where some fields run into each other. |
14 | * | 14 | * |
15 | * This executable works by reading the kernel memory structures, so needs | 15 | * This executable works by reading process address structures, so needs |
16 | * to be executed as root | 16 | * to be executed as root |
17 | * | 17 | * |
18 | * Originally written by R.W.Ingraham | 18 | * Originally written by R.W.Ingraham |
19 | * Rewritten by Duncan Ferguson (Altinity Ltd, June 2008) | ||
20 | * The rewrite was necessary as /dev/kmem is not available within | ||
21 | * non-global zones on Solaris 10 | ||
22 | * | ||
23 | * Details for rewrite came from | ||
24 | * source of /usr/ucb/ps on Solaris: | ||
25 | * http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/ucbcmd/ps/ps.c#argvoff | ||
26 | * usenet group posting | ||
27 | * 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 | ||
19 | * | 28 | * |
20 | * This program is free software: you can redistribute it and/or modify | 29 | * 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 | 30 | * it under the terms of the GNU General Public License as published by |
@@ -32,185 +41,216 @@ | |||
32 | * | 41 | * |
33 | *****************************************************************************/ | 42 | *****************************************************************************/ |
34 | 43 | ||
35 | #define _KMEMUSER 1 | ||
36 | |||
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> | 44 | #include <stdio.h> |
45 | #include <stdlib.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> | 46 | #include <dirent.h> |
51 | #include <errno.h> | 47 | #include <errno.h> |
52 | 48 | #include <fcntl.h> | |
53 | 49 | #include <procfs.h> | |
54 | /* | 50 | #include <errno.h> |
55 | * Constants | 51 | #include <sys/types32.h> |
56 | */ | ||
57 | |||
58 | #define PROC_DIR "/proc" | ||
59 | #define MAX_PATH 1024 | ||
60 | #define OK 0 | ||
61 | #define FAIL NULL | ||
62 | |||
63 | 52 | ||
64 | /* | 53 | /* |
65 | * Structures | 54 | * Constants |
66 | */ | 55 | */ |
67 | 56 | ||
57 | #define PROC_DIR "/proc" | ||
58 | #define ARGS 30 | ||
68 | 59 | ||
69 | /* | 60 | /* |
70 | * Globals | 61 | * Globals |
71 | */ | 62 | */ |
72 | 63 | ||
73 | static char * szProg; | 64 | static char * szProg; |
74 | static kvm_t * kd; | ||
75 | static struct proc * pProc; | ||
76 | static struct user * pUser; | ||
77 | static char ** myArgv; | ||
78 | |||
79 | 65 | ||
80 | /* | 66 | /* |
81 | * Prototypes | 67 | * Prototypes |
82 | */ | 68 | */ |
83 | 69 | void usage(); | |
84 | static void output_info(struct proc *proc_kvm,char **proc_argv); | ||
85 | static void HandleProc(struct proc *proc); | ||
86 | 70 | ||
87 | /*----------------------------------------------------------------------------*/ | 71 | /*----------------------------------------------------------------------------*/ |
88 | 72 | ||
89 | int main (int argc, char **argv) | 73 | int main (int argc, char **argv) |
90 | { | 74 | { |
91 | DIR *pDir; | 75 | DIR *procdir; |
92 | struct dirent *pDent; | 76 | struct dirent *proc; |
93 | int retcode = 0; | 77 | char ps_name[ARGS]; |
94 | struct proc *proc; | 78 | char as_name[ARGS]; |
95 | struct pid pid; | 79 | psinfo_t psinfo; |
96 | 80 | ||
97 | /* Set our program name global */ | 81 | /* Set our program name global */ |
98 | if ((szProg = strrchr(argv[0], '/')) != NULL) | 82 | if ((szProg = strrchr(argv[0], '/')) != NULL) |
99 | szProg++; | 83 | szProg++; |
100 | else | 84 | else |
101 | szProg = argv[0]; | 85 | szProg = argv[0]; |
102 | 86 | ||
103 | /* Make sure that our euid is root */ | 87 | /* if given any parameters, print out help */ |
104 | if (geteuid() != 0) | 88 | if(argc > 1) { |
105 | { | 89 | (void)usage(); |
106 | fprintf(stderr, "%s: This program can only be run by the root user!\n", szProg); | 90 | exit(1); |
107 | exit(1); | 91 | } |
108 | } | 92 | |
109 | 93 | /* Make sure that our euid is root */ | |
110 | /* Get a handle to the running kernel image */ | 94 | if (geteuid() != 0) |
111 | if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, argv[0])) == NULL) | 95 | { |
112 | { | 96 | fprintf(stderr, "%s: This program can only be run by the root user!\n", szProg); |
113 | fprintf(stderr, "%s: Failed to open kernel memory: %s\n", szProg, strerror(errno)); | 97 | exit(1); |
114 | exit(2); | 98 | } |
115 | } | 99 | |
116 | 100 | if ((procdir = opendir(PROC_DIR)) == NULL) { | |
117 | /* reset to first proc in list */ | 101 | fprintf(stderr, "%s: cannot open PROC directory %s\n", szProg, PROC_DIR); |
118 | if(kvm_setproc(kd) == -1) { | 102 | exit(1); |
119 | perror("kvm_setproc"); | 103 | } |
120 | exit(2); | 104 | |
121 | } | 105 | /* Display column headings */ |
122 | 106 | printf("%c %5s %5s %5s %6s %6s %4s %s %s\n", | |
123 | /* Display column headings */ | 107 | 'S', |
124 | printf("%c %5s %5s %5s %6s %6s %4s %s %s\n", | 108 | "UID", |
125 | 'S', | 109 | "PID", |
126 | "UID", | 110 | "PPID", |
127 | "PID", | 111 | "VSZ", |
128 | "PPID", | 112 | "RSS", |
129 | "VSZ", | 113 | "%CPU", |
130 | "RSS", | 114 | "COMMAND", |
131 | "%CPU", | 115 | "ARGS" |
132 | "COMMAND", | 116 | ); |
133 | "ARGS" | 117 | |
134 | ); | 118 | /* Zip through all of the process entries */ |
135 | 119 | while((proc = readdir(procdir))) { | |
136 | /* Zip through all of the process entries */ | 120 | int ps_fd; |
137 | while((proc = kvm_nextproc(kd)) != 0) { | 121 | int as_fd; |
138 | HandleProc(proc); | 122 | off_t argoff; |
139 | } | 123 | int i; |
140 | 124 | char *args; | |
141 | /* Close the handle to the running kernel image */ | 125 | char *procname; |
142 | kvm_close(kd); | 126 | char *ptr; |
143 | 127 | int argslen; | |
144 | return retcode; | 128 | uintptr_t args_addr;; |
129 | uintptr_t *args_vecs;; | ||
130 | int args_count; | ||
131 | |||
132 | if(proc->d_name[0] == '.') | ||
133 | continue; | ||
134 | |||
135 | sprintf(ps_name,"%s/%s/%s",PROC_DIR,proc->d_name,"psinfo"); | ||
136 | sprintf(as_name,"%s/%s/%s",PROC_DIR,proc->d_name,"as"); | ||
137 | try_again: | ||
138 | if((ps_fd = open(ps_name, O_RDONLY)) == -1) | ||
139 | continue; | ||
140 | |||
141 | if((as_fd = open(as_name, O_RDONLY)) == -1) | ||
142 | continue; | ||
143 | |||
144 | if(read(ps_fd, &psinfo, sizeof(psinfo)) != sizeof(psinfo)) { | ||
145 | int err = errno; | ||
146 | close(ps_fd); | ||
147 | close(as_fd); | ||
148 | if(err == EAGAIN) goto try_again; | ||
149 | if(err != ENOENT) | ||
150 | fprintf(stderr, "%s: read() on %s: %s\n", szProg, | ||
151 | ps_name, strerror(err)); | ||
152 | continue; | ||
153 | } | ||
154 | close(ps_fd); | ||
155 | |||
156 | /* system process, ignore since the previous version did */ | ||
157 | if( | ||
158 | psinfo.pr_nlwp == 0 || | ||
159 | strcmp(psinfo.pr_lwp.pr_clname, "SYS") == 0 | ||
160 | ) { | ||
161 | continue; | ||
162 | } | ||
163 | |||
164 | /* get the procname to match previous versions */ | ||
165 | procname = strdup(psinfo.pr_psargs); | ||
166 | if((ptr = strchr(procname, ' ')) != NULL) | ||
167 | *ptr = '\0'; | ||
168 | if((ptr = strrchr(procname, '/')) != NULL) | ||
169 | ptr++; | ||
170 | else | ||
171 | ptr = procname; | ||
172 | |||
173 | /* | ||
174 | * print out what we currently know | ||
175 | */ | ||
176 | printf("%c %5d %5d %5d %6lu %6lu %4.1f %s ", | ||
177 | psinfo.pr_lwp.pr_sname, | ||
178 | psinfo.pr_euid, | ||
179 | psinfo.pr_pid, | ||
180 | psinfo.pr_ppid, | ||
181 | psinfo.pr_size, | ||
182 | psinfo.pr_rssize, | ||
183 | ((float)(psinfo.pr_pctcpu) / 0x8000 * 100.0), | ||
184 | ptr | ||
185 | ); | ||
186 | free(procname); | ||
187 | |||
188 | /* | ||
189 | * and now for the command line stuff | ||
190 | */ | ||
191 | |||
192 | args_addr = psinfo.pr_argv; | ||
193 | args_count = psinfo.pr_argc; | ||
194 | args_vecs = malloc(args_count * sizeof(uintptr_t)); | ||
195 | |||
196 | if(psinfo.pr_dmodel == PR_MODEL_NATIVE) { | ||
197 | /* this process matches target process */ | ||
198 | pread(as_fd,args_vecs, args_count * sizeof(uintptr_t), | ||
199 | args_addr); | ||
200 | } else { | ||
201 | /* this process is 64bit, target process is 32 bit*/ | ||
202 | caddr32_t *args_vecs32 = (caddr32_t *)args_vecs; | ||
203 | pread(as_fd,args_vecs32,args_count * sizeof(caddr32_t), | ||
204 | args_addr); | ||
205 | for (i=args_count-1;i>=0;--i) | ||
206 | args_vecs[i]=args_vecs32[i]; | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * now read in the args - if what we read in fills buffer | ||
211 | * resize buffer and reread that bit again | ||
212 | */ | ||
213 | argslen=ARGS; | ||
214 | args=malloc(argslen+1); | ||
215 | for(i=0;i<args_count;i++) { | ||
216 | memset(args,'\0',argslen+1); | ||
217 | if(pread(as_fd, args, argslen, args_vecs[i]) <= 0) { | ||
218 | break; | ||
219 | } | ||
220 | args[argslen]='\0'; | ||
221 | if(strlen(args) == argslen){ | ||
222 | argslen += ARGS; | ||
223 | args = realloc(args, argslen + 1); | ||
224 | i--; | ||
225 | continue; | ||
226 | } | ||
227 | printf(" %s", args); | ||
228 | } | ||
229 | free(args_vecs); | ||
230 | free(args); | ||
231 | printf("\n"); | ||
232 | } | ||
233 | |||
234 | return (0); | ||
145 | } | 235 | } |
146 | 236 | ||
147 | /*----------------------------------------------------------------------------*/ | 237 | /*----------------------------------------------------------------------------*/ |
148 | 238 | ||
149 | static void HandleProc(struct proc *proc) | 239 | void usage() { |
150 | { | 240 | printf("%s: Help output\n\n", szProg); |
151 | struct pid pid; | 241 | printf("If this program is given any arguments, this help is displayed.\n"); |
152 | struct user *user; | 242 | printf("This command is used to print out the full command line for all\n"); |
153 | char **proc_argv = NULL; | 243 | printf("running processes because /usr/bin/ps is limited to 80 chars and\n"); |
154 | 244 | printf("/usr/ucb/ps can merge columns together.\n\n"); | |
155 | if(kvm_kread(kd, (unsigned long) proc->p_pidp, (char *) &pid, sizeof pid) == -1) { | 245 | printf("Columns are:\n"); |
156 | perror("kvm_read error"); | 246 | printf("\tS - State of process - see 'ps' man page\n"); |
157 | exit(2); | 247 | printf("\tUID - UID of the process owner\n"); |
158 | } | 248 | printf("\tPID - PID of the process\n"); |
159 | proc->p_pidp = &pid; | 249 | printf("\tPPID - PID of the parent process\n"); |
160 | user = kvm_getu(kd, proc); | 250 | printf("\tVSZ - Virtual memory usage (kilobytes)\n"); |
161 | 251 | printf("\tRSS - Real memory usage (kilobytes)\n"); | |
162 | if(kvm_getcmd(kd, proc, user, &proc_argv, NULL) == -1) { | 252 | printf("\t%%CPU - CPU usage\n"); |
163 | return; | 253 | printf("\tCOMMAND - Command being run\n"); |
164 | } | 254 | printf("\tARGS - Full command line with arguements\n"); |
165 | 255 | return; | |
166 | if(proc_argv == NULL) { | ||
167 | return; | ||
168 | } | ||
169 | |||
170 | output_info(proc, proc_argv); | ||
171 | free(proc_argv); | ||
172 | } | 256 | } |
173 | |||
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; | ||
181 | |||
182 | sprintf(procpath, "/proc/%d/psinfo", proc_kvm->p_pidp->pid_id); | ||
183 | |||
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 | } | ||
193 | |||
194 | if((procname = strrchr(proc_argv[0], '/')) != NULL) | ||
195 | procname++; | ||
196 | else | ||
197 | procname = proc_argv[0]; | ||
198 | |||
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 | ); | ||
209 | |||
210 | for(i=0;proc_argv[i];i++) { | ||
211 | printf(" %s", proc_argv[i]); | ||
212 | } | ||
213 | |||
214 | printf("\n"); | ||
215 | } | ||
216 | |||