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