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 <sys/ioctl.h>
22 #include <cygwin/version.h>
26 /* Maximum possible path length under NT. There's no official define
27 for that value. Note that PATH_MAX is only 4K. */
28 #define NT_MAX_PATH 32767
30 #define OUTPUT_BUFSIZ 65536
32 static char *prog_name
;
34 static struct option longopts
[] =
36 {"all", no_argument
, NULL
, 'a' },
37 {"everyone", no_argument
, NULL
, 'e' },
38 {"full", no_argument
, NULL
, 'f' },
39 {"help", no_argument
, NULL
, 'h' },
40 {"long", no_argument
, NULL
, 'l' },
41 {"process", required_argument
, NULL
, 'p'},
42 {"summary", no_argument
, NULL
, 's' },
43 {"user", required_argument
, NULL
, 'u'},
44 {"version", no_argument
, NULL
, 'V'},
45 {"windows", no_argument
, NULL
, 'W'},
49 static char opts
[] = "aefhlp:su:VW";
52 start_time (external_pinfo
*child
)
54 time_t st
= child
->start_time
;
55 time_t t
= time (NULL
);
56 static char stime
[40] = {'\0'};
59 strncpy (stime
, ctime (&st
) + 4, 15);
60 strcpy (now
, ctime (&t
) + 4);
62 if ((t
- st
) < (24 * 3600))
70 #define FACTOR (0x19db1ded53ea710LL)
71 #define NSPERSEC 10000000LL
73 /* Convert a Win32 time to "UNIX" format. */
75 to_time_t (FILETIME
*ptr
)
77 /* A file time is the number of 100ns since jan 1 1601
78 stuffed into two long words.
79 A time_t is the number of seconds since jan 1 1970. */
82 long long x
= ((long long) ptr
->dwHighDateTime
<< 32) + ((unsigned)ptr
->dwLowDateTime
);
83 x
-= FACTOR
; /* number of 100ns between 1601 and 1970 */
84 rem
= x
% ((long long)NSPERSEC
);
85 rem
+= (NSPERSEC
/ 2);
86 x
/= (long long) NSPERSEC
; /* number of 100ns in a second */
87 x
+= (long long) (rem
/ NSPERSEC
);
92 ttynam (int ntty
, char buf
[9])
98 else if (ntty
& 0xffff0000)
99 snprintf (buf0
, 9, "cons%d", ntty
& 0xff);
101 snprintf (buf0
, 9, "pty%d", ntty
);
102 snprintf (buf
, 9, " %-7.7s", buf0
);
106 static void __attribute__ ((__noreturn__
))
107 usage (FILE * stream
, int status
)
110 Usage: %1$s [-aefls] [-u UID] [-p PID]\n\
112 Report process status\n\
114 -a, --all show processes of all users\n\
115 -e, --everyone show processes of all users\n\
116 -f, --full show process uids, ppids and command line\n\
117 -h, --help output usage information and exit\n\
118 -l, --long show process uids, ppids, pgids, winpids\n\
119 -p, --process show information for specified PID\n\
120 -s, --summary show process summary\n\
121 -u, --user list processes owned by UID\n\
122 -V, --version output version information and exit\n\
123 -W, --windows show windows as well as cygwin processes\n\
125 With no options, %1$s outputs the long format by default\n\n",
133 printf ("ps (cygwin) %d.%d.%d\n"
134 "Show process statistics\n"
135 "Copyright (C) 1996 - %s Cygwin Authors\n"
136 "This is free software; see the source for copying conditions. There is NO\n"
137 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
138 CYGWIN_VERSION_DLL_MAJOR
/ 1000,
139 CYGWIN_VERSION_DLL_MAJOR
% 1000,
140 CYGWIN_VERSION_DLL_MINOR
,
141 strrchr (__DATE__
, ' ') + 1);
146 SYSTEM_PROCESS_ID_INFORMATION spii
;
147 WCHAR buf
[NT_MAX_PATH
+ 1];
150 char pname
[NT_MAX_PATH
+ sizeof (" <defunct>") + 1];
152 char output_buffer
[OUTPUT_BUFSIZ
];
155 ps_print (const char *string
, int width
)
157 printf ("%.*s\n", width
, string
);
161 main (int argc
, char *argv
[])
164 int aflag
, lflag
, fflag
, sflag
, proc_id
, width
, col
;
166 bool found_proc_id
= true;
167 cygwin_getinfo_types query
= CW_GETPINFO
;
168 const char *stitle
= " PID TTY STIME COMMAND";
169 const char *sfmt
= "%7d%4s%10s %s";
170 const char *ftitle
= " UID PID PPID TTY STIME COMMAND";
171 const char *ffmt
= "%8.8s%8d%8d%4s%10s %s";
172 const char *ltitle
= " PID PPID PGID WINPID TTY UID STIME COMMAND";
173 const char *lfmt
= "%c %7d %7d %7d %10u %4s %8u %8s %s";
175 void *drive_map
= NULL
;
176 time_t boot_time
= -1;
181 aflag
= lflag
= fflag
= sflag
= 0;
186 setlocale (LC_ALL
, "");
188 prog_name
= program_invocation_short_name
;
190 while ((ch
= getopt_long (argc
, argv
, opts
, longopts
, NULL
)) != EOF
)
210 proc_id
= atoi (optarg
);
212 found_proc_id
= false;
225 if ((pw
= getpwnam (optarg
)))
229 fprintf (stderr
, "%s: user %s unknown\n", prog_name
, optarg
);
239 query
= CW_GETPINFO_FULL
;
244 fprintf (stderr
, "Try `%s --help' for more information.\n", prog_name
);
248 (void) cygwin_internal (CW_LOCK_PINFO
, 1000);
250 if (query
== CW_GETPINFO_FULL
)
254 SYSTEM_TIMEOFDAY_INFORMATION stodi
;
256 /* Enable debug privilege to allow to enumerate all processes,
257 not only processes in current session. */
258 if (OpenProcessToken (GetCurrentProcess (),
259 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
262 TOKEN_PRIVILEGES priv
;
264 priv
.PrivilegeCount
= 1;
265 if (LookupPrivilegeValue (NULL
, SE_DEBUG_NAME
,
266 &priv
.Privileges
[0].Luid
))
268 priv
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
269 AdjustTokenPrivileges (tok
, FALSE
, &priv
, 0, NULL
, NULL
);
273 drive_map
= (void *) cygwin_internal (CW_ALLOC_DRIVE_MAP
);
275 /* Get system boot time to default process start time */
276 status
= NtQuerySystemInformation (SystemTimeOfDayInformation
,
277 (PVOID
) &stodi
, sizeof stodi
, NULL
);
278 if (!NT_SUCCESS (status
))
280 "NtQuerySystemInformation(SystemTimeOfDayInformation), "
281 "status %#010x\n", (unsigned int) status
);
282 boot_time
= to_time_t ((FILETIME
*)&stodi
.BootTime
);
285 width
= OUTPUT_BUFSIZ
;
286 if ((columns
= getenv ("COLUMNS")) && *columns
287 && (col
= strtoul (columns
, &end
, 0)) > 0 && !*end
)
289 else if (isatty (STDOUT_FILENO
))
292 if (ioctl (STDOUT_FILENO
, TIOCGWINSZ
, &ws
) != -1)
295 if (width
> OUTPUT_BUFSIZ
)
296 width
= OUTPUT_BUFSIZ
;
299 ps_print (stitle
, width
);
301 ps_print (ftitle
, width
);
303 ps_print (ltitle
, width
);
306 (p
= (external_pinfo
*) cygwin_internal (query
, pid
| CW_NEXTPID
));
309 if ((proc_id
> 0) && (p
->pid
!= proc_id
))
312 found_proc_id
= true;
316 else if (p
->version
>= EXTERNAL_PINFO_VERSION_32_BIT
)
321 else if (p
->uid
!= uid
)
324 if (p
->process_state
& PID_STOPPED
)
326 else if (p
->process_state
& PID_TTYIN
)
328 else if (p
->process_state
& PID_TTYOU
)
335 strncat (pname
, p
->progname_long
, NT_MAX_PATH
);
336 s
= strchr (pname
, '\0') - 4;
337 if (s
> pname
&& strcasecmp (s
, ".exe") == 0)
339 if (p
->process_state
& PID_EXITED
|| (p
->exitcode
& ~0xffff))
340 strcat (pname
, " <defunct>");
342 else if (query
== CW_GETPINFO_FULL
)
346 wchar_t *win32path
= NULL
;
347 FILETIME ct
, et
, kt
, ut
;
349 ucbuf
.spii
.ProcessId
= (PVOID
) (ULONG_PTR
) p
->dwProcessId
;
350 ucbuf
.spii
.ImageName
.Length
= 0;
351 ucbuf
.spii
.ImageName
.MaximumLength
= NT_MAX_PATH
* sizeof (WCHAR
);
352 ucbuf
.spii
.ImageName
.Buffer
= ucbuf
.buf
;
353 status
= NtQuerySystemInformation (SystemProcessIdInformation
,
354 &ucbuf
.spii
, sizeof ucbuf
.spii
,
356 if (NT_SUCCESS (status
))
358 if (ucbuf
.spii
.ImageName
.Length
)
359 ucbuf
.spii
.ImageName
.Buffer
[ucbuf
.spii
.ImageName
.Length
360 / sizeof (WCHAR
)] = L
'\0';
361 win32path
= ucbuf
.spii
.ImageName
.Buffer
;
365 /* Call CW_MAP_DRIVE_MAP to convert native NT device paths to
366 an ordinary Win32 path. The returned pointer points into
367 the incoming buffer given as third argument. */
368 if (win32path
[0] == L
'\\')
369 win32path
= (wchar_t *) cygwin_internal (CW_MAP_DRIVE_MAP
,
370 drive_map
, win32path
);
371 wcstombs (pname
, win32path
, sizeof pname
);
374 strcpy (pname
, p
->dwProcessId
== 4 ? "System" : "*** unknown ***");
376 h
= OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION
, FALSE
,
380 if (GetProcessTimes (h
, &ct
, &et
, &kt
, &ut
))
381 p
->start_time
= to_time_t (&ct
);
384 /* Default to boot time when process start time inaccessible, 0, -1 */
385 if (!h
|| 0 == p
->start_time
|| -1 == p
->start_time
)
387 p
->start_time
= boot_time
;
393 char *cmdline
= NULL
;
399 if ((pw
= getpwuid (p
->version
>= EXTERNAL_PINFO_VERSION_32_BIT
?
401 strcpy (uname
, pw
->pw_name
);
403 sprintf (uname
, "%u", (unsigned)
404 (p
->version
>= EXTERNAL_PINFO_VERSION_32_BIT
?
407 cmdline
= (char *) cygwin_internal (CW_CMDLINE_ALLOC
, p
->pid
);
408 if (cmdline
) /* Replace \0 with spaces */
412 if ((p
= strchr (p
, '\0')))
419 snprintf (output_buffer
, sizeof output_buffer
, sfmt
,
420 p
->pid
, ttynam (p
->ctty
, ttyname
), start_time (p
), pname
);
424 snprintf (output_buffer
, sizeof output_buffer
, ffmt
,
425 uname
, p
->pid
, p
->ppid
, ttynam (p
->ctty
, ttyname
),
426 start_time (p
), cmdline
?: pname
);
430 snprintf (output_buffer
, sizeof output_buffer
, lfmt
,
431 status
, p
->pid
, p
->ppid
, p
->pgid
,
432 p
->dwProcessId
, ttynam (p
->ctty
, ttyname
),
433 p
->version
>= EXTERNAL_PINFO_VERSION_32_BIT
435 start_time (p
), pname
);
436 ps_print (output_buffer
, width
);
439 cygwin_internal (CW_FREE_DRIVE_MAP
, drive_map
);
440 (void) cygwin_internal (CW_UNLOCK_PINFO
);
442 return found_proc_id
? 0 : 1;