]> sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/fhandler_proc.cc
Avoid decimal point localization in /proc/loadavg
[newlib-cygwin.git] / winsup / cygwin / fhandler_proc.cc
1 /* fhandler_proc.cc: fhandler for /proc virtual filesystem
2
3 This file is part of Cygwin.
4
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7 details. */
8
9 #include "winsup.h"
10 #include "miscfuncs.h"
11 #include <unistd.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include "cygerrno.h"
15 #include "security.h"
16 #include "path.h"
17 #include "shared_info.h"
18 #include "fhandler.h"
19 #include "fhandler_virtual.h"
20 #include "pinfo.h"
21 #include "dtable.h"
22 #include "cygheap.h"
23 #include "tls_pbuf.h"
24 #include <sys/utsname.h>
25 #include <sys/param.h>
26 #include <sys/sysinfo.h>
27 #include "ntdll.h"
28 #include <winioctl.h>
29 #include <wchar.h>
30 #include <wctype.h>
31 #include "cpuid.h"
32 #include "mount.h"
33 #include <math.h>
34
35 #define _COMPILING_NEWLIB
36 #include <dirent.h>
37
38 static off_t format_proc_loadavg (void *, char *&);
39 static off_t format_proc_meminfo (void *, char *&);
40 static off_t format_proc_stat (void *, char *&);
41 static off_t format_proc_version (void *, char *&);
42 static off_t format_proc_uptime (void *, char *&);
43 static off_t format_proc_cpuinfo (void *, char *&);
44 static off_t format_proc_partitions (void *, char *&);
45 static off_t format_proc_self (void *, char *&);
46 static off_t format_proc_cygdrive (void *, char *&);
47 static off_t format_proc_mounts (void *, char *&);
48 static off_t format_proc_filesystems (void *, char *&);
49 static off_t format_proc_swaps (void *, char *&);
50 static off_t format_proc_devices (void *, char *&);
51 static off_t format_proc_misc (void *, char *&);
52
53 /* names of objects in /proc */
54 static const virt_tab_t proc_tab[] = {
55 { _VN ("."), FH_PROC, virt_directory, NULL },
56 { _VN (".."), FH_PROC, virt_directory, NULL },
57 { _VN ("cpuinfo"), FH_PROC, virt_file, format_proc_cpuinfo },
58 { _VN ("cygdrive"), FH_PROC, virt_symlink, format_proc_cygdrive },
59 { _VN ("devices"), FH_PROC, virt_file, format_proc_devices },
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 },
63 { _VN ("misc"), FH_PROC, virt_file, format_proc_misc },
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 },
72 { _VN ("swaps"), FH_PROC, virt_file, format_proc_swaps },
73 { _VN ("sys"), FH_PROCSYS, virt_directory, NULL },
74 { _VN ("sysvipc"), FH_PROCSYSVIPC, virt_directory, NULL },
75 { _VN ("uptime"), FH_PROC, virt_file, format_proc_uptime },
76 { _VN ("version"), FH_PROC, virt_file, format_proc_version },
77 { NULL, 0, FH_NADA, virt_none, NULL }
78 };
79
80 #define PROC_DIR_COUNT 4
81
82 static const int PROC_LINK_COUNT = (sizeof (proc_tab) / sizeof (virt_tab_t)) - 1;
83
84 /* name of the /proc filesystem */
85 const char proc[] = "/proc";
86 const size_t proc_len = sizeof (proc) - 1;
87
88 /* bsearch compare function. */
89 static int
90 proc_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
99 /* Helper function to perform a binary search of the incoming pathname
100 against the alpha-sorted virtual file table. */
101 virt_tab_t *
102 virt_tab_search (const char *path, bool prefix, const virt_tab_t *table,
103 size_t nelem)
104 {
105 virt_tab_t key = { path, 0, FH_NADA, virt_none, NULL };
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. */
117 fh_devices
118 fhandler_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
123 it being normalised and therefore the path may have runs of slashes
124 in it. */
125 while (isdirsep (*path))
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
132 virt_tab_t *entry = virt_tab_search (path, true, proc_tab,
133 PROC_LINK_COUNT);
134 if (entry)
135 return entry->fhandler;
136
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)
144 return FH_PROCESS;
145
146 bool has_subdir = false;
147 while (*path)
148 if (isdirsep (*path++))
149 {
150 has_subdir = true;
151 break;
152 }
153
154 if (has_subdir)
155 /* The user is trying to access a non-existent subdirectory of /proc. */
156 return FH_NADA;
157 else
158 /* Return FH_PROC so that we can return EROFS if the user is trying to
159 create a file. */
160 return FH_PROC;
161 }
162
163 /* Returns 0 if path doesn't exist, >0 if path is a directory,
164 -1 if path is a file, -2 if it's a symlink. */
165 virtual_ftype_t
166 fhandler_proc::exists ()
167 {
168 const char *path = get_name ();
169 debug_printf ("exists (%s)", path);
170 path += proc_len;
171 if (*path == 0)
172 return virt_rootdir;
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 }
180 return virt_none;
181 }
182
183 fhandler_proc::fhandler_proc ():
184 fhandler_virtual ()
185 {
186 }
187
188 int __reg2
189 fhandler_proc::fstat (struct stat *buf)
190 {
191 const char *path = get_name ();
192 debug_printf ("fstat (%s)", path);
193
194 path += proc_len;
195 fhandler_base::fstat (buf);
196
197 buf->st_mode &= ~_IFMT & NO_W;
198
199 if (!*path)
200 {
201 winpids pids ((DWORD) 0);
202 buf->st_ino = 2;
203 buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
204 buf->st_nlink = PROC_DIR_COUNT + 2 + pids.npids;
205 return 0;
206 }
207 else
208 {
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 }
224 }
225 set_errno (ENOENT);
226 return -1;
227 }
228
229 DIR *
230 fhandler_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
242 int
243 fhandler_proc::closedir (DIR *dir)
244 {
245 delete (winpids *) dir->__handle;
246 return fhandler_virtual::closedir (dir);
247 }
248
249 int
250 fhandler_proc::readdir (DIR *dir, dirent *de)
251 {
252 int res;
253 if (dir->__d_position < PROC_LINK_COUNT)
254 {
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++;
258 dir->__flags |= dirent_saw_dot | dirent_saw_dot_dot;
259 res = 0;
260 }
261 else
262 {
263 winpids &pids = *(winpids *) dir->__handle;
264 int found = 0;
265 res = ENMFILE;
266 for (unsigned i = 0; i < pids.npids; i++)
267 if (found++ == dir->__d_position - PROC_LINK_COUNT)
268 {
269 __small_sprintf (de->d_name, "%d", pids[i]->pid);
270 de->d_type = DT_DIR;
271 dir->__d_position++;
272 res = 0;
273 break;
274 }
275 }
276
277 syscall_printf ("%d = readdir(%p, %p) (%s)", res, dir, de, de->d_name);
278 return res;
279 }
280
281 int
282 fhandler_proc::open (int flags, mode_t mode)
283 {
284 int proc_file_no = -1;
285
286 int res = fhandler_virtual::open (flags, mode);
287 if (!res)
288 goto out;
289
290 nohandle (true);
291
292 const char *path;
293
294 path = get_name () + proc_len;
295
296 if (!*path)
297 {
298 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
299 {
300 set_errno (EEXIST);
301 res = 0;
302 goto out;
303 }
304 else if (flags & O_WRONLY)
305 {
306 set_errno (EISDIR);
307 res = 0;
308 goto out;
309 }
310 else
311 {
312 flags |= O_DIROPEN;
313 goto success;
314 }
315 }
316
317 proc_file_no = -1;
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),
320 false))
321 {
322 proc_file_no = i;
323 if (proc_tab[i].fhandler != FH_PROC)
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 }
343 }
344
345 if (proc_file_no == -1)
346 {
347 if (flags & O_CREAT)
348 {
349 set_errno (EROFS);
350 res = 0;
351 goto out;
352 }
353 else
354 {
355 set_errno (ENOENT);
356 res = 0;
357 goto out;
358 }
359 }
360 if (flags & O_WRONLY)
361 {
362 set_errno (EROFS);
363 res = 0;
364 goto out;
365 }
366
367 fileid = proc_file_no;
368 if (!fill_filebuf ())
369 {
370 res = 0;
371 goto out;
372 }
373
374 if (flags & O_APPEND)
375 position = filesize;
376 else
377 position = 0;
378
379 success:
380 res = 1;
381 set_flags ((flags & ~O_TEXT) | O_BINARY);
382 set_open_status ();
383 out:
384 syscall_printf ("%d = fhandler_proc::open(%y, 0%o)", res, flags, mode);
385 return res;
386 }
387
388 bool
389 fhandler_proc::fill_filebuf ()
390 {
391 if (fileid < PROC_LINK_COUNT && proc_tab[fileid].format_func)
392 {
393 filesize = proc_tab[fileid].format_func (NULL, filebuf);
394 if (filesize > 0)
395 return true;
396 }
397 return false;
398 }
399
400 static off_t
401 format_proc_version (void *, char *&destbuf)
402 {
403 tmp_pathbuf tp;
404 char *buf = tp.c_get ();
405 char *bufptr = buf;
406 struct utsname uts_name;
407
408 uname (&uts_name);
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;
416 }
417
418 static off_t
419 format_proc_loadavg (void *, char *&destbuf)
420 {
421 extern int get_process_state (DWORD dwProcessId);
422 unsigned int running = 0;
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':
429 running++;
430 break;
431 }
432
433 double loadavg[3] = { 0.0, 0.0, 0.0 };
434 getloadavg (loadavg, 3);
435
436 #define HUNDRETHS(l) (int)((l - floor(l))*100)
437
438 destbuf = (char *) crealloc_abort (destbuf, 48);
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);
444 }
445
446 static off_t
447 format_proc_meminfo (void *, char *&destbuf)
448 {
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;
457
458 destbuf = (char *) crealloc_abort (destbuf, 512);
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);
470 }
471
472 static off_t
473 format_proc_uptime (void *, char *&destbuf)
474 {
475 unsigned long long uptime = 0ULL, idle_time = 0ULL;
476 NTSTATUS status;
477 SYSTEM_TIMEOFDAY_INFORMATION stodi;
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);
485
486 status = NtQuerySystemInformation (SystemTimeOfDayInformation, &stodi,
487 sizeof stodi, NULL);
488 if (NT_SUCCESS (status))
489 uptime = (stodi.CurrentTime.QuadPart - stodi.BootTime.QuadPart) / 100000ULL;
490 else
491 debug_printf ("NtQuerySystemInformation(SystemTimeOfDayInformation), "
492 "status %y", status);
493
494 if (NT_SUCCESS (NtQuerySystemInformation (SystemPerformanceInformation,
495 spi, sizeof_spi, NULL)))
496 idle_time = (spi->IdleTime.QuadPart / wincap.cpu_count ())
497 / 100000ULL;
498
499 destbuf = (char *) crealloc_abort (destbuf, 80);
500 return __small_sprintf (destbuf, "%U.%02u %U.%02u\n",
501 uptime / 100, long (uptime % 100),
502 idle_time / 100, long (idle_time % 100));
503 }
504
505 static off_t
506 format_proc_stat (void *, char *&destbuf)
507 {
508 unsigned long pages_in = 0UL, pages_out = 0UL, interrupt_count = 0UL,
509 context_switches = 0UL, swap_in = 0UL, swap_out = 0UL;
510 time_t boot_time = 0;
511 NTSTATUS status;
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);
519 SYSTEM_TIMEOFDAY_INFORMATION stodi;
520 tmp_pathbuf tp;
521
522 char *buf = tp.c_get ();
523 char *eobuf = buf;
524
525 SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION spt[wincap.cpu_count ()];
526 status = NtQuerySystemInformation (SystemProcessorPerformanceInformation,
527 (PVOID) spt,
528 sizeof spt[0] * wincap.cpu_count (), NULL);
529 if (!NT_SUCCESS (status))
530 debug_printf ("NtQuerySystemInformation(SystemProcessorPerformanceInformation), "
531 "status %y", status);
532 else
533 {
534 unsigned long long user_time = 0ULL, kernel_time = 0ULL, idle_time = 0ULL;
535 for (unsigned long i = 0; i < wincap.cpu_count (); i++)
536 {
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;
541 }
542
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;
546 for (unsigned long i = 0; i < wincap.cpu_count (); i++)
547 {
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,
553 user_time, 0ULL, kernel_time, idle_time);
554 }
555
556 status = NtQuerySystemInformation (SystemPerformanceInformation,
557 (PVOID) spi, sizeof_spi, NULL);
558 if (!NT_SUCCESS (status))
559 {
560 debug_printf ("NtQuerySystemInformation(SystemPerformanceInformation)"
561 ", status %y", status);
562 memset (spi, 0, sizeof_spi);
563 }
564 status = NtQuerySystemInformation (SystemTimeOfDayInformation,
565 (PVOID) &stodi, sizeof stodi, NULL);
566 if (!NT_SUCCESS (status))
567 debug_printf ("NtQuerySystemInformation(SystemTimeOfDayInformation), "
568 "status %y", status);
569 }
570 if (!NT_SUCCESS (status))
571 {
572 __seterrno_from_nt_status (status);
573 return 0;
574 }
575
576 pages_in = spi->PagesRead;
577 pages_out = spi->PagefilePagesWritten + spi->MappedFilePagesWritten;
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. */
582 swap_in = spi->PagesRead;
583 swap_out = spi->PagefilePagesWritten;
584 context_switches = spi->ContextSwitches;
585 boot_time = to_time_t (&stodi.BootTime);
586
587 eobuf += __small_sprintf (eobuf, "page %u %u\n"
588 "swap %u %u\n"
589 "intr %u\n"
590 "ctxt %u\n"
591 "btime %u\n",
592 pages_in, pages_out,
593 swap_in, swap_out,
594 interrupt_count,
595 context_switches,
596 boot_time);
597 destbuf = (char *) crealloc_abort (destbuf, eobuf - buf);
598 memcpy (destbuf, buf, eobuf - buf);
599 return eobuf - buf;
600 }
601
602 #define add_size(p,s) ((p) = ((__typeof__(p))((PBYTE)(p)+(s))))
603 #define print(x) { bufptr = stpcpy (bufptr, (x)); }
604
605 static inline uint32_t
606 get_msb (uint32_t in)
607 {
608 return 32 - __builtin_clz (in);
609 }
610
611 static inline uint32_t
612 mask_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
620 static off_t
621 format_proc_cpuinfo (void *, char *&destbuf)
622 {
623 WCHAR cpu_key[128], *cpu_num_p;
624 DWORD orig_affinity_mask = 0;
625 GROUP_AFFINITY orig_group_affinity;
626 int cpu_number;
627 const int BUFSIZE = 256;
628 union
629 {
630 BYTE b[BUFSIZE];
631 char s[BUFSIZE];
632 WCHAR w[BUFSIZE / sizeof (WCHAR)];
633 DWORD d;
634 uint32_t m[13];
635 } in_buf;
636 tmp_pathbuf tp;
637
638 char *buf = tp.c_get ();
639 char *bufptr = buf;
640
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;
650 if (!GetLogicalProcessorInformationEx (RelationGroup, lpi, &lpi_size))
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\\");
669 for (cpu_number = 0; ; cpu_number++)
670 {
671 __small_swprintf (cpu_num_p, L"%d", cpu_number);
672 if (!NT_SUCCESS (RtlCheckRegistryKey (RTL_REGISTRY_ABSOLUTE, cpu_key)))
673 break;
674 if (cpu_number)
675 print ("\n");
676
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 }
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 */
702 yield ();
703
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 }
753 else
754 {
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 {
767 extern long get_cpu_cache_intel (int sysc, uint32_t maxf);
768 long cs;
769
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)
773 {
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;
780 }
781 else
782 cache_size = cs;
783 if (cache_size != -1)
784 cache_size >>= 10;
785 }
786 else if (is_amd)
787 {
788 extern long get_cpu_cache_amd (int sysc, uint32_t maxe);
789 long cs;
790
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;
807 }
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 */
825 {
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. */
834
835 if (is_intel)
836 {
837 bool valid = false;
838 if (maxf >= 0x0000000b) /* topoext supported? */
839 {
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 }
870 }
871 if (!valid && maxf >= 0x00000004)
872 {
873 uint32_t apic_reserved;
874
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 }
893 }
894 if (!valid) /* single core, multi thread */
895 {
896 cpu_cores = 1;
897 siblings = (extra_info >> 16) & 0xff;
898 logical_bits = mask_bits (siblings);
899 ht_bits = logical_bits;
900 }
901 }
902 else if (is_amd)
903 {
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)
917 {
918 uint32_t core_info;
919
920 cpuid (&unused, &unused, &core_info, &unused, 0x80000008);
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;
927 }
928 else
929 {
930 siblings = (extra_info >> 16) & 0xff;
931 cpu_cores = siblings;
932 logical_bits = mask_bits (siblings);
933 ht_bits = 0;
934 }
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 }
1049
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 {
1121 if (features1 & (1 << 2))
1122 print (" svm");
1123 if (features1 & (1 << 3))
1124 print (" extapic");
1125 if (features1 & (1 << 4))
1126 print (" cr8_legacy");
1127 if (features1 & (1 << 5))
1128 print (" abm");
1129 if (features1 & (1 << 6))
1130 print (" sse4a");
1131 if (features1 & (1 << 7))
1132 print (" misalignsse");
1133 if (features1 & (1 << 8))
1134 print (" 3dnowprefetch");
1135 if (features1 & (1 << 9))
1136 print (" osvw");
1137 }
1138 if (features1 & (1 << 10))
1139 print (" ibs");
1140 if (is_amd)
1141 {
1142 if (features1 & (1 << 11))
1143 print (" sse5");
1144 if (features1 & (1 << 12))
1145 print (" skinit");
1146 if (features1 & (1 << 13))
1147 print (" wdt");
1148 if (features1 & (1 << 15))
1149 print (" lwp");
1150 if (features1 & (1 << 16))
1151 print (" fma4");
1152 if (features1 & (1 << 17))
1153 print (" tce");
1154 if (features1 & (1 << 19))
1155 print (" nodeid_msr");
1156 if (features1 & (1 << 21))
1157 print (" tbm");
1158 if (features1 & (1 << 22))
1159 print (" topoext");
1160 if (features1 & (1 << 23))
1161 print (" perfctr_core");
1162 if (features1 & (1 << 24))
1163 print (" perfctr_nb");
1164 if (features1 & (1 << 28))
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 }
1233
1234 print ("\n");
1235
1236 /* TODO: bogomips */
1237
1238 bufptr += __small_sprintf (bufptr, "clflush size\t: %d\n"
1239 "cache_alignment\t: %d\n",
1240 clflush,
1241 cache_alignment);
1242
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 }
1258
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");
1280 if (features1 & (1 << 9))
1281 print (" cpb");
1282 if (features1 & (1 << 10))
1283 print (" eff_freq_ro");
1284 }
1285
1286 if (orig_affinity_mask != 0)
1287 {
1288 if (wincap.has_processor_groups ())
1289 SetThreadGroupAffinity (GetCurrentThread (), &orig_group_affinity,
1290 NULL);
1291 else
1292 SetThreadAffinityMask (GetCurrentThread (), orig_affinity_mask);
1293 }
1294 print ("\n");
1295 }
1296
1297 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1298 memcpy (destbuf, buf, bufptr - buf);
1299 return bufptr - buf;
1300 }
1301
1302 static off_t
1303 format_proc_partitions (void *, char *&destbuf)
1304 {
1305 OBJECT_ATTRIBUTES attr;
1306 IO_STATUS_BLOCK io;
1307 NTSTATUS status;
1308 HANDLE dirhdl;
1309 tmp_pathbuf tp;
1310
1311 char *buf = tp.c_get ();
1312 char *bufptr = buf;
1313 char *ioctl_buf = tp.c_get ();
1314 PWCHAR mp_buf = tp.w_get ();
1315 WCHAR fpath[MAX_PATH];
1316 WCHAR gpath[MAX_PATH];
1317 DWORD len;
1318
1319 /* Open \Device object directory. */
1320 wchar_t wpath[MAX_PATH] = L"\\Device";
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 {
1326 debug_printf ("NtOpenDirectoryObject, status %y", status);
1327 __seterrno_from_nt_status (status);
1328 return 0;
1329 }
1330
1331 /* Traverse \Device directory ... */
1332 PDIRECTORY_BASIC_INFORMATION dbi = (PDIRECTORY_BASIC_INFORMATION)
1333 alloca (640);
1334 BOOLEAN restart = TRUE;
1335 bool got_one = false;
1336 ULONG context = 0;
1337 while (NT_SUCCESS (NtQueryDirectoryObject (dirhdl, dbi, 640, TRUE, restart,
1338 &context, NULL)))
1339 {
1340 HANDLE devhdl;
1341 PARTITION_INFORMATION_EX *pix = NULL;
1342 PARTITION_INFORMATION *pi = NULL;
1343 DWORD bytes_read;
1344 DWORD part_cnt = 0;
1345 unsigned long long size;
1346
1347 restart = FALSE;
1348 /* ... and check for a "Harddisk[0-9]*" entry. */
1349 if (dbi->ObjectName.Length < 9 * sizeof (WCHAR)
1350 || wcsncasecmp (dbi->ObjectName.Buffer, L"Harddisk", 8) != 0
1351 || !iswdigit (dbi->ObjectName.Buffer[8]))
1352 continue;
1353 /* Got it. Now construct the path to the entire disk, which is
1354 "\\Device\\HarddiskX\\Partition0", and open the disk with
1355 minimum permissions. */
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);
1359 wcpcpy (wpart, L"\\Partition0");
1360 upath.Length = dbi->ObjectName.Length + 22;
1361 upath.MaximumLength = upath.Length + sizeof (WCHAR);
1362 InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE,
1363 dirhdl, NULL);
1364 status = NtOpenFile (&devhdl, READ_CONTROL, &attr, &io,
1365 FILE_SHARE_VALID_FLAGS, 0);
1366 if (!NT_SUCCESS (status))
1367 {
1368 debug_printf ("NtOpenFile(%S), status %y", &upath, status);
1369 __seterrno_from_nt_status (status);
1370 continue;
1371 }
1372 if (!got_one)
1373 {
1374 print ("major minor #blocks name win-mounts\n\n");
1375 got_one = true;
1376 }
1377 /* Fetch partition info for the entire disk to get its size. */
1378 if (DeviceIoControl (devhdl, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0,
1379 ioctl_buf, NT_MAX_PATH, &bytes_read, NULL))
1380 {
1381 pix = (PARTITION_INFORMATION_EX *) ioctl_buf;
1382 size = pix->PartitionLength.QuadPart;
1383 }
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 }
1390 else
1391 {
1392 debug_printf ("DeviceIoControl (%S, "
1393 "IOCTL_DISK_GET_PARTITION_INFO{_EX}) %E", &upath);
1394 size = 0;
1395 }
1396 device dev (drive_num, 0);
1397 bufptr += __small_sprintf (bufptr, "%5d %5d %9U %s\n",
1398 dev.get_major (), dev.get_minor (),
1399 size >> 10, dev.name () + 5);
1400 /* Fetch drive layout info to get size of all partitions on the disk. */
1401 if (DeviceIoControl (devhdl, IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
1402 NULL, 0, ioctl_buf, NT_MAX_PATH, &bytes_read, NULL))
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)
1421 for (DWORD i = 0; i < part_cnt && i < 64; ++i)
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;
1434 part_num = pi->PartitionNumber;
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;
1442 device dev (drive_num, part_num);
1443
1444 bufptr += __small_sprintf (bufptr, "%5d %5d %9U %s",
1445 dev.get_major (), dev.get_minor (),
1446 size >> 10, dev.name () + 5);
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 {
1456 len = strlen (dev.name () + 5);
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';
1464 }
1465 NtClose (devhdl);
1466 }
1467 NtClose (dirhdl);
1468
1469 if (!got_one)
1470 return 0;
1471
1472 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1473 memcpy (destbuf, buf, bufptr - buf);
1474 return bufptr - buf;
1475 }
1476
1477 static off_t
1478 format_proc_self (void *, char *&destbuf)
1479 {
1480 destbuf = (char *) crealloc_abort (destbuf, 16);
1481 return __small_sprintf (destbuf, "%d", getpid ());
1482 }
1483
1484 static off_t
1485 format_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);
1489 if (dend > destbuf + 1) /* cygdrive != "/"? */
1490 *--dend = '\0';
1491 return dend - destbuf;
1492 }
1493
1494 static off_t
1495 format_proc_mounts (void *, char *&destbuf)
1496 {
1497 destbuf = (char *) crealloc_abort (destbuf, sizeof ("self/mounts"));
1498 return __small_sprintf (destbuf, "self/mounts");
1499 }
1500
1501 static off_t
1502 format_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",
1511 fs_names[i].block_device ? "" : "nodev",
1512 fs_names[i].name);
1513
1514 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1515 memcpy (destbuf, buf, bufptr - buf);
1516 return bufptr - buf;
1517 }
1518
1519 static off_t
1520 format_proc_swaps (void *, char *&destbuf)
1521 {
1522 unsigned long long total = 0ULL, used = 0ULL;
1523 PSYSTEM_PAGEFILE_INFORMATION spi = NULL;
1524 ULONG size = 512;
1525 NTSTATUS status = STATUS_SUCCESS;
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 {
1534 status = NtQuerySystemInformation (SystemPagefileInformation, (PVOID) spi,
1535 size, &size);
1536 if (status == STATUS_INFO_LENGTH_MISMATCH)
1537 {
1538 free (spi);
1539 spi = (PSYSTEM_PAGEFILE_INFORMATION) malloc (size);
1540 if (spi)
1541 status = NtQuerySystemInformation (SystemPagefileInformation,
1542 (PVOID) spi, size, &size);
1543 }
1544 }
1545
1546 bufptr += __small_sprintf (bufptr,
1547 "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
1548
1549 if (spi && NT_SUCCESS (status))
1550 {
1551 PSYSTEM_PAGEFILE_INFORMATION spp = spi;
1552 char *filename = tp.c_get ();
1553 do
1554 {
1555 total = (unsigned long long) spp->CurrentSize * wincap.page_size ();
1556 used = (unsigned long long) spp->TotalUsed * wincap.page_size ();
1557 cygwin_conv_path (CCP_WIN_W_TO_POSIX, spp->FileName.Buffer,
1558 filename, NT_MAX_PATH);
1559 bufptr += sprintf (bufptr, "%-40s%-16s%-8llu%-8llu%-8d\n",
1560 filename, "file", total >> 10, used >> 10, 0);
1561 }
1562 while (spp->NextEntryOffset
1563 && (spp = (PSYSTEM_PAGEFILE_INFORMATION)
1564 ((char *) spp + spp->NextEntryOffset)));
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
1575 static off_t
1576 format_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),
1607 _major (FH_CONSOLE), _major (FH_PTMX),
1608 DEV_TAPE_MAJOR, DEV_MISC_MAJOR, DEV_SOUND_MAJOR,
1609 DEV_SERIAL_MAJOR, DEV_PTYS_MAJOR, DEV_FLOPPY_MAJOR,
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
1619 static off_t
1620 format_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
1636 #undef print
This page took 0.181226 seconds and 5 git commands to generate.