3 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
4 2008, 2009, 2010 Red Hat, Inc.
6 This file is part of Cygwin.
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
21 #include <sys/cygwin.h>
24 #include <ddk/ntapi.h>
25 #include <ddk/winddk.h>
28 /* Maximum possible path length under NT. There's no official define
29 for that value. Note that PATH_MAX is only 4K. */
30 #define NT_MAX_PATH 32768
32 static const char version[] = "$Revision$";
33 static char *prog_name;
35 static struct option longopts[] =
37 {"all", no_argument, NULL, 'a' },
38 {"everyone", no_argument, NULL, 'e' },
39 {"full", no_argument, NULL, 'f' },
40 {"help", no_argument, NULL, 'h' },
41 {"long", no_argument, NULL, 'l' },
42 {"process", required_argument, NULL, 'p'},
43 {"summary", no_argument, NULL, 's' },
44 {"user", required_argument, NULL, 'u'},
45 {"version", no_argument, NULL, 'v'},
46 {"windows", no_argument, NULL, 'W'},
50 static char opts[] = "aefhlp:su:vW";
52 typedef BOOL (WINAPI *ENUMPROCESSMODULES)(
53 HANDLE hProcess, // handle to the process
54 HMODULE * lphModule, // array to receive the module handles
55 DWORD cb, // size of the array
56 LPDWORD lpcbNeeded // receives the number of bytes returned
59 typedef DWORD (WINAPI *GETMODULEFILENAME)(
66 typedef HANDLE (WINAPI *CREATESNAPSHOT)(
72 typedef BOOL (WINAPI *PROCESSWALK)(
77 ENUMPROCESSMODULES myEnumProcessModules;
78 GETMODULEFILENAME myGetModuleFileNameEx;
79 CREATESNAPSHOT myCreateToolhelp32Snapshot;
80 PROCESSWALK myProcess32First;
81 PROCESSWALK myProcess32Next;
83 static BOOL WINAPI dummyprocessmodules (
84 HANDLE hProcess, // handle to the process
85 HMODULE * lphModule, // array to receive the module handles
86 DWORD cb, // size of the array
87 LPDWORD lpcbNeeded // receives the number of bytes returned
90 lphModule[0] = (HMODULE) *lpcbNeeded;
95 static DWORD WINAPI GetModuleFileNameEx95 (
103 DWORD pid = (DWORD) hModule;
105 h = myCreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0);
110 proc.dwSize = sizeof (proc);
111 if (myProcess32First(h, &proc))
113 if (proc.th32ProcessID == pid)
116 strcpy (lpstrFileName, proc.szExeFile);
119 while (myProcess32Next (h, &proc));
127 OSVERSIONINFO os_version_info;
129 memset (&os_version_info, 0, sizeof os_version_info);
130 os_version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
131 GetVersionEx (&os_version_info);
134 if (os_version_info.dwPlatformId == VER_PLATFORM_WIN32_NT)
136 h = LoadLibrary ("psapi.dll");
139 myEnumProcessModules = (ENUMPROCESSMODULES) GetProcAddress (h, "EnumProcessModules");
140 myGetModuleFileNameEx = (GETMODULEFILENAME) GetProcAddress (h, "GetModuleFileNameExA");
141 if (!myEnumProcessModules || !myGetModuleFileNameEx)
146 h = GetModuleHandle("KERNEL32.DLL");
147 myCreateToolhelp32Snapshot = (CREATESNAPSHOT)GetProcAddress (h, "CreateToolhelp32Snapshot");
148 myProcess32First = (PROCESSWALK)GetProcAddress (h, "Process32First");
149 myProcess32Next = (PROCESSWALK)GetProcAddress (h, "Process32Next");
150 if (!myCreateToolhelp32Snapshot || !myProcess32First || !myProcess32Next)
153 myEnumProcessModules = dummyprocessmodules;
154 myGetModuleFileNameEx = GetModuleFileNameEx95;
159 start_time (external_pinfo *child)
161 time_t st = child->start_time;
162 time_t t = time (NULL);
163 static char stime[40] = {'\0'};
166 strncpy (stime, ctime (&st) + 4, 15);
167 strcpy (now, ctime (&t) + 4);
169 if ((t - st) < (24 * 3600))
177 #define FACTOR (0x19db1ded53ea710LL)
178 #define NSPERSEC 10000000LL
180 /* Convert a Win32 time to "UNIX" format. */
182 to_time_t (FILETIME *ptr)
184 /* A file time is the number of 100ns since jan 1 1601
185 stuffed into two long words.
186 A time_t is the number of seconds since jan 1 1970. */
189 long long x = ((long long) ptr->dwHighDateTime << 32) + ((unsigned)ptr->dwLowDateTime);
190 x -= FACTOR; /* number of 100ns between 1601 and 1970 */
191 rem = x % ((long long)NSPERSEC);
192 rem += (NSPERSEC / 2);
193 x /= (long long) NSPERSEC; /* number of 100ns in a second */
194 x += (long long) (rem / NSPERSEC);
204 if (ntty == TTY_CONSOLE)
206 sprintf (buf, "%4d", ntty);
211 usage (FILE * stream, int status)
214 Usage: %s [-aefls] [-u UID] [-p PID]\n\
215 Report process status\n\
217 -a, --all show processes of all users\n\
218 -e, --everyone show processes of all users\n\
219 -f, --full show process uids, ppids\n\
220 -h, --help output usage information and exit\n\
221 -l, --long show process uids, ppids, pgids, winpids\n\
222 -p, --process show information for specified PID\n\
223 -s, --summary show process summary\n\
224 -u, --user list processes owned by UID\n\
225 -v, --version output version information and exit\n\
226 -W, --windows show windows as well as cygwin processes\n\
227 With no options, %s outputs the long format by default\n",
228 prog_name, prog_name);
235 const char *v = strchr (version, ':');
245 len = strchr (v, ' ') - v;
249 Process Statistics\n\
250 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.\n\
252 ", prog_name, len, v, __DATE__);
258 main (int argc, char *argv[])
261 int aflag, lflag, fflag, sflag, uid, proc_id;
262 bool found_proc_id = true;
263 cygwin_getinfo_types query = CW_GETPINFO;
264 const char *dtitle = " PID TTY STIME COMMAND\n";
265 const char *dfmt = "%7d%4s%10s %s\n";
266 const char *ftitle = " UID PID PPID TTY STIME COMMAND\n";
267 const char *ffmt = "%8.8s%8d%8d%4s%10s %s\n";
268 const char *ltitle = " PID PPID PGID WINPID TTY UID STIME COMMAND\n";
269 const char *lfmt = "%c %7d %7d %7d %10u %4s %4u %8s %s\n";
271 PUNICODE_STRING uni = NULL;
273 aflag = lflag = fflag = sflag = 0;
278 prog_name = strrchr (argv[0], '/');
279 if (prog_name == NULL)
280 prog_name = strrchr (argv[0], '\\');
281 if (prog_name == NULL)
286 while ((ch = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
302 proc_id = atoi (optarg);
304 found_proc_id = false;
315 if ((pw = getpwnam (optarg)))
319 fprintf (stderr, "%s: user %s unknown\n", prog_name, optarg);
329 query = CW_GETPINFO_FULL;
344 (void) cygwin_internal (CW_LOCK_PINFO, 1000);
346 if (query == CW_GETPINFO_FULL && !init_win ())
348 if (query == CW_GETPINFO_FULL)
350 /* Enable debug privilege to allow to enumerate all processes,
351 not only processes in current session. */
353 if (OpenProcessToken (GetCurrentProcess (),
354 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
357 TOKEN_PRIVILEGES priv;
359 priv.PrivilegeCount = 1;
360 if (LookupPrivilegeValue (NULL, SE_DEBUG_NAME,
361 &priv.Privileges[0].Luid))
363 priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
364 AdjustTokenPrivileges (tok, FALSE, &priv, 0, NULL, NULL);
370 (p = (external_pinfo *) cygwin_internal (query, pid | CW_NEXTPID));
373 if ((proc_id > 0) && (p->pid != proc_id))
376 found_proc_id = true;
380 else if (p->version >= EXTERNAL_PINFO_VERSION_32_BIT)
382 if (p->uid32 != (__uid32_t) uid)
385 else if (p->uid != uid)
388 if (p->process_state & PID_STOPPED)
390 else if (p->process_state & PID_TTYIN)
392 else if (p->process_state & PID_TTYOU)
395 /* Maximum possible path length under NT. There's no official define
397 char pname[NT_MAX_PATH];
398 if (p->process_state & PID_EXITED || (p->exitcode & ~0xffff))
399 strcpy (pname, "<defunct>");
404 if (p->version >= EXTERNAL_PINFO_VERSION_32_LP)
405 cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE,
406 p->progname_long, pname, NT_MAX_PATH);
408 cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE,
409 p->progname, pname, NT_MAX_PATH);
410 s = strchr (pname, '\0') - 4;
411 if (s > pname && strcasecmp (s, ".exe") == 0)
414 else if (query == CW_GETPINFO_FULL)
416 HANDLE h = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
417 FALSE, p->dwProcessId);
421 DWORD n = p->dwProcessId;
422 if (!myEnumProcessModules (h, hm, sizeof (hm), &n))
424 /* This occurs when trying to enum modules of a 64 bit process.
425 GetModuleFileNameEx with a NULL module will return the same error.
426 Only NtQueryInformationProcess allows to fetch the process image
427 name in that case. */
428 if (!n && GetLastError () == ERROR_PARTIAL_COPY)
433 size_t len = sizeof (UNICODE_STRING) + PATH_MAX * sizeof (WCHAR);
437 uni = (PUNICODE_STRING) alloca (len);
438 QueryDosDevice (NULL, dosdevs, 32000);
440 status = NtQueryInformationProcess (h, ProcessImageFileName, uni,
442 if (NT_SUCCESS (status)
443 && (len = wcsnrtombs (pbuf, (const wchar_t **) &uni->Buffer,
444 uni->Length / sizeof (WCHAR), PATH_MAX,
448 if (!strncmp (pbuf, "\\Device\\Mup\\", 12))
450 strcpy (pname, "\\\\");
451 strcpy (pname + 2, pbuf + 12);
455 strcpy (pname, pbuf);
456 for (char *d = dosdevs; *d; d = strchr (d, '\0') + 1)
457 if (QueryDosDevice (d, dev, 256)
459 && !strncmp (dev, pbuf, strlen (dev)))
462 strcat (pname, pbuf + strlen (dev));
468 strcpy (pname, "*** unknown ***");
470 else if (!n || !myGetModuleFileNameEx (h, hm[0], pname, PATH_MAX))
471 strcpy (pname, "*** unknown ***");
472 FILETIME ct, et, kt, ut;
473 if (GetProcessTimes (h, &ct, &et, &kt, &ut))
474 p->start_time = to_time_t (&ct);
484 if ((pw = getpwuid (p->version >= EXTERNAL_PINFO_VERSION_32_BIT ?
486 strcpy (uname, pw->pw_name);
488 sprintf (uname, "%u", (unsigned)
489 (p->version >= EXTERNAL_PINFO_VERSION_32_BIT ?
494 printf (dfmt, p->pid, ttynam (p->ctty), start_time (p), pname);
496 printf (ffmt, uname, p->pid, p->ppid, ttynam (p->ctty), start_time (p),
499 printf (lfmt, status, p->pid, p->ppid, p->pgid,
500 p->dwProcessId, ttynam (p->ctty),
501 p->version >= EXTERNAL_PINFO_VERSION_32_BIT ? p->uid32 : p->uid,
502 start_time (p), pname);
505 (void) cygwin_internal (CW_UNLOCK_PINFO);
507 return found_proc_id ? 0 : 1;