]> sourceware.org Git - newlib-cygwin.git/blob - winsup/utils/ps.cc
478ed8efd27e98f0c5a4795242e7f9ccd523b689
[newlib-cygwin.git] / winsup / utils / ps.cc
1 /* ps.cc
2
3 This file is part of Cygwin.
4
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7 details. */
8
9 #include <errno.h>
10 #include <stdio.h>
11 #include <locale.h>
12 #include <wchar.h>
13 #include <windows.h>
14 #include <time.h>
15 #include <getopt.h>
16 #include <unistd.h>
17 #include <stdlib.h>
18 #include <pwd.h>
19 #include <limits.h>
20 #include <sys/cygwin.h>
21 #include <cygwin/version.h>
22 #include <psapi.h>
23 #include <ntdef.h>
24 #include <ntdll.h>
25 #include "loadlib.h"
26
27 /* Maximum possible path length under NT. There's no official define
28 for that value. Note that PATH_MAX is only 4K. */
29 #define NT_MAX_PATH 32767
30
31 static char *prog_name;
32
33 static struct option longopts[] =
34 {
35 {"all", no_argument, NULL, 'a' },
36 {"everyone", no_argument, NULL, 'e' },
37 {"full", no_argument, NULL, 'f' },
38 {"help", no_argument, NULL, 'h' },
39 {"long", no_argument, NULL, 'l' },
40 {"process", required_argument, NULL, 'p'},
41 {"summary", no_argument, NULL, 's' },
42 {"user", required_argument, NULL, 'u'},
43 {"version", no_argument, NULL, 'V'},
44 {"windows", no_argument, NULL, 'W'},
45 {NULL, 0, NULL, 0}
46 };
47
48 static char opts[] = "aefhlp:su:VW";
49
50 static char *
51 start_time (external_pinfo *child)
52 {
53 time_t st = child->start_time;
54 time_t t = time (NULL);
55 static char stime[40] = {'\0'};
56 char now[40];
57
58 strncpy (stime, ctime (&st) + 4, 15);
59 strcpy (now, ctime (&t) + 4);
60
61 if ((t - st) < (24 * 3600))
62 return (stime + 7);
63
64 stime[6] = '\0';
65
66 return stime;
67 }
68
69 #define FACTOR (0x19db1ded53ea710LL)
70 #define NSPERSEC 10000000LL
71
72 /* Convert a Win32 time to "UNIX" format. */
73 long __stdcall
74 to_time_t (FILETIME *ptr)
75 {
76 /* A file time is the number of 100ns since jan 1 1601
77 stuffed into two long words.
78 A time_t is the number of seconds since jan 1 1970. */
79
80 long rem;
81 long long x = ((long long) ptr->dwHighDateTime << 32) + ((unsigned)ptr->dwLowDateTime);
82 x -= FACTOR; /* number of 100ns between 1601 and 1970 */
83 rem = x % ((long long)NSPERSEC);
84 rem += (NSPERSEC / 2);
85 x /= (long long) NSPERSEC; /* number of 100ns in a second */
86 x += (long long) (rem / NSPERSEC);
87 return x;
88 }
89
90 static const char *
91 ttynam (int ntty, char buf[9])
92 {
93 char buf0[9];
94
95 if (ntty < 0)
96 strcpy (buf0, "?");
97 else if (ntty & 0xffff0000)
98 snprintf (buf0, 9, "cons%d", ntty & 0xff);
99 else
100 snprintf (buf0, 9, "pty%d", ntty);
101 snprintf (buf, 9, " %-7.7s", buf0);
102 return buf;
103 }
104
105 static void __attribute__ ((__noreturn__))
106 usage (FILE * stream, int status)
107 {
108 fprintf (stream, "\
109 Usage: %1$s [-aefls] [-u UID] [-p PID]\n\
110 \n\
111 Report process status\n\
112 \n\
113 -a, --all show processes of all users\n\
114 -e, --everyone show processes of all users\n\
115 -f, --full show process uids, ppids\n\
116 -h, --help output usage information and exit\n\
117 -l, --long show process uids, ppids, pgids, winpids\n\
118 -p, --process show information for specified PID\n\
119 -s, --summary show process summary\n\
120 -u, --user list processes owned by UID\n\
121 -V, --version output version information and exit\n\
122 -W, --windows show windows as well as cygwin processes\n\
123 \n\
124 With no options, %1$s outputs the long format by default\n\n",
125 prog_name);
126 exit (status);
127 }
128
129 static void
130 print_version ()
131 {
132 printf ("ps (cygwin) %d.%d.%d\n"
133 "Show process statistics\n"
134 "Copyright (C) 1996 - %s Cygwin Authors\n"
135 "This is free software; see the source for copying conditions. There is NO\n"
136 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
137 CYGWIN_VERSION_DLL_MAJOR / 1000,
138 CYGWIN_VERSION_DLL_MAJOR % 1000,
139 CYGWIN_VERSION_DLL_MINOR,
140 strrchr (__DATE__, ' ') + 1);
141 }
142
143 struct
144 {
145 SYSTEM_PROCESS_ID_INFORMATION spii;
146 WCHAR buf[NT_MAX_PATH + 1];
147 } ucbuf;
148
149 char pname[NT_MAX_PATH + sizeof (" <defunct>") + 1];
150
151 int
152 main (int argc, char *argv[])
153 {
154 external_pinfo *p;
155 int aflag, lflag, fflag, sflag, proc_id;
156 uid_t uid;
157 bool found_proc_id = true;
158 cygwin_getinfo_types query = CW_GETPINFO;
159 const char *dtitle = " PID TTY STIME COMMAND\n";
160 const char *dfmt = "%7d%4s%10s %s\n";
161 const char *ftitle = " UID PID PPID TTY STIME COMMAND\n";
162 const char *ffmt = "%8.8s%8d%8d%4s%10s %s\n";
163 const char *ltitle = " PID PPID PGID WINPID TTY UID STIME COMMAND\n";
164 const char *lfmt = "%c %7d %7d %7d %10u %4s %8u %8s %s\n";
165 char ch;
166 void *drive_map = NULL;
167 time_t boot_time = -1;
168
169 aflag = lflag = fflag = sflag = 0;
170 uid = getuid ();
171 proc_id = -1;
172 lflag = 1;
173
174 setlocale (LC_ALL, "");
175
176 prog_name = program_invocation_short_name;
177
178 while ((ch = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
179 switch (ch)
180 {
181 case 'a':
182 case 'e':
183 aflag = 1;
184 break;
185 case 'f':
186 fflag = 1;
187 break;
188 case 'h':
189 usage (stdout, 0);
190 case 'l':
191 lflag = 1;
192 break;
193 case 'p':
194 proc_id = atoi (optarg);
195 aflag = 1;
196 found_proc_id = false;
197 break;
198 case 's':
199 sflag = 1;
200 break;
201 case 'u':
202 uid = atoi (optarg);
203 if (uid == 0)
204 {
205 struct passwd *pw;
206
207 if ((pw = getpwnam (optarg)))
208 uid = pw->pw_uid;
209 else
210 {
211 fprintf (stderr, "%s: user %s unknown\n", prog_name, optarg);
212 exit (1);
213 }
214 }
215 break;
216 case 'V':
217 print_version ();
218 exit (0);
219 break;
220 case 'W':
221 query = CW_GETPINFO_FULL;
222 aflag = 1;
223 break;
224
225 default:
226 fprintf (stderr, "Try `%s --help' for more information.\n", prog_name);
227 exit (1);
228 }
229
230 if (sflag)
231 fputs (dtitle, stdout);
232 else if (fflag)
233 fputs (ftitle, stdout);
234 else if (lflag)
235 fputs (ltitle, stdout);
236
237 (void) cygwin_internal (CW_LOCK_PINFO, 1000);
238
239 if (query == CW_GETPINFO_FULL)
240 {
241 HANDLE tok;
242 NTSTATUS status;
243 SYSTEM_TIMEOFDAY_INFORMATION stodi;
244
245 /* Enable debug privilege to allow to enumerate all processes,
246 not only processes in current session. */
247 if (OpenProcessToken (GetCurrentProcess (),
248 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
249 &tok))
250 {
251 TOKEN_PRIVILEGES priv;
252
253 priv.PrivilegeCount = 1;
254 if (LookupPrivilegeValue (NULL, SE_DEBUG_NAME,
255 &priv.Privileges[0].Luid))
256 {
257 priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
258 AdjustTokenPrivileges (tok, FALSE, &priv, 0, NULL, NULL);
259 }
260 }
261
262 drive_map = (void *) cygwin_internal (CW_ALLOC_DRIVE_MAP);
263
264 /* Get system boot time to default process start time */
265 status = NtQuerySystemInformation (SystemTimeOfDayInformation,
266 (PVOID) &stodi, sizeof stodi, NULL);
267 if (!NT_SUCCESS (status))
268 fprintf (stderr,
269 "NtQuerySystemInformation(SystemTimeOfDayInformation), "
270 "status %#010x\n", (unsigned int) status);
271 boot_time = to_time_t ((FILETIME*)&stodi.BootTime);
272 }
273
274 for (int pid = 0;
275 (p = (external_pinfo *) cygwin_internal (query, pid | CW_NEXTPID));
276 pid = p->pid)
277 {
278 if ((proc_id > 0) && (p->pid != proc_id))
279 continue;
280 else
281 found_proc_id = true;
282
283 if (aflag)
284 /* nothing to do */;
285 else if (p->version >= EXTERNAL_PINFO_VERSION_32_BIT)
286 {
287 if (p->uid32 != uid)
288 continue;
289 }
290 else if (p->uid != uid)
291 continue;
292 char status = ' ';
293 if (p->process_state & PID_STOPPED)
294 status = 'S';
295 else if (p->process_state & PID_TTYIN)
296 status = 'I';
297 else if (p->process_state & PID_TTYOU)
298 status = 'O';
299
300 if (p->ppid)
301 {
302 char *s;
303 pname[0] = '\0';
304 strncat (pname, p->progname_long, NT_MAX_PATH);
305 s = strchr (pname, '\0') - 4;
306 if (s > pname && strcasecmp (s, ".exe") == 0)
307 *s = '\0';
308 if (p->process_state & PID_EXITED || (p->exitcode & ~0xffff))
309 strcat (pname, " <defunct>");
310 }
311 else if (query == CW_GETPINFO_FULL)
312 {
313 HANDLE h;
314 NTSTATUS status;
315 wchar_t *win32path = NULL;
316 FILETIME ct, et, kt, ut;
317
318 ucbuf.spii.ProcessId = (PVOID) (ULONG_PTR) p->dwProcessId;
319 ucbuf.spii.ImageName.Length = 0;
320 ucbuf.spii.ImageName.MaximumLength = NT_MAX_PATH * sizeof (WCHAR);
321 ucbuf.spii.ImageName.Buffer = ucbuf.buf;
322 status = NtQuerySystemInformation (SystemProcessIdInformation,
323 &ucbuf.spii, sizeof ucbuf.spii,
324 NULL);
325 if (NT_SUCCESS (status))
326 {
327 if (ucbuf.spii.ImageName.Length)
328 ucbuf.spii.ImageName.Buffer[ucbuf.spii.ImageName.Length
329 / sizeof (WCHAR)] = L'\0';
330 win32path = ucbuf.spii.ImageName.Buffer;
331 }
332 if (win32path)
333 {
334 /* Call CW_MAP_DRIVE_MAP to convert native NT device paths to
335 an ordinary Win32 path. The returned pointer points into
336 the incoming buffer given as third argument. */
337 if (win32path[0] == L'\\')
338 win32path = (wchar_t *) cygwin_internal (CW_MAP_DRIVE_MAP,
339 drive_map, win32path);
340 wcstombs (pname, win32path, sizeof pname);
341 }
342 else
343 strcpy (pname, p->dwProcessId == 4 ? "System" : "*** unknown ***");
344
345 h = OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION, FALSE,
346 p->dwProcessId);
347 if (h)
348 {
349 if (GetProcessTimes (h, &ct, &et, &kt, &ut))
350 p->start_time = to_time_t (&ct);
351 CloseHandle (h);
352 }
353 /* Default to boot time when process start time inaccessible, 0, -1 */
354 if (!h || 0 == p->start_time || -1 == p->start_time)
355 {
356 p->start_time = boot_time;
357 }
358 }
359
360 char uname[128];
361 char ttyname[9];
362
363 if (fflag)
364 {
365 struct passwd *pw;
366
367 if ((pw = getpwuid (p->version >= EXTERNAL_PINFO_VERSION_32_BIT ?
368 p->uid32 : p->uid)))
369 strcpy (uname, pw->pw_name);
370 else
371 sprintf (uname, "%u", (unsigned)
372 (p->version >= EXTERNAL_PINFO_VERSION_32_BIT ?
373 p->uid32 : p->uid));
374 }
375
376 if (sflag)
377 printf (dfmt, p->pid, ttynam (p->ctty, ttyname), start_time (p), pname);
378 else if (fflag)
379 printf (ffmt, uname, p->pid, p->ppid, ttynam (p->ctty, ttyname),
380 start_time (p), pname);
381 else if (lflag)
382 printf (lfmt, status, p->pid, p->ppid, p->pgid,
383 p->dwProcessId, ttynam (p->ctty, ttyname),
384 p->version >= EXTERNAL_PINFO_VERSION_32_BIT ? p->uid32 : p->uid,
385 start_time (p), pname);
386
387 }
388 if (drive_map)
389 cygwin_internal (CW_FREE_DRIVE_MAP, drive_map);
390 (void) cygwin_internal (CW_UNLOCK_PINFO);
391
392 return found_proc_id ? 0 : 1;
393 }
This page took 0.055037 seconds and 4 git commands to generate.