]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygwin/fhandler_proc.cc
Avoid decimal point localization in /proc/loadavg
[newlib-cygwin.git] / winsup / cygwin / fhandler_proc.cc
CommitLineData
c477dccf
CF
1/* fhandler_proc.cc: fhandler for /proc virtual filesystem
2
c477dccf
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
9#include "winsup.h"
ade47a34 10#include "miscfuncs.h"
c477dccf
CF
11#include <unistd.h>
12#include <stdlib.h>
5f6d028d 13#include <stdio.h>
c477dccf
CF
14#include "cygerrno.h"
15#include "security.h"
c477dccf 16#include "path.h"
f207699a 17#include "shared_info.h"
7ac61736 18#include "fhandler.h"
38f50ae4 19#include "fhandler_virtual.h"
c477dccf 20#include "pinfo.h"
8761c1dc
CF
21#include "dtable.h"
22#include "cygheap.h"
38f50ae4 23#include "tls_pbuf.h"
c477dccf 24#include <sys/utsname.h>
c8bef400 25#include <sys/param.h>
205b8208 26#include <sys/sysinfo.h>
9ba913a5 27#include "ntdll.h"
c367dfd0 28#include <winioctl.h>
e9c8cb31 29#include <wchar.h>
483e9d00 30#include <wctype.h>
c448f78f 31#include "cpuid.h"
a52993d4 32#include "mount.h"
c84697c2 33#include <math.h>
c477dccf
CF
34
35#define _COMPILING_NEWLIB
36#include <dirent.h>
37
61522196
CV
38static off_t format_proc_loadavg (void *, char *&);
39static off_t format_proc_meminfo (void *, char *&);
40static off_t format_proc_stat (void *, char *&);
41static off_t format_proc_version (void *, char *&);
42static off_t format_proc_uptime (void *, char *&);
43static off_t format_proc_cpuinfo (void *, char *&);
44static off_t format_proc_partitions (void *, char *&);
45static off_t format_proc_self (void *, char *&);
f207699a 46static off_t format_proc_cygdrive (void *, char *&);
61522196
CV
47static off_t format_proc_mounts (void *, char *&);
48static off_t format_proc_filesystems (void *, char *&);
49static off_t format_proc_swaps (void *, char *&);
50static off_t format_proc_devices (void *, char *&);
51static off_t format_proc_misc (void *, char *&);
c477dccf
CF
52
53/* names of objects in /proc */
38f50ae4 54static const virt_tab_t proc_tab[] = {
43f65cdd
CV
55 { _VN ("."), FH_PROC, virt_directory, NULL },
56 { _VN (".."), FH_PROC, virt_directory, NULL },
57 { _VN ("cpuinfo"), FH_PROC, virt_file, format_proc_cpuinfo },
f207699a 58 { _VN ("cygdrive"), FH_PROC, virt_symlink, format_proc_cygdrive },
07797cc0 59 { _VN ("devices"), FH_PROC, virt_file, format_proc_devices },
43f65cdd
CV
60 { _VN ("filesystems"), FH_PROC, virt_file, format_proc_filesystems },
61 { _VN ("loadavg"), FH_PROC, virt_file, format_proc_loadavg },
62 { _VN ("meminfo"), FH_PROC, virt_file, format_proc_meminfo },
07797cc0 63 { _VN ("misc"), FH_PROC, virt_file, format_proc_misc },
43f65cdd
CV
64 { _VN ("mounts"), FH_PROC, virt_symlink, format_proc_mounts },
65 { _VN ("net"), FH_PROCNET, virt_directory, NULL },
66 { _VN ("partitions"), FH_PROC, virt_file, format_proc_partitions },
67 { _VN ("registry"), FH_REGISTRY, virt_directory, NULL },
68 { _VN ("registry32"), FH_REGISTRY, virt_directory, NULL },
69 { _VN ("registry64"), FH_REGISTRY, virt_directory, NULL },
70 { _VN ("self"), FH_PROC, virt_symlink, format_proc_self },
71 { _VN ("stat"), FH_PROC, virt_file, format_proc_stat },
5f6d028d 72 { _VN ("swaps"), FH_PROC, virt_file, format_proc_swaps },
43f65cdd 73 { _VN ("sys"), FH_PROCSYS, virt_directory, NULL },
d68288f6 74 { _VN ("sysvipc"), FH_PROCSYSVIPC, virt_directory, NULL },
43f65cdd
CV
75 { _VN ("uptime"), FH_PROC, virt_file, format_proc_uptime },
76 { _VN ("version"), FH_PROC, virt_file, format_proc_version },
c3a9063f 77 { NULL, 0, FH_NADA, virt_none, NULL }
c477dccf
CF
78};
79
214c3a11
CV
80#define PROC_DIR_COUNT 4
81
38f50ae4 82static const int PROC_LINK_COUNT = (sizeof (proc_tab) / sizeof (virt_tab_t)) - 1;
c477dccf
CF
83
84/* name of the /proc filesystem */
85const char proc[] = "/proc";
43f65cdd 86const size_t proc_len = sizeof (proc) - 1;
c477dccf 87
43f65cdd
CV
88/* bsearch compare function. */
89static int
90proc_tab_cmp (const void *key, const void *memb)
91{
92 int ret = strncmp (((virt_tab_t *) key)->name, ((virt_tab_t *) memb)->name,
93 ((virt_tab_t *) memb)->name_len);
94 if (!ret && ((virt_tab_t *) key)->name[((virt_tab_t *) memb)->name_len] != '\0' && ((virt_tab_t *) key)->name[((virt_tab_t *) memb)->name_len] != '/')
95 return 1;
96 return ret;
97}
98
483e9d00 99/* Helper function to perform a binary search of the incoming pathname
43f65cdd
CV
100 against the alpha-sorted virtual file table. */
101virt_tab_t *
102virt_tab_search (const char *path, bool prefix, const virt_tab_t *table,
103 size_t nelem)
104{
c3a9063f 105 virt_tab_t key = { path, 0, FH_NADA, virt_none, NULL };
43f65cdd
CV
106 virt_tab_t *entry = (virt_tab_t *) bsearch (&key, table, nelem,
107 sizeof (virt_tab_t),
108 proc_tab_cmp);
109 if (entry && (path[entry->name_len] == '\0'
110 || (prefix && path[entry->name_len] == '/')))
111 return entry;
112 return NULL;
113}
114
115/* Auxillary function that returns the fhandler associated with the given
116 path. */
44d2fc0a 117fh_devices
c477dccf
CF
118fhandler_proc::get_proc_fhandler (const char *path)
119{
120 debug_printf ("get_proc_fhandler(%s)", path);
121 path += proc_len;
122 /* Since this method is called from path_conv::check we can't rely on
c367dfd0
CF
123 it being normalised and therefore the path may have runs of slashes
124 in it. */
85ba109d 125 while (isdirsep (*path))
c477dccf
CF
126 path++;
127
128 /* Check if this is the root of the virtual filesystem (i.e. /proc). */
129 if (*path == 0)
130 return FH_PROC;
131
43f65cdd
CV
132 virt_tab_t *entry = virt_tab_search (path, true, proc_tab,
133 PROC_LINK_COUNT);
134 if (entry)
135 return entry->fhandler;
c477dccf 136
6e2c5823
CV
137 int pid = atoi (path);
138 pinfo p (pid);
139 /* If p->pid != pid, then pid is actually the Windows PID for an execed
140 Cygwin process, and the pinfo entry is the additional entry created
141 at exec time. We don't want to enable the user to access a process
142 entry by using the Win32 PID, though. */
143 if (p && p->pid == pid)
6b7cd251 144 return FH_PROCESS;
8761c1dc 145
6b7cd251
CF
146 bool has_subdir = false;
147 while (*path)
85ba109d 148 if (isdirsep (*path++))
6b7cd251
CF
149 {
150 has_subdir = true;
151 break;
152 }
8761c1dc 153
6b7cd251
CF
154 if (has_subdir)
155 /* The user is trying to access a non-existent subdirectory of /proc. */
c3a9063f 156 return FH_NADA;
6b7cd251 157 else
fcdca881
CV
158 /* Return FH_PROC so that we can return EROFS if the user is trying to
159 create a file. */
6b7cd251 160 return FH_PROC;
c477dccf
CF
161}
162
163/* Returns 0 if path doesn't exist, >0 if path is a directory,
e8309efd 164 -1 if path is a file, -2 if it's a symlink. */
43f65cdd 165virtual_ftype_t
fc240f58 166fhandler_proc::exists ()
c477dccf 167{
fc240f58 168 const char *path = get_name ();
c477dccf
CF
169 debug_printf ("exists (%s)", path);
170 path += proc_len;
171 if (*path == 0)
38f50ae4 172 return virt_rootdir;
43f65cdd
CV
173 virt_tab_t *entry = virt_tab_search (path + 1, false, proc_tab,
174 PROC_LINK_COUNT);
175 if (entry)
176 {
177 fileid = entry - proc_tab;
178 return entry->type;
179 }
38f50ae4 180 return virt_none;
c477dccf
CF
181}
182
183fhandler_proc::fhandler_proc ():
7ac61736 184 fhandler_virtual ()
c477dccf
CF
185{
186}
187
6e75c72b 188int __reg2
61522196 189fhandler_proc::fstat (struct stat *buf)
c477dccf 190{
c477dccf 191 const char *path = get_name ();
e065a187
CF
192 debug_printf ("fstat (%s)", path);
193
c477dccf 194 path += proc_len;
0c55f6ed 195 fhandler_base::fstat (buf);
c477dccf
CF
196
197 buf->st_mode &= ~_IFMT & NO_W;
198
199 if (!*path)
200 {
214c3a11
CV
201 winpids pids ((DWORD) 0);
202 buf->st_ino = 2;
c477dccf 203 buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
214c3a11 204 buf->st_nlink = PROC_DIR_COUNT + 2 + pids.npids;
c477dccf
CF
205 return 0;
206 }
207 else
208 {
43f65cdd
CV
209 virt_tab_t *entry = virt_tab_search (path + 1, false, proc_tab,
210 PROC_LINK_COUNT);
211 if (entry)
212 {
213 if (entry->type == virt_directory)
214 buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
215 else if (entry->type == virt_symlink)
216 buf->st_mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
217 else
218 {
219 buf->st_mode &= NO_X;
220 buf->st_mode |= S_IFREG;
221 }
222 return 0;
223 }
c477dccf
CF
224 }
225 set_errno (ENOENT);
226 return -1;
227}
228
1f08558f
CV
229DIR *
230fhandler_proc::opendir (int fd)
231{
232 DIR *dir = fhandler_virtual::opendir (fd);
233 if (dir && !(dir->__handle = (void *) new winpids ((DWORD) 0)))
234 {
235 free (dir);
236 dir = NULL;
237 set_errno (ENOMEM);
238 }
239 return dir;
240}
241
242int
243fhandler_proc::closedir (DIR *dir)
244{
ad391746 245 delete (winpids *) dir->__handle;
1f08558f
CV
246 return fhandler_virtual::closedir (dir);
247}
248
d9a22764
CF
249int
250fhandler_proc::readdir (DIR *dir, dirent *de)
c477dccf 251{
d9a22764
CF
252 int res;
253 if (dir->__d_position < PROC_LINK_COUNT)
254 {
54338f16
CV
255 strcpy (de->d_name, proc_tab[dir->__d_position].name);
256 de->d_type = virt_ftype_to_dtype (proc_tab[dir->__d_position].type);
257 dir->__d_position++;
9e5f45ed 258 dir->__flags |= dirent_saw_dot | dirent_saw_dot_dot;
d9a22764
CF
259 res = 0;
260 }
261 else
c477dccf 262 {
1f08558f 263 winpids &pids = *(winpids *) dir->__handle;
c477dccf 264 int found = 0;
d9a22764 265 res = ENMFILE;
c477dccf 266 for (unsigned i = 0; i < pids.npids; i++)
6b7cd251
CF
267 if (found++ == dir->__d_position - PROC_LINK_COUNT)
268 {
d9a22764 269 __small_sprintf (de->d_name, "%d", pids[i]->pid);
54338f16 270 de->d_type = DT_DIR;
6b7cd251 271 dir->__d_position++;
d9a22764
CF
272 res = 0;
273 break;
6b7cd251 274 }
c477dccf
CF
275 }
276
b9aa8149 277 syscall_printf ("%d = readdir(%p, %p) (%s)", res, dir, de, de->d_name);
d9a22764 278 return res;
c477dccf
CF
279}
280
281int
7ac61736 282fhandler_proc::open (int flags, mode_t mode)
c477dccf
CF
283{
284 int proc_file_no = -1;
285
7ac61736 286 int res = fhandler_virtual::open (flags, mode);
c477dccf
CF
287 if (!res)
288 goto out;
289
56551a9b 290 nohandle (true);
74fcdaec 291
c477dccf
CF
292 const char *path;
293
335c87f9 294 path = get_name () + proc_len;
c477dccf
CF
295
296 if (!*path)
297 {
8761c1dc 298 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
2402700d
CF
299 {
300 set_errno (EEXIST);
301 res = 0;
302 goto out;
303 }
8761c1dc 304 else if (flags & O_WRONLY)
2402700d
CF
305 {
306 set_errno (EISDIR);
307 res = 0;
308 goto out;
309 }
c477dccf 310 else
2402700d
CF
311 {
312 flags |= O_DIROPEN;
313 goto success;
314 }
c477dccf
CF
315 }
316
317 proc_file_no = -1;
40255b64
CV
318 for (int i = 0; proc_tab[i].name; i++)
319 if (path_prefix_p (proc_tab[i].name, path + 1, strlen (proc_tab[i].name),
e4b57503 320 false))
c477dccf 321 {
2402700d 322 proc_file_no = i;
40255b64 323 if (proc_tab[i].fhandler != FH_PROC)
2402700d
CF
324 {
325 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
326 {
327 set_errno (EEXIST);
328 res = 0;
329 goto out;
330 }
331 else if (flags & O_WRONLY)
332 {
333 set_errno (EISDIR);
334 res = 0;
335 goto out;
336 }
337 else
338 {
339 flags |= O_DIROPEN;
340 goto success;
341 }
342 }
c477dccf
CF
343 }
344
345 if (proc_file_no == -1)
346 {
8761c1dc 347 if (flags & O_CREAT)
2402700d
CF
348 {
349 set_errno (EROFS);
350 res = 0;
351 goto out;
352 }
c477dccf 353 else
2402700d
CF
354 {
355 set_errno (ENOENT);
356 res = 0;
357 goto out;
358 }
c477dccf 359 }
8761c1dc 360 if (flags & O_WRONLY)
c477dccf
CF
361 {
362 set_errno (EROFS);
363 res = 0;
364 goto out;
365 }
9ba913a5
CF
366
367 fileid = proc_file_no;
74fcdaec
CF
368 if (!fill_filebuf ())
369 {
370 res = 0;
371 goto out;
40255b64 372 }
9ba913a5
CF
373
374 if (flags & O_APPEND)
375 position = filesize;
376 else
377 position = 0;
378
379success:
380 res = 1;
1bc9effd 381 set_flags ((flags & ~O_TEXT) | O_BINARY);
9ba913a5 382 set_open_status ();
9ba913a5 383out:
61522196 384 syscall_printf ("%d = fhandler_proc::open(%y, 0%o)", res, flags, mode);
9ba913a5
CF
385 return res;
386}
387
74fcdaec 388bool
9ba913a5
CF
389fhandler_proc::fill_filebuf ()
390{
40255b64 391 if (fileid < PROC_LINK_COUNT && proc_tab[fileid].format_func)
c477dccf 392 {
38f50ae4 393 filesize = proc_tab[fileid].format_func (NULL, filebuf);
483e9d00
CV
394 if (filesize > 0)
395 return true;
c477dccf 396 }
40255b64
CV
397 return false;
398}
399
61522196 400static off_t
38f50ae4 401format_proc_version (void *, char *&destbuf)
40255b64 402{
a2ef34bf
YS
403 tmp_pathbuf tp;
404 char *buf = tp.c_get ();
405 char *bufptr = buf;
40255b64
CV
406 struct utsname uts_name;
407
408 uname (&uts_name);
a2ef34bf
YS
409 bufptr += __small_sprintf (bufptr, "%s version %s (%s@%s) (%s) %s\n",
410 uts_name.sysname, uts_name.release, USERNAME, HOSTNAME,
411 GCC_VERSION, uts_name.version);
412
413 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
414 memcpy (destbuf, buf, bufptr - buf);
415 return bufptr - buf;
40255b64
CV
416}
417
61522196 418static off_t
38f50ae4 419format_proc_loadavg (void *, char *&destbuf)
40255b64 420{
9ca65531 421 extern int get_process_state (DWORD dwProcessId);
d0a359f6 422 unsigned int running = 0;
9ca65531
YS
423 winpids pids ((DWORD) 0);
424
425 for (unsigned i = 0; i < pids.npids; i++)
426 switch (get_process_state (i)) {
427 case 'O':
428 case 'R':
b86f999a
CF
429 running++;
430 break;
9ca65531
YS
431 }
432
d0a359f6
JT
433 double loadavg[3] = { 0.0, 0.0, 0.0 };
434 getloadavg (loadavg, 3);
435
c84697c2
JT
436#define HUNDRETHS(l) (int)((l - floor(l))*100)
437
7810aa7c 438 destbuf = (char *) crealloc_abort (destbuf, 48);
c84697c2
JT
439 return __small_sprintf (destbuf, "%u.%02u %u.%02u %u.%02u %u/%u\n",
440 (int)loadavg[0], HUNDRETHS(loadavg[0]),
441 (int)loadavg[1], HUNDRETHS(loadavg[1]),
442 (int)loadavg[2], HUNDRETHS(loadavg[2]),
443 running, (unsigned int)pids.npids);
9ba913a5 444}
c477dccf 445
61522196 446static off_t
38f50ae4 447format_proc_meminfo (void *, char *&destbuf)
9ba913a5 448{
205b8208
YS
449 unsigned long long mem_total, mem_free, swap_total, swap_free;
450 struct sysinfo info;
451
452 sysinfo (&info);
453 mem_total = (unsigned long long) info.totalram * info.mem_unit;
454 mem_free = (unsigned long long) info.freeram * info.mem_unit;
455 swap_total = (unsigned long long) info.totalswap * info.mem_unit;
456 swap_free = (unsigned long long) info.freeswap * info.mem_unit;
38f50ae4 457
38f50ae4 458 destbuf = (char *) crealloc_abort (destbuf, 512);
205b8208
YS
459 return sprintf (destbuf, "MemTotal: %10llu kB\n"
460 "MemFree: %10llu kB\n"
461 "HighTotal: 0 kB\n"
462 "HighFree: 0 kB\n"
463 "LowTotal: %10llu kB\n"
464 "LowFree: %10llu kB\n"
465 "SwapTotal: %10llu kB\n"
466 "SwapFree: %10llu kB\n",
467 mem_total >> 10, mem_free >> 10,
468 mem_total >> 10, mem_free >> 10,
469 swap_total >> 10, swap_free >> 10);
9ba913a5
CF
470}
471
61522196 472static off_t
38f50ae4 473format_proc_uptime (void *, char *&destbuf)
9ba913a5
CF
474{
475 unsigned long long uptime = 0ULL, idle_time = 0ULL;
177dc6c7 476 NTSTATUS status;
61522196 477 SYSTEM_TIMEOFDAY_INFORMATION stodi;
962082b9
CV
478 /* Sizeof SYSTEM_PERFORMANCE_INFORMATION on 64 bit systems. It
479 appears to contain some trailing additional information from
480 what I can tell after examining the content.
481 FIXME: It would be nice if this could be verified somehow. */
482 const size_t sizeof_spi = sizeof (SYSTEM_PERFORMANCE_INFORMATION) + 16;
483 PSYSTEM_PERFORMANCE_INFORMATION spi = (PSYSTEM_PERFORMANCE_INFORMATION)
484 alloca (sizeof_spi);
570858c3 485
177dc6c7
CV
486 status = NtQuerySystemInformation (SystemTimeOfDayInformation, &stodi,
487 sizeof stodi, NULL);
488 if (NT_SUCCESS (status))
fcdca881 489 uptime = (stodi.CurrentTime.QuadPart - stodi.BootTime.QuadPart) / 100000ULL;
d8e551a1
CV
490 else
491 debug_printf ("NtQuerySystemInformation(SystemTimeOfDayInformation), "
61522196 492 "status %y", status);
d8e551a1 493
962082b9
CV
494 if (NT_SUCCESS (NtQuerySystemInformation (SystemPerformanceInformation,
495 spi, sizeof_spi, NULL)))
c29e6933 496 idle_time = (spi->IdleTime.QuadPart / wincap.cpu_count ())
962082b9 497 / 100000ULL;
c477dccf 498
38f50ae4 499 destbuf = (char *) crealloc_abort (destbuf, 80);
9ba913a5 500 return __small_sprintf (destbuf, "%U.%02u %U.%02u\n",
2402700d
CF
501 uptime / 100, long (uptime % 100),
502 idle_time / 100, long (idle_time % 100));
9ba913a5
CF
503}
504
61522196 505static off_t
38f50ae4 506format_proc_stat (void *, char *&destbuf)
9ba913a5 507{
9ba913a5 508 unsigned long pages_in = 0UL, pages_out = 0UL, interrupt_count = 0UL,
2402700d 509 context_switches = 0UL, swap_in = 0UL, swap_out = 0UL;
9ba913a5 510 time_t boot_time = 0;
177dc6c7 511 NTSTATUS status;
962082b9
CV
512 /* Sizeof SYSTEM_PERFORMANCE_INFORMATION on 64 bit systems. It
513 appears to contain some trailing additional information from
514 what I can tell after examining the content.
515 FIXME: It would be nice if this could be verified somehow. */
516 const size_t sizeof_spi = sizeof (SYSTEM_PERFORMANCE_INFORMATION) + 16;
517 PSYSTEM_PERFORMANCE_INFORMATION spi = (PSYSTEM_PERFORMANCE_INFORMATION)
518 alloca (sizeof_spi);
61522196 519 SYSTEM_TIMEOFDAY_INFORMATION stodi;
38f50ae4
CV
520 tmp_pathbuf tp;
521
522 char *buf = tp.c_get ();
523 char *eobuf = buf;
524
61522196
CV
525 SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION spt[wincap.cpu_count ()];
526 status = NtQuerySystemInformation (SystemProcessorPerformanceInformation,
527 (PVOID) spt,
177dc6c7
CV
528 sizeof spt[0] * wincap.cpu_count (), NULL);
529 if (!NT_SUCCESS (status))
61522196
CV
530 debug_printf ("NtQuerySystemInformation(SystemProcessorPerformanceInformation), "
531 "status %y", status);
d8e551a1 532 else
9ba913a5 533 {
570858c3 534 unsigned long long user_time = 0ULL, kernel_time = 0ULL, idle_time = 0ULL;
c29e6933 535 for (unsigned long i = 0; i < wincap.cpu_count (); i++)
cf38615c 536 {
570858c3
CV
537 kernel_time += (spt[i].KernelTime.QuadPart - spt[i].IdleTime.QuadPart)
538 * HZ / 10000000ULL;
539 user_time += spt[i].UserTime.QuadPart * HZ / 10000000ULL;
540 idle_time += spt[i].IdleTime.QuadPart * HZ / 10000000ULL;
cf38615c
CF
541 }
542
570858c3
CV
543 eobuf += __small_sprintf (eobuf, "cpu %U %U %U %U\n",
544 user_time, 0ULL, kernel_time, idle_time);
545 user_time = 0ULL, kernel_time = 0ULL, idle_time = 0ULL;
c29e6933 546 for (unsigned long i = 0; i < wincap.cpu_count (); i++)
cf38615c 547 {
570858c3
CV
548 interrupt_count += spt[i].InterruptCount;
549 kernel_time = (spt[i].KernelTime.QuadPart - spt[i].IdleTime.QuadPart) * HZ / 10000000ULL;
550 user_time = spt[i].UserTime.QuadPart * HZ / 10000000ULL;
551 idle_time = spt[i].IdleTime.QuadPart * HZ / 10000000ULL;
552 eobuf += __small_sprintf (eobuf, "cpu%d %U %U %U %U\n", i,
cf38615c 553 user_time, 0ULL, kernel_time, idle_time);
2402700d 554 }
570858c3 555
177dc6c7
CV
556 status = NtQuerySystemInformation (SystemPerformanceInformation,
557 (PVOID) spi, sizeof_spi, NULL);
558 if (!NT_SUCCESS (status))
d8e551a1
CV
559 {
560 debug_printf ("NtQuerySystemInformation(SystemPerformanceInformation)"
61522196 561 ", status %y", status);
962082b9 562 memset (spi, 0, sizeof_spi);
d8e551a1 563 }
177dc6c7
CV
564 status = NtQuerySystemInformation (SystemTimeOfDayInformation,
565 (PVOID) &stodi, sizeof stodi, NULL);
566 if (!NT_SUCCESS (status))
d8e551a1 567 debug_printf ("NtQuerySystemInformation(SystemTimeOfDayInformation), "
61522196 568 "status %y", status);
9ba913a5 569 }
177dc6c7 570 if (!NT_SUCCESS (status))
483e9d00 571 {
177dc6c7 572 __seterrno_from_nt_status (status);
483e9d00
CV
573 return 0;
574 }
d8e551a1 575
962082b9
CV
576 pages_in = spi->PagesRead;
577 pages_out = spi->PagefilePagesWritten + spi->MappedFilePagesWritten;
177dc6c7
CV
578 /* Note: there is no distinction made in this structure between pages read
579 from the page file and pages read from mapped files, but there is such
580 a distinction made when it comes to writing. Goodness knows why. The
581 value of swap_in, then, will obviously be wrong but its our best guess. */
962082b9
CV
582 swap_in = spi->PagesRead;
583 swap_out = spi->PagefilePagesWritten;
584 context_switches = spi->ContextSwitches;
0ff057d5 585 boot_time = to_time_t (&stodi.BootTime);
570858c3 586
cf38615c 587 eobuf += __small_sprintf (eobuf, "page %u %u\n"
2402700d
CF
588 "swap %u %u\n"
589 "intr %u\n"
590 "ctxt %u\n"
591 "btime %u\n",
cf38615c
CF
592 pages_in, pages_out,
593 swap_in, swap_out,
594 interrupt_count,
595 context_switches,
596 boot_time);
38f50ae4
CV
597 destbuf = (char *) crealloc_abort (destbuf, eobuf - buf);
598 memcpy (destbuf, buf, eobuf - buf);
599 return eobuf - buf;
c477dccf 600}
c367dfd0 601
e0d48deb 602#define add_size(p,s) ((p) = ((__typeof__(p))((PBYTE)(p)+(s))))
f5ab5b84 603#define print(x) { bufptr = stpcpy (bufptr, (x)); }
c367dfd0 604
e0d48deb
CV
605static inline uint32_t
606get_msb (uint32_t in)
607{
608 return 32 - __builtin_clz (in);
609}
610
611static inline uint32_t
612mask_bits (uint32_t in)
613{
614 uint32_t bits = get_msb (in) - 1;
615 if (in & (in - 1))
616 ++bits;
617 return bits;
618}
619
61522196 620static off_t
38f50ae4 621format_proc_cpuinfo (void *, char *&destbuf)
c367dfd0 622{
e0d48deb
CV
623 WCHAR cpu_key[128], *cpu_num_p;
624 DWORD orig_affinity_mask = 0;
625 GROUP_AFFINITY orig_group_affinity;
c367dfd0
CF
626 int cpu_number;
627 const int BUFSIZE = 256;
523a66d9
CV
628 union
629 {
630 BYTE b[BUFSIZE];
631 char s[BUFSIZE];
f5ab5b84 632 WCHAR w[BUFSIZE / sizeof (WCHAR)];
523a66d9 633 DWORD d;
5b4e301b 634 uint32_t m[13];
523a66d9 635 } in_buf;
38f50ae4 636 tmp_pathbuf tp;
c367dfd0 637
38f50ae4
CV
638 char *buf = tp.c_get ();
639 char *bufptr = buf;
c367dfd0 640
e0d48deb
CV
641 DWORD lpi_size = NT_MAX_PATH;
642 //WORD num_cpu_groups = 1; /* Pre Windows 7, only one group... */
643 WORD num_cpu_per_group = 64; /* ...and a max of 64 CPUs. */
644
645 if (wincap.has_processor_groups ())
646 {
647 PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX lpi =
648 (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) tp.c_get ();
649 lpi_size = NT_MAX_PATH;
9074b9b8 650 if (!GetLogicalProcessorInformationEx (RelationGroup, lpi, &lpi_size))
e0d48deb
CV
651 lpi = NULL;
652 else
653 {
654 PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX plpi = lpi;
655 for (DWORD size = lpi_size; size > 0;
656 size -= plpi->Size, add_size (plpi, plpi->Size))
657 if (plpi->Relationship == RelationGroup)
658 {
659 //num_cpu_groups = plpi->Group.MaximumGroupCount;
660 num_cpu_per_group
661 = plpi->Group.GroupInfo[0].MaximumProcessorCount;
662 break;
663 }
664 }
665 }
666
667 cpu_num_p = wcpcpy (cpu_key, L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION"
668 "\\System\\CentralProcessor\\");
0cb6fc5d 669 for (cpu_number = 0; ; cpu_number++)
c367dfd0 670 {
e0d48deb 671 __small_swprintf (cpu_num_p, L"%d", cpu_number);
f5ab5b84
CV
672 if (!NT_SUCCESS (RtlCheckRegistryKey (RTL_REGISTRY_ABSOLUTE, cpu_key)))
673 break;
fcdca881 674 if (cpu_number)
8581e92c 675 print ("\n");
fcdca881 676
e0d48deb
CV
677 WORD cpu_group = cpu_number / num_cpu_per_group;
678 KAFFINITY cpu_mask = 1L << (cpu_number % num_cpu_per_group);
679
680 if (wincap.has_processor_groups ())
681 {
682 GROUP_AFFINITY affinity = {
683 .Mask = cpu_mask,
684 .Group = cpu_group,
685 };
686
687 if (!SetThreadGroupAffinity (GetCurrentThread (), &affinity,
688 &orig_group_affinity))
689 system_printf ("SetThreadGroupAffinity(%x,%d (%x/%d)) failed %E", cpu_mask, cpu_group, cpu_number, cpu_number);
690 orig_affinity_mask = 1; /* Just mark success. */
691 }
692 else
693 {
694 orig_affinity_mask = SetThreadAffinityMask (GetCurrentThread (),
695 1 << cpu_number);
696 if (orig_affinity_mask == 0)
697 debug_printf ("SetThreadAffinityMask failed %E");
698 }
f5ab5b84
CV
699 /* I'm not sure whether the thread changes processor immediately
700 and I'm not sure whether this function will cause the thread
701 to be rescheduled */
084ea510 702 yield ();
c367dfd0 703
e0d48deb
CV
704 DWORD cpu_mhz = 0;
705 RTL_QUERY_REGISTRY_TABLE tab[2] = {
706 { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOSTRING,
707 L"~Mhz", &cpu_mhz, REG_NONE, NULL, 0 },
708 { NULL, 0, NULL, NULL, 0, NULL, 0 }
709 };
710
711 RtlQueryRegistryValues (RTL_REGISTRY_ABSOLUTE, cpu_key, tab,
712 NULL, NULL);
713 bufptr += __small_sprintf (bufptr, "processor\t: %d\n", cpu_number);
714 uint32_t maxf, vendor_id[4], unused;
715
716 cpuid (&maxf, &vendor_id[0], &vendor_id[2], &vendor_id[1], 0x00000000);
717 maxf &= 0xffff;
718 vendor_id[3] = 0;
719
720 /* Vendor identification. */
721 bool is_amd = false, is_intel = false;
722 if (!strcmp ((char*)vendor_id, "AuthenticAMD"))
723 is_amd = true;
724 else if (!strcmp ((char*)vendor_id, "GenuineIntel"))
725 is_intel = true;
726
727 bufptr += __small_sprintf (bufptr, "vendor_id\t: %s\n",
728 (char *)vendor_id);
729
730 uint32_t features1, features2, extra_info, cpuid_sig;
731 cpuid (&cpuid_sig, &extra_info, &features2, &features1, 0x00000001);
732 uint32_t family = (cpuid_sig & 0x00000f00) >> 8,
733 model = (cpuid_sig & 0x000000f0) >> 4,
734 stepping = cpuid_sig & 0x0000000f,
735 apic_id = (extra_info & 0xff000000) >> 24;
736 if (family == 15)
737 family += (cpuid_sig >> 20) & 0xff;
738 if (family >= 6)
739 model += ((cpuid_sig >> 16) & 0x0f) << 4;
740
741 uint32_t maxe = 0;
742 cpuid (&maxe, &unused, &unused, &unused, 0x80000000);
743 if (maxe >= 0x80000004)
744 {
745 cpuid (&in_buf.m[0], &in_buf.m[1], &in_buf.m[2],
746 &in_buf.m[3], 0x80000002);
747 cpuid (&in_buf.m[4], &in_buf.m[5], &in_buf.m[6],
748 &in_buf.m[7], 0x80000003);
749 cpuid (&in_buf.m[8], &in_buf.m[9], &in_buf.m[10],
750 &in_buf.m[11], 0x80000004);
751 in_buf.m[12] = 0;
752 }
c367dfd0
CF
753 else
754 {
e0d48deb
CV
755 /* Could implement a lookup table here if someone needs it. */
756 strcpy (in_buf.s, "unknown");
757 }
758 int cache_size = -1,
759 clflush = 64,
760 cache_alignment = 64;
761 if (features1 & (1 << 19)) /* CLFSH */
762 clflush = ((extra_info >> 8) & 0xff) << 3;
763 if (is_intel && family == 15)
764 cache_alignment = clflush * 2;
765 if (is_intel)
766 {
38fd7ddb
CV
767 extern long get_cpu_cache_intel (int sysc, uint32_t maxf);
768 long cs;
e0d48deb 769
38fd7ddb
CV
770 /* As on Linux, don't check for L3 cache. */
771 cs = get_cpu_cache_intel (_SC_LEVEL2_CACHE_SIZE, maxf);
772 if (cs == -1)
c367dfd0 773 {
38fd7ddb
CV
774 cs = get_cpu_cache_intel (_SC_LEVEL1_ICACHE_SIZE, maxf);
775 if (cs != -1)
776 cache_size = cs;
777 cs = get_cpu_cache_intel (_SC_LEVEL1_DCACHE_SIZE, maxf);
778 if (cs != -1)
779 cache_size += cs;
c367dfd0 780 }
38fd7ddb
CV
781 else
782 cache_size = cs;
e0d48deb
CV
783 if (cache_size != -1)
784 cache_size >>= 10;
c367dfd0 785 }
38fd7ddb 786 else if (is_amd)
c367dfd0 787 {
38fd7ddb
CV
788 extern long get_cpu_cache_amd (int sysc, uint32_t maxe);
789 long cs;
f5ab5b84 790
38fd7ddb
CV
791 cs = get_cpu_cache_amd (_SC_LEVEL3_CACHE_SIZE, maxe);
792 if (cs == -1)
793 cs = get_cpu_cache_amd (_SC_LEVEL2_CACHE_SIZE, maxe);
794 if (cs == -1)
795 {
796 cs = get_cpu_cache_amd (_SC_LEVEL1_ICACHE_SIZE, maxe);
797 if (cs != -1)
798 cache_size = cs;
799 cs = get_cpu_cache_amd (_SC_LEVEL1_DCACHE_SIZE, maxe);
800 if (cs != -1)
801 cache_size += cs;
802 }
803 else
804 cache_size = cs;
805 if (cache_size != -1)
806 cache_size >>= 10;
df04ae29 807 }
e0d48deb
CV
808 bufptr += __small_sprintf (bufptr, "cpu family\t: %d\n"
809 "model\t\t: %d\n"
810 "model name\t: %s\n"
811 "stepping\t: %d\n"
812 "cpu MHz\t\t: %d.000\n",
813 family,
814 model,
815 in_buf.s + strspn (in_buf.s, " "),
816 stepping,
817 cpu_mhz);
818
819 if (cache_size >= 0)
820 bufptr += __small_sprintf (bufptr, "cache size\t: %d KB\n",
821 cache_size);
822
823 /* Recognize multi-core CPUs. */
824 if (features1 & (1 << 28)) /* HTT */
c367dfd0 825 {
e0d48deb
CV
826 uint32_t siblings = 0;
827 uint32_t cpu_cores = 0;
828 uint32_t phys_id = 0;
829 uint32_t core_id = 0;
830 uint32_t initial_apic_id = apic_id;
831
832 uint32_t logical_bits = 0; /* # of logical core bits in apicid. */
833 uint32_t ht_bits = 0; /* # of thread bits in apic_id. */
f5ab5b84 834
e0d48deb 835 if (is_intel)
c367dfd0 836 {
e0d48deb
CV
837 bool valid = false;
838 if (maxf >= 0x0000000b) /* topoext supported? */
c367dfd0 839 {
e0d48deb
CV
840 uint32_t bits, logical, level, unused;
841
842 /* Threads */
843 cpuid (&bits, &logical, &level, &unused,
844 0x0000000b, 0x00);
845 /* Even if topoext is supposedly supported, it can return
846 "invalid". */
847 if (bits != 0 && ((level >> 8) & 0xff) == 1)
848 {
849 valid = true;
850 ht_bits = (bits & 0x1f);
851 siblings = (logical & 0xffff);
852 cpu_cores = siblings;
853 for (uint32_t idx = 1; ; ++idx)
854 {
855 cpuid (&bits, &logical, &level, &initial_apic_id,
856 0x0000000b, idx);
857
858 uint32_t level_type = ((level >> 8) & 0xff);
859 if (level_type == 0) /* Invalid */
860 break;
861 if (level_type == 2) /* Core */
862 {
863 logical_bits = (bits & 0x1f);
864 siblings = (logical & 0xffff);
865 cpu_cores = siblings >> ht_bits;
866 break;
867 }
868 }
869 }
c367dfd0 870 }
e0d48deb 871 if (!valid && maxf >= 0x00000004)
8581e92c 872 {
e0d48deb 873 uint32_t apic_reserved;
fcdca881 874
e0d48deb
CV
875 cpuid (&apic_reserved, &unused, &unused, &unused,
876 0x00000004, 0x00);
877 if (apic_reserved & 0x1f)
878 {
879 valid = true;
880 cpu_cores = ((apic_reserved >> 26) & 0x3f) + 1;
881 siblings = (extra_info >> 16) & 0xff;
882 if (siblings <= 1) /* HT could be fused out */
883 {
884 logical_bits = mask_bits (cpu_cores);
885 ht_bits = 0;
886 }
887 else
888 {
889 logical_bits = mask_bits (siblings);
890 ht_bits = mask_bits (siblings / cpu_cores);
891 }
892 }
fcdca881 893 }
e0d48deb 894 if (!valid) /* single core, multi thread */
8581e92c 895 {
e0d48deb
CV
896 cpu_cores = 1;
897 siblings = (extra_info >> 16) & 0xff;
898 logical_bits = mask_bits (siblings);
899 ht_bits = logical_bits;
fcdca881 900 }
e0d48deb
CV
901 }
902 else if (is_amd)
903 {
37b6936f
CV
904 if (maxe >= 0x8000001e)
905 {
906 uint32_t cus, core_info;
907
908 cpuid (&unused, &unused, &core_info, &unused, 0x80000008);
909 cpuid (&unused, &cus, &unused, &unused, 0x8000001e);
910 siblings = (core_info & 0xff) + 1;
911 logical_bits = (core_info >> 12) & 0xf;
912 cus = ((cus >> 8) & 0x3) + 1;
913 ht_bits = mask_bits (cus);
914 cpu_cores = siblings >> ht_bits;
915 }
916 else if (maxe >= 0x80000008)
8581e92c 917 {
5b4e301b 918 uint32_t core_info;
fcdca881 919
e0d48deb 920 cpuid (&unused, &unused, &core_info, &unused, 0x80000008);
37b6936f
CV
921 siblings = (core_info & 0xff) + 1;
922 cpu_cores = siblings;
923 logical_bits = (core_info >> 12) & 0xf;
924 if (!logical_bits)
925 logical_bits = mask_bits (siblings);
926 ht_bits = 0;
fcdca881 927 }
e0d48deb 928 else
8581e92c 929 {
37b6936f
CV
930 siblings = (extra_info >> 16) & 0xff;
931 cpu_cores = siblings;
932 logical_bits = mask_bits (siblings);
933 ht_bits = 0;
fcdca881 934 }
e0d48deb
CV
935 }
936 phys_id = initial_apic_id >> logical_bits;
937 core_id = (initial_apic_id & ((1 << logical_bits) - 1)) >> ht_bits;
938
939 bufptr += __small_sprintf (bufptr, "physical id\t: %d\n", phys_id);
940 if (siblings > 0)
941 bufptr += __small_sprintf (bufptr, "siblings\t: %u\n", siblings);
942 bufptr += __small_sprintf (bufptr, "core id\t\t: %d\n"
943 "cpu cores\t: %d\n",
944 core_id, cpu_cores);
945 if (features1 & (1 << 9)) /* apic */
946 bufptr += __small_sprintf (bufptr, "apicid\t\t: %d\n"
947 "initial apicid\t: %d\n",
948 apic_id, initial_apic_id);
949
950 }
951
952 bufptr += __small_sprintf (bufptr, "fpu\t\t: %s\n"
953 "fpu_exception\t: %s\n"
954 "cpuid level\t: %d\n"
955 "wp\t\t: yes\n",
956 (features1 & (1 << 0)) ? "yes" : "no",
957 (features1 & (1 << 0)) ? "yes" : "no",
958 maxf);
959 print ("flags\t\t:");
960 if (features1 & (1 << 0))
961 print (" fpu");
962 if (features1 & (1 << 1))
963 print (" vme");
964 if (features1 & (1 << 2))
965 print (" de");
966 if (features1 & (1 << 3))
967 print (" pse");
968 if (features1 & (1 << 4))
969 print (" tsc");
970 if (features1 & (1 << 5))
971 print (" msr");
972 if (features1 & (1 << 6))
973 print (" pae");
974 if (features1 & (1 << 7))
975 print (" mce");
976 if (features1 & (1 << 8))
977 print (" cx8");
978 if (features1 & (1 << 9))
979 print (" apic");
980 if (features1 & (1 << 11))
981 print (" sep");
982 if (features1 & (1 << 12))
983 print (" mtrr");
984 if (features1 & (1 << 13))
985 print (" pge");
986 if (features1 & (1 << 14))
987 print (" mca");
988 if (features1 & (1 << 15))
989 print (" cmov");
990 if (features1 & (1 << 16))
991 print (" pat");
992 if (features1 & (1 << 17))
993 print (" pse36");
994 if (features1 & (1 << 18))
995 print (" pn");
996 if (features1 & (1 << 19))
997 print (" clflush");
998 if (is_intel && features1 & (1 << 21))
999 print (" dts");
1000 if (is_intel && features1 & (1 << 22))
1001 print (" acpi");
1002 if (features1 & (1 << 23))
1003 print (" mmx");
1004 if (features1 & (1 << 24))
1005 print (" fxsr");
1006 if (features1 & (1 << 25))
1007 print (" sse");
1008 if (features1 & (1 << 26))
1009 print (" sse2");
1010 if (is_intel && (features1 & (1 << 27)))
1011 print (" ss");
1012 if (features1 & (1 << 28))
1013 print (" ht");
1014 if (is_intel)
1015 {
1016 if (features1 & (1 << 29))
1017 print (" tm");
1018 if (features1 & (1 << 30))
1019 print (" ia64");
1020 if (features1 & (1 << 31))
1021 print (" pbe");
1022 }
1023
1024 if (is_amd && maxe >= 0x80000001)
1025 {
1026 cpuid (&unused, &unused, &unused, &features1, 0x80000001);
1027
1028 if (features1 & (1 << 11))
1029 print (" syscall");
1030 if (features1 & (1 << 19)) /* Huh? Not in AMD64 specs. */
1031 print (" mp");
1032 if (features1 & (1 << 20))
1033 print (" nx");
1034 if (features1 & (1 << 22))
1035 print (" mmxext");
1036 if (features1 & (1 << 25))
1037 print (" fxsr_opt");
1038 if (features1 & (1 << 26))
1039 print (" pdpe1gb");
1040 if (features1 & (1 << 27))
1041 print (" rdtscp");
1042 if (features1 & (1 << 29))
1043 print (" lm");
1044 if (features1 & (1 << 30)) /* 31th bit is on. */
1045 print (" 3dnowext");
1046 if (features1 & (1 << 31)) /* 32th bit (highest) is on. */
1047 print (" 3dnow");
1048 }
fcdca881 1049
e0d48deb
CV
1050 if (features2 & (1 << 0))
1051 print (" pni");
1052 if (is_intel)
1053 {
1054 if (features2 & (1 << 2))
1055 print (" dtes64");
1056 if (features2 & (1 << 3))
1057 print (" monitor");
1058 if (features2 & (1 << 4))
1059 print (" ds_cpl");
1060 if (features2 & (1 << 5))
1061 print (" vmx");
1062 if (features2 & (1 << 6))
1063 print (" smx");
1064 if (features2 & (1 << 7))
1065 print (" est");
1066 if (features2 & (1 << 8))
1067 print (" tm2");
1068 if (features2 & (1 << 9))
1069 print (" ssse3");
1070 if (features2 & (1 << 10))
1071 print (" cid");
1072 if (features2 & (1 << 12))
1073 print (" fma");
1074 }
1075 if (features2 & (1 << 13))
1076 print (" cx16");
1077 if (is_intel)
1078 {
1079 if (features2 & (1 << 14))
1080 print (" xtpr");
1081 if (features2 & (1 << 15))
1082 print (" pdcm");
1083 if (features2 & (1 << 18))
1084 print (" dca");
1085 if (features2 & (1 << 19))
1086 print (" sse4_1");
1087 if (features2 & (1 << 20))
1088 print (" sse4_2");
1089 if (features2 & (1 << 21))
1090 print (" x2apic");
1091 if (features2 & (1 << 22))
1092 print (" movbe");
1093 if (features2 & (1 << 23))
1094 print (" popcnt");
1095 if (features2 & (1 << 25))
1096 print (" aes");
1097 if (features2 & (1 << 26))
1098 print (" xsave");
1099 if (features2 & (1 << 27))
1100 print (" osxsave");
1101 if (features2 & (1 << 28))
1102 print (" avx");
1103 if (features2 & (1 << 29))
1104 print (" f16c");
1105 if (features2 & (1 << 30))
1106 print (" rdrand");
1107 if (features2 & (1 << 31))
1108 print (" hypervisor");
1109 }
1110
1111 if (maxe >= 0x80000001)
1112 {
1113 cpuid (&unused, &unused, &features1, &unused, 0x80000001);
1114
1115 if (features1 & (1 << 0))
1116 print (" lahf_lm");
1117 if (features1 & (1 << 1))
1118 print (" cmp_legacy");
1119 if (is_amd)
1120 {
c367dfd0 1121 if (features1 & (1 << 2))
e0d48deb 1122 print (" svm");
c367dfd0 1123 if (features1 & (1 << 3))
e0d48deb 1124 print (" extapic");
c367dfd0 1125 if (features1 & (1 << 4))
e0d48deb 1126 print (" cr8_legacy");
c367dfd0 1127 if (features1 & (1 << 5))
e0d48deb 1128 print (" abm");
c367dfd0 1129 if (features1 & (1 << 6))
e0d48deb 1130 print (" sse4a");
c367dfd0 1131 if (features1 & (1 << 7))
e0d48deb 1132 print (" misalignsse");
c367dfd0 1133 if (features1 & (1 << 8))
e0d48deb 1134 print (" 3dnowprefetch");
c367dfd0 1135 if (features1 & (1 << 9))
e0d48deb
CV
1136 print (" osvw");
1137 }
1138 if (features1 & (1 << 10))
1139 print (" ibs");
1140 if (is_amd)
1141 {
c367dfd0 1142 if (features1 & (1 << 11))
e0d48deb 1143 print (" sse5");
c367dfd0 1144 if (features1 & (1 << 12))
e0d48deb 1145 print (" skinit");
c367dfd0 1146 if (features1 & (1 << 13))
e0d48deb 1147 print (" wdt");
c367dfd0 1148 if (features1 & (1 << 15))
e0d48deb 1149 print (" lwp");
c367dfd0 1150 if (features1 & (1 << 16))
e0d48deb 1151 print (" fma4");
c367dfd0 1152 if (features1 & (1 << 17))
e0d48deb 1153 print (" tce");
c367dfd0 1154 if (features1 & (1 << 19))
e0d48deb
CV
1155 print (" nodeid_msr");
1156 if (features1 & (1 << 21))
1157 print (" tbm");
1158 if (features1 & (1 << 22))
1159 print (" topoext");
c367dfd0 1160 if (features1 & (1 << 23))
e0d48deb 1161 print (" perfctr_core");
c367dfd0 1162 if (features1 & (1 << 24))
e0d48deb 1163 print (" perfctr_nb");
fcdca881 1164 if (features1 & (1 << 28))
e0d48deb
CV
1165 print (" perfctr_l2");
1166 }
1167 }
1168 if (is_intel) /* features scattered in various CPUID levels. */
1169 {
1170 cpuid (&features1, &unused, &features2, &unused, 0x06);
1171
1172 if (features1 & (1 << 1))
1173 print (" ida");
1174 if (features1 & (1 << 2))
1175 print (" arat");
1176 if (features2 & (1 << 3))
1177 print (" epb");
1178
1179 cpuid (&features2, &unused, &unused, &unused, 0x0d, 1);
1180 if (features2 & (1 << 0))
1181 print (" xsaveopt");
1182
1183 if (features1 & (1 << 4))
1184 print (" pln");
1185 if (features1 & (1 << 6))
1186 print (" pts");
1187 if (features1 & (1 << 0))
1188 print (" dtherm");
1189 }
1190 if (is_intel) /* Extended feature flags */
1191 {
1192 cpuid (&unused, &features1, &unused, &unused, 0x07, 0);
1193
1194 if (features1 & (1 << 0))
1195 print (" fsgsbase");
1196 if (features1 & (1 << 1))
1197 print (" tsc_adjust");
1198 if (features1 & (1 << 3))
1199 print (" bmi1");
1200 if (features1 & (1 << 4))
1201 print (" hle");
1202 if (features1 & (1 << 5))
1203 print (" avx2");
1204 if (features1 & (1 << 7))
1205 print (" smep");
1206 if (features1 & (1 << 8))
1207 print (" bmi2");
1208 if (features1 & (1 << 9))
1209 print (" erms");
1210 if (features1 & (1 << 10))
1211 print (" invpcid");
1212 if (features1 & (1 << 11))
1213 print (" rtm");
1214 if (features1 & (1 << 14))
1215 print (" mpx");
1216 if (features1 & (1 << 16))
1217 print (" avx512f");
1218 if (features1 & (1 << 18))
1219 print (" rdseed");
1220 if (features1 & (1 << 19))
1221 print (" adx");
1222 if (features1 & (1 << 20))
1223 print (" smap");
1224 if (features1 & (1 << 23))
1225 print (" clflushopt");
1226 if (features1 & (1 << 26))
1227 print (" avx512pf");
1228 if (features1 & (1 << 27))
1229 print (" avx512er");
1230 if (features1 & (1 << 28))
1231 print (" avx512cd");
1232 }
fcdca881 1233
e0d48deb 1234 print ("\n");
26462985 1235
e0d48deb 1236 /* TODO: bogomips */
fcdca881 1237
e0d48deb
CV
1238 bufptr += __small_sprintf (bufptr, "clflush size\t: %d\n"
1239 "cache_alignment\t: %d\n",
1240 clflush,
1241 cache_alignment);
fcdca881 1242
e0d48deb
CV
1243 if (maxe >= 0x80000008) /* Address size. */
1244 {
1245 uint32_t addr_size, phys, virt;
1246 cpuid (&addr_size, &unused, &unused, &unused, 0x80000008);
1247
1248 phys = addr_size & 0xff;
1249 virt = (addr_size >> 8) & 0xff;
1250 /* Fix an errata on Intel CPUs */
1251 if (is_intel && family == 15 && model == 3 && stepping == 4)
1252 phys = 36;
1253 bufptr += __small_sprintf (bufptr, "address sizes\t: "
1254 "%u bits physical, "
1255 "%u bits virtual\n",
1256 phys, virt);
1257 }
fcdca881 1258
e0d48deb
CV
1259 if (maxe >= 0x80000007) /* Advanced power management. */
1260 {
1261 cpuid (&unused, &unused, &unused, &features1, 0x80000007);
1262
1263 print ("power management:");
1264 if (features1 & (1 << 0))
1265 print (" ts");
1266 if (features1 & (1 << 1))
1267 print (" fid");
1268 if (features1 & (1 << 2))
1269 print (" vid");
1270 if (features1 & (1 << 3))
1271 print (" ttp");
1272 if (features1 & (1 << 4))
1273 print (" tm");
1274 if (features1 & (1 << 5))
1275 print (" stc");
1276 if (features1 & (1 << 6))
1277 print (" 100mhzsteps");
1278 if (features1 & (1 << 7))
1279 print (" hwpstate");
861a27db
CV
1280 if (features1 & (1 << 9))
1281 print (" cpb");
1282 if (features1 & (1 << 10))
1283 print (" eff_freq_ro");
e0d48deb 1284 }
fcdca881 1285
e0d48deb
CV
1286 if (orig_affinity_mask != 0)
1287 {
1288 if (wincap.has_processor_groups ())
1289 SetThreadGroupAffinity (GetCurrentThread (), &orig_group_affinity,
1290 NULL);
570858c3 1291 else
e0d48deb 1292 SetThreadAffinityMask (GetCurrentThread (), orig_affinity_mask);
c367dfd0 1293 }
f5ab5b84
CV
1294 print ("\n");
1295 }
c367dfd0 1296
38f50ae4
CV
1297 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1298 memcpy (destbuf, buf, bufptr - buf);
1299 return bufptr - buf;
c367dfd0
CF
1300}
1301
61522196 1302static off_t
38f50ae4 1303format_proc_partitions (void *, char *&destbuf)
c367dfd0 1304{
e9c8cb31 1305 OBJECT_ATTRIBUTES attr;
e9c8cb31
CV
1306 IO_STATUS_BLOCK io;
1307 NTSTATUS status;
483e9d00 1308 HANDLE dirhdl;
38f50ae4
CV
1309 tmp_pathbuf tp;
1310
1311 char *buf = tp.c_get ();
1312 char *bufptr = buf;
483e9d00 1313 char *ioctl_buf = tp.c_get ();
a3dfd53a
CV
1314 PWCHAR mp_buf = tp.w_get ();
1315 WCHAR fpath[MAX_PATH];
1316 WCHAR gpath[MAX_PATH];
1317 DWORD len;
e9c8cb31
CV
1318
1319 /* Open \Device object directory. */
86a1bb43 1320 wchar_t wpath[MAX_PATH] = L"\\Device";
e9c8cb31
CV
1321 UNICODE_STRING upath = {14, 16, wpath};
1322 InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL);
1323 status = NtOpenDirectoryObject (&dirhdl, DIRECTORY_QUERY, &attr);
1324 if (!NT_SUCCESS (status))
1325 {
61522196 1326 debug_printf ("NtOpenDirectoryObject, status %y", status);
483e9d00 1327 __seterrno_from_nt_status (status);
38f50ae4 1328 return 0;
e9c8cb31
CV
1329 }
1330
1331 /* Traverse \Device directory ... */
1332 PDIRECTORY_BASIC_INFORMATION dbi = (PDIRECTORY_BASIC_INFORMATION)
1333 alloca (640);
1334 BOOLEAN restart = TRUE;
483e9d00 1335 bool got_one = false;
e9c8cb31
CV
1336 ULONG context = 0;
1337 while (NT_SUCCESS (NtQueryDirectoryObject (dirhdl, dbi, 640, TRUE, restart,
1338 &context, NULL)))
c367dfd0 1339 {
483e9d00
CV
1340 HANDLE devhdl;
1341 PARTITION_INFORMATION_EX *pix = NULL;
1342 PARTITION_INFORMATION *pi = NULL;
1343 DWORD bytes_read;
fc660168 1344 DWORD part_cnt = 0;
483e9d00 1345 unsigned long long size;
483e9d00 1346
e9c8cb31 1347 restart = FALSE;
e9c8cb31 1348 /* ... and check for a "Harddisk[0-9]*" entry. */
8a5e2a62 1349 if (dbi->ObjectName.Length < 9 * sizeof (WCHAR)
483e9d00
CV
1350 || wcsncasecmp (dbi->ObjectName.Buffer, L"Harddisk", 8) != 0
1351 || !iswdigit (dbi->ObjectName.Buffer[8]))
e9c8cb31 1352 continue;
483e9d00
CV
1353 /* Got it. Now construct the path to the entire disk, which is
1354 "\\Device\\HarddiskX\\Partition0", and open the disk with
a3dfd53a 1355 minimum permissions. */
483e9d00
CV
1356 unsigned long drive_num = wcstoul (dbi->ObjectName.Buffer + 8, NULL, 10);
1357 wcscpy (wpath, dbi->ObjectName.Buffer);
1358 PWCHAR wpart = wpath + dbi->ObjectName.Length / sizeof (WCHAR);
a3dfd53a
CV
1359 wcpcpy (wpart, L"\\Partition0");
1360 upath.Length = dbi->ObjectName.Length + 22;
483e9d00
CV
1361 upath.MaximumLength = upath.Length + sizeof (WCHAR);
1362 InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE,
1363 dirhdl, NULL);
61522196
CV
1364 status = NtOpenFile (&devhdl, READ_CONTROL, &attr, &io,
1365 FILE_SHARE_VALID_FLAGS, 0);
483e9d00 1366 if (!NT_SUCCESS (status))
c367dfd0 1367 {
61522196 1368 debug_printf ("NtOpenFile(%S), status %y", &upath, status);
483e9d00
CV
1369 __seterrno_from_nt_status (status);
1370 continue;
1371 }
1372 if (!got_one)
1373 {
a3dfd53a 1374 print ("major minor #blocks name win-mounts\n\n");
483e9d00
CV
1375 got_one = true;
1376 }
1377 /* Fetch partition info for the entire disk to get its size. */
61522196
CV
1378 if (DeviceIoControl (devhdl, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0,
1379 ioctl_buf, NT_MAX_PATH, &bytes_read, NULL))
483e9d00
CV
1380 {
1381 pix = (PARTITION_INFORMATION_EX *) ioctl_buf;
1382 size = pix->PartitionLength.QuadPart;
c367dfd0 1383 }
483e9d00
CV
1384 else if (DeviceIoControl (devhdl, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0,
1385 ioctl_buf, NT_MAX_PATH, &bytes_read, NULL))
1386 {
1387 pi = (PARTITION_INFORMATION *) ioctl_buf;
1388 size = pi->PartitionLength.QuadPart;
1389 }
483e9d00
CV
1390 else
1391 {
1392 debug_printf ("DeviceIoControl (%S, "
1393 "IOCTL_DISK_GET_PARTITION_INFO{_EX}) %E", &upath);
1394 size = 0;
1395 }
b2867a68 1396 device dev (drive_num, 0);
483e9d00 1397 bufptr += __small_sprintf (bufptr, "%5d %5d %9U %s\n",
44d2fc0a 1398 dev.get_major (), dev.get_minor (),
b2867a68 1399 size >> 10, dev.name () + 5);
483e9d00 1400 /* Fetch drive layout info to get size of all partitions on the disk. */
61522196
CV
1401 if (DeviceIoControl (devhdl, IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
1402 NULL, 0, ioctl_buf, NT_MAX_PATH, &bytes_read, NULL))
483e9d00
CV
1403 {
1404 PDRIVE_LAYOUT_INFORMATION_EX pdlix = (PDRIVE_LAYOUT_INFORMATION_EX)
1405 ioctl_buf;
1406 part_cnt = pdlix->PartitionCount;
1407 pix = pdlix->PartitionEntry;
1408 }
1409 else if (DeviceIoControl (devhdl, IOCTL_DISK_GET_DRIVE_LAYOUT,
1410 NULL, 0, ioctl_buf, NT_MAX_PATH, &bytes_read, NULL))
1411 {
1412 PDRIVE_LAYOUT_INFORMATION pdli = (PDRIVE_LAYOUT_INFORMATION) ioctl_buf;
1413 part_cnt = pdli->PartitionCount;
1414 pi = pdli->PartitionEntry;
1415 }
1416 else
1417 debug_printf ("DeviceIoControl(%S, "
1418 "IOCTL_DISK_GET_DRIVE_LAYOUT{_EX}): %E", &upath);
1419 /* Loop over partitions. */
1420 if (pix || pi)
b2867a68 1421 for (DWORD i = 0; i < part_cnt && i < 64; ++i)
483e9d00
CV
1422 {
1423 DWORD part_num;
1424
1425 if (pix)
1426 {
1427 size = pix->PartitionLength.QuadPart;
1428 part_num = pix->PartitionNumber;
1429 ++pix;
1430 }
1431 else
1432 {
1433 size = pi->PartitionLength.QuadPart;
61522196 1434 part_num = pi->PartitionNumber;
483e9d00
CV
1435 ++pi;
1436 }
1437 /* A partition number of 0 denotes an extended partition or a
1438 filler entry as described in fhandler_dev_floppy::lock_partition.
1439 Just skip. */
1440 if (part_num == 0)
1441 continue;
b2867a68 1442 device dev (drive_num, part_num);
a3dfd53a
CV
1443
1444 bufptr += __small_sprintf (bufptr, "%5d %5d %9U %s",
44d2fc0a 1445 dev.get_major (), dev.get_minor (),
b2867a68 1446 size >> 10, dev.name () + 5);
a3dfd53a
CV
1447 /* Check if the partition is mounted in Windows and, if so,
1448 print the mount point list. */
1449 __small_swprintf (fpath,
1450 L"\\\\?\\GLOBALROOT\\Device\\%S\\Partition%u\\",
1451 &dbi->ObjectName, part_num);
1452 if (GetVolumeNameForVolumeMountPointW (fpath, gpath, MAX_PATH)
1453 && GetVolumePathNamesForVolumeNameW (gpath, mp_buf,
1454 NT_MAX_PATH, &len))
1455 {
b2867a68 1456 len = strlen (dev.name () + 5);
a3dfd53a
CV
1457 while (len++ < 6)
1458 *bufptr++ = ' ';
1459 for (PWCHAR p = mp_buf; *p; p = wcschr (p, L'\0') + 1)
1460 bufptr += __small_sprintf (bufptr, " %W", p);
1461 }
1462
1463 *bufptr++ = '\n';
483e9d00
CV
1464 }
1465 NtClose (devhdl);
c367dfd0 1466 }
e9c8cb31
CV
1467 NtClose (dirhdl);
1468
483e9d00
CV
1469 if (!got_one)
1470 return 0;
1471
38f50ae4
CV
1472 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1473 memcpy (destbuf, buf, bufptr - buf);
1474 return bufptr - buf;
c367dfd0
CF
1475}
1476
61522196 1477static off_t
38f50ae4 1478format_proc_self (void *, char *&destbuf)
40255b64 1479{
38f50ae4 1480 destbuf = (char *) crealloc_abort (destbuf, 16);
40255b64
CV
1481 return __small_sprintf (destbuf, "%d", getpid ());
1482}
1483
f207699a
CV
1484static off_t
1485format_proc_cygdrive (void *, char *&destbuf)
1486{
1487 destbuf = (char *) crealloc_abort (destbuf, mount_table->cygdrive_len + 1);
1488 char *dend = stpcpy (destbuf, mount_table->cygdrive);
e91c2f80
CV
1489 if (dend > destbuf + 1) /* cygdrive != "/"? */
1490 *--dend = '\0';
f207699a
CV
1491 return dend - destbuf;
1492}
1493
61522196 1494static off_t
8c71dc58
CV
1495format_proc_mounts (void *, char *&destbuf)
1496{
1497 destbuf = (char *) crealloc_abort (destbuf, sizeof ("self/mounts"));
1498 return __small_sprintf (destbuf, "self/mounts");
1499}
1500
61522196 1501static off_t
a52993d4
CV
1502format_proc_filesystems (void *, char *&destbuf)
1503{
1504 tmp_pathbuf tp;
1505 char *buf = tp.c_get ();
1506 char *bufptr = buf;
1507
1508 /* start at 1 to skip type "none" */
1509 for (int i = 1; fs_names[i].name; i++)
1510 bufptr += __small_sprintf(bufptr, "%s\t%s\n",
b86f999a
CF
1511 fs_names[i].block_device ? "" : "nodev",
1512 fs_names[i].name);
a52993d4
CV
1513
1514 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1515 memcpy (destbuf, buf, bufptr - buf);
1516 return bufptr - buf;
1517}
1518
61522196 1519static off_t
5f6d028d
YS
1520format_proc_swaps (void *, char *&destbuf)
1521{
205b8208 1522 unsigned long long total = 0ULL, used = 0ULL;
5f6d028d
YS
1523 PSYSTEM_PAGEFILE_INFORMATION spi = NULL;
1524 ULONG size = 512;
177dc6c7 1525 NTSTATUS status = STATUS_SUCCESS;
5f6d028d
YS
1526
1527 tmp_pathbuf tp;
1528 char *buf = tp.c_get ();
1529 char *bufptr = buf;
1530
1531 spi = (PSYSTEM_PAGEFILE_INFORMATION) malloc (size);
1532 if (spi)
1533 {
177dc6c7
CV
1534 status = NtQuerySystemInformation (SystemPagefileInformation, (PVOID) spi,
1535 size, &size);
1536 if (status == STATUS_INFO_LENGTH_MISMATCH)
5f6d028d
YS
1537 {
1538 free (spi);
1539 spi = (PSYSTEM_PAGEFILE_INFORMATION) malloc (size);
1540 if (spi)
177dc6c7
CV
1541 status = NtQuerySystemInformation (SystemPagefileInformation,
1542 (PVOID) spi, size, &size);
5f6d028d
YS
1543 }
1544 }
1545
1546 bufptr += __small_sprintf (bufptr,
b86f999a 1547 "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
5f6d028d 1548
177dc6c7 1549 if (spi && NT_SUCCESS (status))
5f6d028d
YS
1550 {
1551 PSYSTEM_PAGEFILE_INFORMATION spp = spi;
3ccae7b6 1552 char *filename = tp.c_get ();
5f6d028d
YS
1553 do
1554 {
177dc6c7
CV
1555 total = (unsigned long long) spp->CurrentSize * wincap.page_size ();
1556 used = (unsigned long long) spp->TotalUsed * wincap.page_size ();
177dc6c7 1557 cygwin_conv_path (CCP_WIN_W_TO_POSIX, spp->FileName.Buffer,
3ccae7b6 1558 filename, NT_MAX_PATH);
205b8208 1559 bufptr += sprintf (bufptr, "%-40s%-16s%-8llu%-8llu%-8d\n",
b86f999a 1560 filename, "file", total >> 10, used >> 10, 0);
5f6d028d
YS
1561 }
1562 while (spp->NextEntryOffset
1563 && (spp = (PSYSTEM_PAGEFILE_INFORMATION)
177dc6c7 1564 ((char *) spp + spp->NextEntryOffset)));
5f6d028d
YS
1565 }
1566
1567 if (spi)
1568 free (spi);
1569
1570 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1571 memcpy (destbuf, buf, bufptr - buf);
1572 return bufptr - buf;
1573}
1574
61522196 1575static off_t
07797cc0
YS
1576format_proc_devices (void *, char *&destbuf)
1577{
1578 tmp_pathbuf tp;
1579 char *buf = tp.c_get ();
1580 char *bufptr = buf;
1581
1582 bufptr += __small_sprintf (bufptr,
1583 "Character devices:\n"
1584 "%3d mem\n"
1585 "%3d cons\n"
1586 "%3d /dev/tty\n"
1587 "%3d /dev/console\n"
1588 "%3d /dev/ptmx\n"
1589 "%3d st\n"
1590 "%3d misc\n"
1591 "%3d sound\n"
1592 "%3d ttyS\n"
1593 "%3d tty\n"
1594 "\n"
1595 "Block devices:\n"
1596 "%3d fd\n"
1597 "%3d sd\n"
1598 "%3d sr\n"
1599 "%3d sd\n"
1600 "%3d sd\n"
1601 "%3d sd\n"
1602 "%3d sd\n"
1603 "%3d sd\n"
1604 "%3d sd\n"
1605 "%3d sd\n",
1606 DEV_MEM_MAJOR, DEV_CONS_MAJOR, _major (FH_TTY),
23771fa1 1607 _major (FH_CONSOLE), _major (FH_PTMX),
07797cc0 1608 DEV_TAPE_MAJOR, DEV_MISC_MAJOR, DEV_SOUND_MAJOR,
38d732a1 1609 DEV_SERIAL_MAJOR, DEV_PTYS_MAJOR, DEV_FLOPPY_MAJOR,
07797cc0
YS
1610 DEV_SD_MAJOR, DEV_CDROM_MAJOR, DEV_SD1_MAJOR,
1611 DEV_SD2_MAJOR, DEV_SD3_MAJOR, DEV_SD4_MAJOR,
1612 DEV_SD5_MAJOR, DEV_SD6_MAJOR, DEV_SD7_MAJOR);
1613
1614 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1615 memcpy (destbuf, buf, bufptr - buf);
1616 return bufptr - buf;
1617}
1618
61522196 1619static off_t
07797cc0
YS
1620format_proc_misc (void *, char *&destbuf)
1621{
1622 tmp_pathbuf tp;
1623 char *buf = tp.c_get ();
1624 char *bufptr = buf;
1625
1626 bufptr += __small_sprintf (bufptr,
1627 "%3d clipboard\n"
1628 "%3d windows\n",
1629 _minor (FH_CLIPBOARD), _minor (FH_WINDOWS));
1630
1631 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1632 memcpy (destbuf, buf, bufptr - buf);
1633 return bufptr - buf;
1634}
1635
c367dfd0 1636#undef print
This page took 0.601653 seconds and 5 git commands to generate.