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