]> sourceware.org Git - newlib-cygwin.git/blame - winsup/utils/ps.cc
newlib: Add more FreeBSD files for non LDBL_EQ_DBL support
[newlib-cygwin.git] / winsup / utils / ps.cc
CommitLineData
1fd5e000
CF
1/* ps.cc
2
1fd5e000
CF
3This file is part of Cygwin.
4
5This software is a copyrighted work licensed under the terms of the
6Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7details. */
8
92b499ac 9#include <errno.h>
1fd5e000 10#include <stdio.h>
c47ec78d 11#include <locale.h>
46777e0a 12#include <wchar.h>
e73a56e9 13#include <windows.h>
1fd5e000
CF
14#include <time.h>
15#include <getopt.h>
16#include <unistd.h>
17#include <stdlib.h>
18#include <pwd.h>
9408cf38 19#include <limits.h>
1fd5e000 20#include <sys/cygwin.h>
c414e1b9 21#include <sys/ioctl.h>
92b499ac 22#include <cygwin/version.h>
9cfc9511
CV
23#include <ntdef.h>
24#include <ntdll.h>
cc631726 25
2b2b42cf
CV
26/* Maximum possible path length under NT. There's no official define
27 for that value. Note that PATH_MAX is only 4K. */
37a04618 28#define NT_MAX_PATH 32767
2b2b42cf 29
c414e1b9
CV
30#define OUTPUT_BUFSIZ 65536
31
ad39fa8c
CF
32static char *prog_name;
33
34static struct option longopts[] =
35{
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' },
df4f13b7 41 {"process", required_argument, NULL, 'p'},
ad39fa8c
CF
42 {"summary", no_argument, NULL, 's' },
43 {"user", required_argument, NULL, 'u'},
92b499ac 44 {"version", no_argument, NULL, 'V'},
ad39fa8c
CF
45 {"windows", no_argument, NULL, 'W'},
46 {NULL, 0, NULL, 0}
47};
48
92b499ac 49static char opts[] = "aefhlp:su:VW";
ad39fa8c 50
1fd5e000
CF
51static char *
52start_time (external_pinfo *child)
53{
54 time_t st = child->start_time;
55 time_t t = time (NULL);
56 static char stime[40] = {'\0'};
57 char now[40];
58
59 strncpy (stime, ctime (&st) + 4, 15);
60 strcpy (now, ctime (&t) + 4);
61
62 if ((t - st) < (24 * 3600))
63 return (stime + 7);
64
65 stime[6] = '\0';
66
67 return stime;
68}
69
cc631726
CF
70#define FACTOR (0x19db1ded53ea710LL)
71#define NSPERSEC 10000000LL
72
73/* Convert a Win32 time to "UNIX" format. */
30c5411d 74long
cc631726
CF
75to_time_t (FILETIME *ptr)
76{
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. */
80
81 long rem;
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);
88 return x;
89}
90
64c41c76 91static const char *
09981903 92ttynam (int ntty, char buf[9])
64c41c76 93{
a4fddeb9 94 char buf0[9];
09981903 95
64c41c76 96 if (ntty < 0)
a4fddeb9
CF
97 strcpy (buf0, "?");
98 else if (ntty & 0xffff0000)
09981903 99 snprintf (buf0, 9, "cons%d", ntty & 0xff);
a4fddeb9 100 else
09981903
CV
101 snprintf (buf0, 9, "pty%d", ntty);
102 snprintf (buf, 9, " %-7.7s", buf0);
64c41c76
CF
103 return buf;
104}
105
e7fca6f8 106static void __attribute__ ((__noreturn__))
ad39fa8c
CF
107usage (FILE * stream, int status)
108{
109 fprintf (stream, "\
92b499ac
CV
110Usage: %1$s [-aefls] [-u UID] [-p PID]\n\
111\n\
aa275fe0
JDF
112Report process status\n\
113\n\
ad39fa8c
CF
114 -a, --all show processes of all users\n\
115 -e, --everyone show processes of all users\n\
76760707 116 -f, --full show process uids, ppids and command line\n\
ad39fa8c
CF
117 -h, --help output usage information and exit\n\
118 -l, --long show process uids, ppids, pgids, winpids\n\
df4f13b7 119 -p, --process show information for specified PID\n\
ad39fa8c
CF
120 -s, --summary show process summary\n\
121 -u, --user list processes owned by UID\n\
92b499ac 122 -V, --version output version information and exit\n\
ad39fa8c 123 -W, --windows show windows as well as cygwin processes\n\
92b499ac
CV
124\n\
125With no options, %1$s outputs the long format by default\n\n",
126 prog_name);
ad39fa8c
CF
127 exit (status);
128}
129
130static void
131print_version ()
132{
92b499ac 133 printf ("ps (cygwin) %d.%d.%d\n"
1b23b30b 134 "Show process statistics\n"
6e623e93 135 "Copyright (C) 1996 - %s Cygwin Authors\n"
1b23b30b 136 "This is free software; see the source for copying conditions. There is NO\n"
92b499ac 137 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
1b23b30b
CF
138 CYGWIN_VERSION_DLL_MAJOR / 1000,
139 CYGWIN_VERSION_DLL_MAJOR % 1000,
140 CYGWIN_VERSION_DLL_MINOR,
141 strrchr (__DATE__, ' ') + 1);
ad39fa8c
CF
142}
143
37a04618
CV
144struct
145{
146 SYSTEM_PROCESS_ID_INFORMATION spii;
147 WCHAR buf[NT_MAX_PATH + 1];
148} ucbuf;
149
150char pname[NT_MAX_PATH + sizeof (" <defunct>") + 1];
46777e0a 151
c414e1b9
CV
152char output_buffer[OUTPUT_BUFSIZ];
153
154void
155ps_print (const char *string, int width)
156{
157 printf ("%.*s\n", width, string);
158}
159
1fd5e000
CF
160int
161main (int argc, char *argv[])
162{
163 external_pinfo *p;
c414e1b9 164 int aflag, lflag, fflag, sflag, proc_id, width, col;
61522196 165 uid_t uid;
d0e99ecc 166 bool found_proc_id = true;
cc631726 167 cygwin_getinfo_types query = CW_GETPINFO;
c414e1b9
CV
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";
1fd5e000 174 char ch;
1281d5fc 175 void *drive_map = NULL;
23bb2f66 176 time_t boot_time = -1;
c414e1b9
CV
177 char *columns, *end;
178 struct winsize ws;
179
1fd5e000 180
cc631726 181 aflag = lflag = fflag = sflag = 0;
1fd5e000 182 uid = getuid ();
df4f13b7 183 proc_id = -1;
cc631726 184 lflag = 1;
1fd5e000 185
c47ec78d
CV
186 setlocale (LC_ALL, "");
187
92b499ac 188 prog_name = program_invocation_short_name;
ad39fa8c
CF
189
190 while ((ch = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
1fd5e000
CF
191 switch (ch)
192 {
193 case 'a':
194 case 'e':
4bfc614b
CF
195 aflag = 1;
196 break;
1fd5e000 197 case 'f':
4bfc614b 198 fflag = 1;
6d0769ef
CV
199 lflag = 0;
200 sflag = 0;
4bfc614b 201 break;
ad39fa8c 202 case 'h':
4bfc614b 203 usage (stdout, 0);
1fd5e000 204 case 'l':
6d0769ef 205 fflag = 0;
4bfc614b 206 lflag = 1;
6d0769ef 207 sflag = 0;
4bfc614b 208 break;
df4f13b7
CV
209 case 'p':
210 proc_id = atoi (optarg);
32410d21 211 aflag = 1;
d0e99ecc 212 found_proc_id = false;
df4f13b7 213 break;
cc631726 214 case 's':
6d0769ef
CV
215 fflag = 0;
216 lflag = 0;
cc631726
CF
217 sflag = 1;
218 break;
1fd5e000 219 case 'u':
4bfc614b
CF
220 uid = atoi (optarg);
221 if (uid == 0)
222 {
223 struct passwd *pw;
224
225 if ((pw = getpwnam (optarg)))
226 uid = pw->pw_uid;
227 else
228 {
229 fprintf (stderr, "%s: user %s unknown\n", prog_name, optarg);
230 exit (1);
231 }
232 }
233 break;
92b499ac 234 case 'V':
4bfc614b
CF
235 print_version ();
236 exit (0);
237 break;
cc631726
CF
238 case 'W':
239 query = CW_GETPINFO_FULL;
240 aflag = 1;
241 break;
242
1fd5e000 243 default:
92b499ac
CV
244 fprintf (stderr, "Try `%s --help' for more information.\n", prog_name);
245 exit (1);
1fd5e000
CF
246 }
247
1fd5e000
CF
248 (void) cygwin_internal (CW_LOCK_PINFO, 1000);
249
46777e0a
CV
250 if (query == CW_GETPINFO_FULL)
251 {
23bb2f66
BI
252 HANDLE tok;
253 NTSTATUS status;
254 SYSTEM_TIMEOFDAY_INFORMATION stodi;
255
46777e0a
CV
256 /* Enable debug privilege to allow to enumerate all processes,
257 not only processes in current session. */
46777e0a
CV
258 if (OpenProcessToken (GetCurrentProcess (),
259 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
260 &tok))
261 {
262 TOKEN_PRIVILEGES priv;
263
264 priv.PrivilegeCount = 1;
265 if (LookupPrivilegeValue (NULL, SE_DEBUG_NAME,
266 &priv.Privileges[0].Luid))
267 {
268 priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
269 AdjustTokenPrivileges (tok, FALSE, &priv, 0, NULL, NULL);
270 }
271 }
185ad82d 272
7701a023 273 drive_map = (void *) cygwin_internal (CW_ALLOC_DRIVE_MAP);
23bb2f66
BI
274
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))
279 fprintf (stderr,
3b4685bf
CV
280 "NtQuerySystemInformation(SystemTimeOfDayInformation), "
281 "status %#010x\n", (unsigned int) status);
23bb2f66 282 boot_time = to_time_t ((FILETIME*)&stodi.BootTime);
46777e0a 283 }
cc631726 284
c414e1b9
CV
285 width = OUTPUT_BUFSIZ;
286 if ((columns = getenv ("COLUMNS")) && *columns
287 && (col = strtoul (columns, &end, 0)) > 0 && !*end)
288 width = col;
289 else if (isatty (STDOUT_FILENO))
290 {
291 width = 80;
292 if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &ws) != -1)
293 width = ws.ws_col;
294 }
295 if (width > OUTPUT_BUFSIZ)
296 width = OUTPUT_BUFSIZ;
297
298 if (sflag)
299 ps_print (stitle, width);
300 else if (fflag)
301 ps_print (ftitle, width);
302 else if (lflag)
303 ps_print (ltitle, width);
304
1fd5e000 305 for (int pid = 0;
cc631726 306 (p = (external_pinfo *) cygwin_internal (query, pid | CW_NEXTPID));
1fd5e000
CF
307 pid = p->pid)
308 {
df4f13b7
CV
309 if ((proc_id > 0) && (p->pid != proc_id))
310 continue;
d0e99ecc
CF
311 else
312 found_proc_id = true;
df4f13b7 313
a35d9f1a
CF
314 if (aflag)
315 /* nothing to do */;
316 else if (p->version >= EXTERNAL_PINFO_VERSION_32_BIT)
317 {
61522196 318 if (p->uid32 != uid)
a35d9f1a
CF
319 continue;
320 }
321 else if (p->uid != uid)
322 continue;
1fd5e000
CF
323 char status = ' ';
324 if (p->process_state & PID_STOPPED)
4bfc614b 325 status = 'S';
1fd5e000 326 else if (p->process_state & PID_TTYIN)
4bfc614b 327 status = 'I';
1fd5e000 328 else if (p->process_state & PID_TTYOU)
4bfc614b 329 status = 'O';
1fd5e000 330
56a85b9c 331 if (p->ppid)
cc631726
CF
332 {
333 char *s;
0ad10c0f 334 pname[0] = '\0';
c47ec78d 335 strncat (pname, p->progname_long, NT_MAX_PATH);
cc631726
CF
336 s = strchr (pname, '\0') - 4;
337 if (s > pname && strcasecmp (s, ".exe") == 0)
338 *s = '\0';
56a85b9c
CV
339 if (p->process_state & PID_EXITED || (p->exitcode & ~0xffff))
340 strcat (pname, " <defunct>");
cc631726 341 }
185ad82d 342 else if (query == CW_GETPINFO_FULL)
cc631726 343 {
1281d5fc
CV
344 HANDLE h;
345 NTSTATUS status;
346 wchar_t *win32path = NULL;
1def2148 347 FILETIME ct, et, kt, ut;
1281d5fc 348
1def2148
CV
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,
355 NULL);
356 if (NT_SUCCESS (status))
185ad82d 357 {
1def2148
CV
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;
185ad82d 362 }
1281d5fc 363 if (win32path)
37a04618
CV
364 {
365 /* Call CW_MAP_DRIVE_MAP to convert native NT device paths to
1def2148
CV
366 an ordinary Win32 path. The returned pointer points into
367 the incoming buffer given as third argument. */
37a04618
CV
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);
372 }
c47ec78d 373 else
37a04618 374 strcpy (pname, p->dwProcessId == 4 ? "System" : "*** unknown ***");
1def2148
CV
375
376 h = OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION, FALSE,
377 p->dwProcessId);
37a04618
CV
378 if (h)
379 {
380 if (GetProcessTimes (h, &ct, &et, &kt, &ut))
381 p->start_time = to_time_t (&ct);
382 CloseHandle (h);
383 }
23bb2f66 384 /* Default to boot time when process start time inaccessible, 0, -1 */
ee1ad642
BI
385 if (!h || 0 == p->start_time || -1 == p->start_time)
386 {
23bb2f66 387 p->start_time = boot_time;
ee1ad642 388 }
cc631726 389 }
1fd5e000
CF
390
391 char uname[128];
09981903 392 char ttyname[9];
1ce9756e 393 char *cmdline = NULL;
1fd5e000
CF
394
395 if (fflag)
4bfc614b
CF
396 {
397 struct passwd *pw;
398
399 if ((pw = getpwuid (p->version >= EXTERNAL_PINFO_VERSION_32_BIT ?
400 p->uid32 : p->uid)))
401 strcpy (uname, pw->pw_name);
402 else
403 sprintf (uname, "%u", (unsigned)
404 (p->version >= EXTERNAL_PINFO_VERSION_32_BIT ?
50674f2d 405 p->uid32 : p->uid));
1ce9756e
CV
406
407 cmdline = (char *) cygwin_internal (CW_CMDLINE_ALLOC, p->pid);
408 if (cmdline) /* Replace \0 with spaces */
409 {
410 char *p = cmdline;
411 while (p && *p)
412 if ((p = strchr (p, '\0')))
413 *p++ = ' ';
414 }
4bfc614b 415 }
1fd5e000 416
cc631726 417 if (sflag)
c414e1b9
CV
418 {
419 snprintf (output_buffer, sizeof output_buffer, sfmt,
420 p->pid, ttynam (p->ctty, ttyname), start_time (p), pname);
421 }
1fd5e000 422 else if (fflag)
1ce9756e 423 {
c414e1b9
CV
424 snprintf (output_buffer, sizeof output_buffer, ffmt,
425 uname, p->pid, p->ppid, ttynam (p->ctty, ttyname),
426 start_time (p), cmdline ?: pname);
1ce9756e
CV
427 free (cmdline);
428 }
cc631726 429 else if (lflag)
c414e1b9
CV
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
434 ? p->uid32 : p->uid,
435 start_time (p), pname);
436 ps_print (output_buffer, width);
1fd5e000 437 }
1281d5fc
CV
438 if (drive_map)
439 cygwin_internal (CW_FREE_DRIVE_MAP, drive_map);
1fd5e000
CF
440 (void) cygwin_internal (CW_UNLOCK_PINFO);
441
d0e99ecc 442 return found_proc_id ? 0 : 1;
1fd5e000 443}
This page took 0.405458 seconds and 6 git commands to generate.