3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
20 #include <sys/cygwin.h>
21 #include <cygwin/version.h>
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
31 static char *prog_name
;
33 static struct option longopts
[] =
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'},
48 static char opts
[] = "aefhlp:su:VW";
51 start_time (external_pinfo
*child
)
53 time_t st
= child
->start_time
;
54 time_t t
= time (NULL
);
55 static char stime
[40] = {'\0'};
58 strncpy (stime
, ctime (&st
) + 4, 15);
59 strcpy (now
, ctime (&t
) + 4);
61 if ((t
- st
) < (24 * 3600))
69 #define FACTOR (0x19db1ded53ea710LL)
70 #define NSPERSEC 10000000LL
72 /* Convert a Win32 time to "UNIX" format. */
74 to_time_t (FILETIME
*ptr
)
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. */
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
);
91 ttynam (int ntty
, char buf
[9])
97 else if (ntty
& 0xffff0000)
98 snprintf (buf0
, 9, "cons%d", ntty
& 0xff);
100 snprintf (buf0
, 9, "pty%d", ntty
);
101 snprintf (buf
, 9, " %-7.7s", buf0
);
105 static void __attribute__ ((__noreturn__
))
106 usage (FILE * stream
, int status
)
109 Usage: %1$s [-aefls] [-u UID] [-p PID]\n\
111 Report process status\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\
124 With no options, %1$s outputs the long format by default\n\n",
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);
145 SYSTEM_PROCESS_ID_INFORMATION spii
;
146 WCHAR buf
[NT_MAX_PATH
+ 1];
149 char pname
[NT_MAX_PATH
+ sizeof (" <defunct>") + 1];
152 main (int argc
, char *argv
[])
155 int aflag
, lflag
, fflag
, sflag
, proc_id
;
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";
166 void *drive_map
= NULL
;
167 time_t boot_time
= -1;
169 aflag
= lflag
= fflag
= sflag
= 0;
174 setlocale (LC_ALL
, "");
176 prog_name
= program_invocation_short_name
;
178 while ((ch
= getopt_long (argc
, argv
, opts
, longopts
, NULL
)) != EOF
)
194 proc_id
= atoi (optarg
);
196 found_proc_id
= false;
207 if ((pw
= getpwnam (optarg
)))
211 fprintf (stderr
, "%s: user %s unknown\n", prog_name
, optarg
);
221 query
= CW_GETPINFO_FULL
;
226 fprintf (stderr
, "Try `%s --help' for more information.\n", prog_name
);
231 fputs (dtitle
, stdout
);
233 fputs (ftitle
, stdout
);
235 fputs (ltitle
, stdout
);
237 (void) cygwin_internal (CW_LOCK_PINFO
, 1000);
239 if (query
== CW_GETPINFO_FULL
)
243 SYSTEM_TIMEOFDAY_INFORMATION stodi
;
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
,
251 TOKEN_PRIVILEGES priv
;
253 priv
.PrivilegeCount
= 1;
254 if (LookupPrivilegeValue (NULL
, SE_DEBUG_NAME
,
255 &priv
.Privileges
[0].Luid
))
257 priv
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
258 AdjustTokenPrivileges (tok
, FALSE
, &priv
, 0, NULL
, NULL
);
262 drive_map
= (void *) cygwin_internal (CW_ALLOC_DRIVE_MAP
);
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
))
269 "NtQuerySystemInformation(SystemTimeOfDayInformation), "
270 "status %#010x\n", (unsigned int) status
);
271 boot_time
= to_time_t ((FILETIME
*)&stodi
.BootTime
);
275 (p
= (external_pinfo
*) cygwin_internal (query
, pid
| CW_NEXTPID
));
278 if ((proc_id
> 0) && (p
->pid
!= proc_id
))
281 found_proc_id
= true;
285 else if (p
->version
>= EXTERNAL_PINFO_VERSION_32_BIT
)
290 else if (p
->uid
!= uid
)
293 if (p
->process_state
& PID_STOPPED
)
295 else if (p
->process_state
& PID_TTYIN
)
297 else if (p
->process_state
& PID_TTYOU
)
304 strncat (pname
, p
->progname_long
, NT_MAX_PATH
);
305 s
= strchr (pname
, '\0') - 4;
306 if (s
> pname
&& strcasecmp (s
, ".exe") == 0)
308 if (p
->process_state
& PID_EXITED
|| (p
->exitcode
& ~0xffff))
309 strcat (pname
, " <defunct>");
311 else if (query
== CW_GETPINFO_FULL
)
315 wchar_t *win32path
= NULL
;
316 FILETIME ct
, et
, kt
, ut
;
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
,
325 if (NT_SUCCESS (status
))
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
;
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
);
343 strcpy (pname
, p
->dwProcessId
== 4 ? "System" : "*** unknown ***");
345 h
= OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION
, FALSE
,
349 if (GetProcessTimes (h
, &ct
, &et
, &kt
, &ut
))
350 p
->start_time
= to_time_t (&ct
);
353 /* Default to boot time when process start time inaccessible, 0, -1 */
354 if (!h
|| 0 == p
->start_time
|| -1 == p
->start_time
)
356 p
->start_time
= boot_time
;
367 if ((pw
= getpwuid (p
->version
>= EXTERNAL_PINFO_VERSION_32_BIT
?
369 strcpy (uname
, pw
->pw_name
);
371 sprintf (uname
, "%u", (unsigned)
372 (p
->version
>= EXTERNAL_PINFO_VERSION_32_BIT
?
377 printf (dfmt
, p
->pid
, ttynam (p
->ctty
, ttyname
), start_time (p
), pname
);
379 printf (ffmt
, uname
, p
->pid
, p
->ppid
, ttynam (p
->ctty
, ttyname
),
380 start_time (p
), pname
);
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
);
389 cygwin_internal (CW_FREE_DRIVE_MAP
, drive_map
);
390 (void) cygwin_internal (CW_UNLOCK_PINFO
);
392 return found_proc_id
? 0 : 1;