1 /* pst3.c
2 *
3 * Third version to get process arg info; this time by using
4 * a combination of reading the /proc/<pid>/psinfo structures
5 * and reading the complete arg vector from kernel memory structures.
6 *
7 * Developed and tested under Solaris 5.8 (both 32 and 64 bit modes).
8 *
9 * NOTE: This program must be setuid-root (or run by root) to work!
10 *
11 * Written: 2005-04-28 R.W.Ingraham
12 */
15 #define _KMEMUSER 1
17 #include <kvm.h>
18 #include <sys/param.h>
19 #include <sys/user.h>
20 #include <sys/time.h>
21 #include <sys/proc.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <procfs.h>
29 #include <fcntl.h>
30 #include <dirent.h>
31 #include <errno.h>
34 /*
35 * Constants
36 */
38 #define PROC_DIR "/proc"
39 #define MAX_PATH 1024
42 /*
43 * Structures
44 */
47 /*
48 * Globals
49 */
51 static char * szProg;
52 static kvm_t * kd;
53 static struct proc * pProc;
54 static struct user * pUser;
55 static char ** myArgv;
58 /*
59 * Prototypes
60 */
62 static int HandleFile (struct dirent *pDent);
63 static int HandlePsInfo (char *szPath, psinfo_t *pPsInfo);
64 static int GetArgVectors (pid_t pid);
65 static void ShowArgVectors (void);
66 static void ReleaseArgVectors();
69 /*----------------------------------------------------------------------------*/
71 int main (int argc, char **argv)
72 {
73 DIR *pDir;
74 struct dirent *pDent;
75 int retcode = 0;
78 /* Set our program name global */
79 if ((szProg = strrchr(argv[0], '/')) != NULL)
80 szProg++;
81 else
82 szProg = argv[0];
84 /* Make sure that our euid is root */
85 if (geteuid() != 0)
86 {
87 fprintf(stderr, "%s: This program can only be run by the root user!\n", szProg);
88 exit(1);
89 }
91 /* Get a handle to the running kernel image */
92 if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, argv[0])) == NULL)
93 {
94 fprintf(stderr, "%s: Failed to open kernel memory: %s\n", szProg, strerror(errno));
95 exit(2);
96 }
98 /* Open the /proc directory */
99 if ((pDir = opendir(PROC_DIR)) != NULL)
100 {
101 /* Display column headings */
102 printf("S UID PPID VSZ RSS %%CPU COMMAND ARGS\n");
104 /* Zip through all of the process entries */
105 while ((pDent = readdir(pDir)) != NULL)
106 {
107 /* Handle each pid sub-directory */
108 HandleFile(pDent);
109 }
111 /* Close the directory */
112 closedir(pDir);
113 }
114 else /* ERROR: Failure to open PROC_DIR */
115 {
116 fprintf(stderr, "%s: Failed to open \"%s\": %s\n", szProg, PROC_DIR, strerror(errno));
117 retcode = 3;
118 }
120 /* Close the handle to the running kernel image */
121 kvm_close(kd);
123 return retcode;
124 }
126 /*----------------------------------------------------------------------------*/
128 static int HandleFile (struct dirent *pDent)
129 {
130 char szPath[MAX_PATH];
131 psinfo_t sPsInfo;
132 int fd, len;
133 int rc = 0;
135 /* Skip files beginning with a "." */
136 if (pDent->d_name[0] == '.')
137 return 0;
139 /* Cosntruct the path to the psinfo file */
140 len = sprintf(szPath, "%s/%s/psinfo", PROC_DIR, pDent->d_name);
142 /* Open the psinfo file for this pid and print out its arg vectors */
143 if ((fd = open(szPath, O_RDONLY)) >= 0)
144 {
145 /* Read the psinfo struct */
146 if ((len = read(fd, &sPsInfo, sizeof(sPsInfo))) != sizeof(sPsInfo))
147 {
148 rc = errno;
149 fprintf(stderr, "%s: Read error of psinfo structure (%d)\n", szPath, len);
150 return rc;
151 }
153 /* Close the psinfo file */
154 close(fd);
156 /* Pass psinfo struct to reporting function */
157 HandlePsInfo(szPath, &sPsInfo);
158 }
159 else if (errno != ENOENT)
160 {
161 rc = errno;
162 fprintf(stderr, "%s: %s\n", szPath, strerror(errno));
163 }
165 return 0;
166 }
168 /*----------------------------------------------------------------------------*/
170 static int HandlePsInfo (char *szPath, psinfo_t *pPsInfo)
171 {
172 int retcode;
173 char *thisProg;
175 /* Make sure that the process is still there */
176 if ((retcode = GetArgVectors(pPsInfo->pr_pid)) == 0)
177 {
178 /* We use the program name from the kvm argv[0] instead
179 * of pr_fname from the psinfo struct because pr_fname
180 * may be truncated.
181 *
182 * Also, strip-off leading path information.
183 */
184 if ((thisProg = strrchr(myArgv[0], '/')) != NULL)
185 thisProg++;
186 else
187 thisProg = myArgv[0];
189 /* Display the ps columns (except for argv) */
190 printf("%c %5d %5d %6lu %6lu %4.1f %s ",
191 pPsInfo->pr_lwp.pr_sname,
192 (int)(pPsInfo->pr_euid),
193 (int)(pPsInfo->pr_ppid),
194 (unsigned long)(pPsInfo->pr_size),
195 (unsigned long)(pPsInfo->pr_rssize),
196 ((float)(pPsInfo->pr_pctcpu) / 0x8000 * 100.0),
197 thisProg);
199 /* Display the arg vectors associated with this pid */
200 ShowArgVectors();
202 /* Release the arg vector buffer memory */
203 ReleaseArgVectors();
204 }
206 return retcode;
207 }
209 /*----------------------------------------------------------------------------*/
211 static int GetArgVectors (pid_t pid)
212 {
213 int retcode = 1;
215 /* Get the proc structure for the specified PID */
216 if ((pProc = kvm_getproc(kd, pid)) != NULL)
217 {
218 /* Save a copy of the process' u-area */
219 if ((pUser = kvm_getu(kd, pProc)) != NULL)
220 {
221 /* Reconstruct the process' argv vector array */
222 if (kvm_getcmd(kd, pProc, pUser, &myArgv, NULL) == 0)
223 {
224 retcode = 0;
225 }
226 }
227 }
229 return retcode;
230 }
232 /*----------------------------------------------------------------------------*/
234 static void ShowArgVectors (void)
235 {
236 int i;
238 for (i=0; myArgv[i]; i++)
239 {
240 printf(" %s", myArgv[i]);
241 }
242 printf("\n");
243 }
245 /*----------------------------------------------------------------------------*/
247 static void ReleaseArgVectors()
248 {
249 /* NOOP */
250 }
252 /*----------------------------------------------------------------------------*/