1 /* fhandler_proc.cc: fhandler for /proc virtual filesystem
3 Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2011 Red Hat, Inc.
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
12 #include "miscfuncs.h"
20 #include "fhandler_virtual.h"
25 #include <sys/utsname.h>
26 #include <sys/param.h>
27 #include <sys/sysinfo.h>
35 #define _COMPILING_NEWLIB
38 static _off64_t format_proc_loadavg (void *, char *&);
39 static _off64_t format_proc_meminfo (void *, char *&);
40 static _off64_t format_proc_stat (void *, char *&);
41 static _off64_t format_proc_version (void *, char *&);
42 static _off64_t format_proc_uptime (void *, char *&);
43 static _off64_t format_proc_cpuinfo (void *, char *&);
44 static _off64_t format_proc_partitions (void *, char *&);
45 static _off64_t format_proc_self (void *, char *&);
46 static _off64_t format_proc_mounts (void *, char *&);
47 static _off64_t format_proc_filesystems (void *, char *&);
48 static _off64_t format_proc_swaps (void *, char *&);
49 static _off64_t format_proc_devices (void *, char *&);
50 static _off64_t format_proc_misc (void *, char *&);
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 ("devices"), FH_PROC, virt_file, format_proc_devices },
58 { _VN ("filesystems"), FH_PROC, virt_file, format_proc_filesystems },
59 { _VN ("loadavg"), FH_PROC, virt_file, format_proc_loadavg },
60 { _VN ("meminfo"), FH_PROC, virt_file, format_proc_meminfo },
61 { _VN ("misc"), FH_PROC, virt_file, format_proc_misc },
62 { _VN ("mounts"), FH_PROC, virt_symlink, format_proc_mounts },
63 { _VN ("net"), FH_PROCNET, virt_directory, NULL },
64 { _VN ("partitions"), FH_PROC, virt_file, format_proc_partitions },
65 { _VN ("registry"), FH_REGISTRY, virt_directory, NULL },
66 { _VN ("registry32"), FH_REGISTRY, virt_directory, NULL },
67 { _VN ("registry64"), FH_REGISTRY, virt_directory, NULL },
68 { _VN ("self"), FH_PROC, virt_symlink, format_proc_self },
69 { _VN ("stat"), FH_PROC, virt_file, format_proc_stat },
70 { _VN ("swaps"), FH_PROC, virt_file, format_proc_swaps },
71 { _VN ("sys"), FH_PROCSYS, virt_directory, NULL },
72 { _VN ("sysvipc"), FH_PROCSYSVIPC, virt_directory, NULL },
73 { _VN ("uptime"), FH_PROC, virt_file, format_proc_uptime },
74 { _VN ("version"), FH_PROC, virt_file, format_proc_version },
75 { NULL, 0, FH_NADA, virt_none, NULL }
78 #define PROC_DIR_COUNT 4
80 static const int PROC_LINK_COUNT = (sizeof (proc_tab) / sizeof (virt_tab_t)) - 1;
82 /* name of the /proc filesystem */
83 const char proc[] = "/proc";
84 const size_t proc_len = sizeof (proc) - 1;
86 /* bsearch compare function. */
88 proc_tab_cmp (const void *key, const void *memb)
90 int ret = strncmp (((virt_tab_t *) key)->name, ((virt_tab_t *) memb)->name,
91 ((virt_tab_t *) memb)->name_len);
92 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] != '/')
97 /* Helper function to perform a binary search of the incoming pathname
98 against the alpha-sorted virtual file table. */
100 virt_tab_search (const char *path, bool prefix, const virt_tab_t *table,
103 virt_tab_t key = { path, 0, FH_NADA, virt_none, NULL };
104 virt_tab_t *entry = (virt_tab_t *) bsearch (&key, table, nelem,
107 if (entry && (path[entry->name_len] == '\0'
108 || (prefix && path[entry->name_len] == '/')))
113 /* Auxillary function that returns the fhandler associated with the given
116 fhandler_proc::get_proc_fhandler (const char *path)
118 debug_printf ("get_proc_fhandler(%s)", path);
120 /* Since this method is called from path_conv::check we can't rely on
121 it being normalised and therefore the path may have runs of slashes
123 while (isdirsep (*path))
126 /* Check if this is the root of the virtual filesystem (i.e. /proc). */
130 virt_tab_t *entry = virt_tab_search (path, true, proc_tab,
133 return entry->fhandler;
135 int pid = atoi (path);
137 /* If p->pid != pid, then pid is actually the Windows PID for an execed
138 Cygwin process, and the pinfo entry is the additional entry created
139 at exec time. We don't want to enable the user to access a process
140 entry by using the Win32 PID, though. */
141 if (p && p->pid == pid)
144 bool has_subdir = false;
146 if (isdirsep (*path++))
153 /* The user is trying to access a non-existent subdirectory of /proc. */
156 /* Return FH_PROC so that we can return EROFS if the user is trying to
161 /* Returns 0 if path doesn't exist, >0 if path is a directory,
162 -1 if path is a file, -2 if it's a symlink. */
164 fhandler_proc::exists ()
166 const char *path = get_name ();
167 debug_printf ("exists (%s)", path);
171 virt_tab_t *entry = virt_tab_search (path + 1, false, proc_tab,
175 fileid = entry - proc_tab;
181 fhandler_proc::fhandler_proc ():
187 fhandler_proc::fstat (struct __stat64 *buf)
189 const char *path = get_name ();
190 debug_printf ("fstat (%s)", path);
193 fhandler_base::fstat (buf);
195 buf->st_mode &= ~_IFMT & NO_W;
199 winpids pids ((DWORD) 0);
201 buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
202 buf->st_nlink = PROC_DIR_COUNT + 2 + pids.npids;
207 virt_tab_t *entry = virt_tab_search (path + 1, false, proc_tab,
211 if (entry->type == virt_directory)
212 buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
213 else if (entry->type == virt_symlink)
214 buf->st_mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
217 buf->st_mode &= NO_X;
218 buf->st_mode |= S_IFREG;
228 fhandler_proc::opendir (int fd)
230 DIR *dir = fhandler_virtual::opendir (fd);
231 if (dir && !(dir->__handle = (void *) new winpids ((DWORD) 0)))
241 fhandler_proc::closedir (DIR *dir)
243 delete (winpids *) dir->__handle;
244 return fhandler_virtual::closedir (dir);
248 fhandler_proc::readdir (DIR *dir, dirent *de)
251 if (dir->__d_position < PROC_LINK_COUNT)
253 strcpy (de->d_name, proc_tab[dir->__d_position++].name);
254 dir->__flags |= dirent_saw_dot | dirent_saw_dot_dot;
259 winpids &pids = *(winpids *) dir->__handle;
262 for (unsigned i = 0; i < pids.npids; i++)
263 if (found++ == dir->__d_position - PROC_LINK_COUNT)
265 __small_sprintf (de->d_name, "%d", pids[i]->pid);
272 syscall_printf ("%d = readdir(%p, %p) (%s)", res, dir, de, de->d_name);
277 fhandler_proc::open (int flags, mode_t mode)
279 int proc_file_no = -1;
281 int res = fhandler_virtual::open (flags, mode);
289 path = get_name () + proc_len;
293 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
299 else if (flags & O_WRONLY)
313 for (int i = 0; proc_tab[i].name; i++)
314 if (path_prefix_p (proc_tab[i].name, path + 1, strlen (proc_tab[i].name),
318 if (proc_tab[i].fhandler != FH_PROC)
320 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
326 else if (flags & O_WRONLY)
340 if (proc_file_no == -1)
355 if (flags & O_WRONLY)
362 fileid = proc_file_no;
363 if (!fill_filebuf ())
369 if (flags & O_APPEND)
376 set_flags ((flags & ~O_TEXT) | O_BINARY);
379 syscall_printf ("%d = fhandler_proc::open(%p, %d)", res, flags, mode);
384 fhandler_proc::fill_filebuf ()
386 if (fileid < PROC_LINK_COUNT && proc_tab[fileid].format_func)
388 filesize = proc_tab[fileid].format_func (NULL, filebuf);
396 format_proc_version (void *, char *&destbuf)
399 char *buf = tp.c_get ();
401 struct utsname uts_name;
404 bufptr += __small_sprintf (bufptr, "%s version %s (%s@%s) (%s) %s\n",
405 uts_name.sysname, uts_name.release, USERNAME, HOSTNAME,
406 GCC_VERSION, uts_name.version);
408 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
409 memcpy (destbuf, buf, bufptr - buf);
414 format_proc_loadavg (void *, char *&destbuf)
416 extern int get_process_state (DWORD dwProcessId);
417 unsigned running = 0;
418 winpids pids ((DWORD) 0);
420 for (unsigned i = 0; i < pids.npids; i++)
421 switch (get_process_state (i)) {
428 destbuf = (char *) crealloc_abort (destbuf, 16);
429 return __small_sprintf (destbuf, "%u.%02u %u.%02u %u.%02u %u/%u\n",
430 0, 0, 0, 0, 0, 0, running, pids.npids);
434 format_proc_meminfo (void *, char *&destbuf)
436 unsigned long long mem_total, mem_free, swap_total, swap_free;
440 mem_total = (unsigned long long) info.totalram * info.mem_unit;
441 mem_free = (unsigned long long) info.freeram * info.mem_unit;
442 swap_total = (unsigned long long) info.totalswap * info.mem_unit;
443 swap_free = (unsigned long long) info.freeswap * info.mem_unit;
445 destbuf = (char *) crealloc_abort (destbuf, 512);
446 return sprintf (destbuf, "MemTotal: %10llu kB\n"
447 "MemFree: %10llu kB\n"
450 "LowTotal: %10llu kB\n"
451 "LowFree: %10llu kB\n"
452 "SwapTotal: %10llu kB\n"
453 "SwapFree: %10llu kB\n",
454 mem_total >> 10, mem_free >> 10,
455 mem_total >> 10, mem_free >> 10,
456 swap_total >> 10, swap_free >> 10);
460 format_proc_uptime (void *, char *&destbuf)
462 unsigned long long uptime = 0ULL, idle_time = 0ULL;
464 SYSTEM_TIME_OF_DAY_INFORMATION stodi;
465 /* Sizeof SYSTEM_PERFORMANCE_INFORMATION on 64 bit systems. It
466 appears to contain some trailing additional information from
467 what I can tell after examining the content.
468 FIXME: It would be nice if this could be verified somehow. */
469 const size_t sizeof_spi = sizeof (SYSTEM_PERFORMANCE_INFORMATION) + 16;
470 PSYSTEM_PERFORMANCE_INFORMATION spi = (PSYSTEM_PERFORMANCE_INFORMATION)
473 status = NtQuerySystemInformation (SystemTimeOfDayInformation, &stodi,
475 if (NT_SUCCESS (status))
476 uptime = (stodi.CurrentTime.QuadPart - stodi.BootTime.QuadPart) / 100000ULL;
478 debug_printf ("NtQuerySystemInformation(SystemTimeOfDayInformation), "
479 "status %p", status);
481 if (NT_SUCCESS (NtQuerySystemInformation (SystemPerformanceInformation,
482 spi, sizeof_spi, NULL)))
483 idle_time = (spi->IdleTime.QuadPart / wincap.cpu_count ())
486 destbuf = (char *) crealloc_abort (destbuf, 80);
487 return __small_sprintf (destbuf, "%U.%02u %U.%02u\n",
488 uptime / 100, long (uptime % 100),
489 idle_time / 100, long (idle_time % 100));
493 format_proc_stat (void *, char *&destbuf)
495 unsigned long pages_in = 0UL, pages_out = 0UL, interrupt_count = 0UL,
496 context_switches = 0UL, swap_in = 0UL, swap_out = 0UL;
497 time_t boot_time = 0;
499 /* Sizeof SYSTEM_PERFORMANCE_INFORMATION on 64 bit systems. It
500 appears to contain some trailing additional information from
501 what I can tell after examining the content.
502 FIXME: It would be nice if this could be verified somehow. */
503 const size_t sizeof_spi = sizeof (SYSTEM_PERFORMANCE_INFORMATION) + 16;
504 PSYSTEM_PERFORMANCE_INFORMATION spi = (PSYSTEM_PERFORMANCE_INFORMATION)
506 SYSTEM_TIME_OF_DAY_INFORMATION stodi;
509 char *buf = tp.c_get ();
512 SYSTEM_PROCESSOR_TIMES spt[wincap.cpu_count ()];
513 status = NtQuerySystemInformation (SystemProcessorTimes, (PVOID) spt,
514 sizeof spt[0] * wincap.cpu_count (), NULL);
515 if (!NT_SUCCESS (status))
516 debug_printf ("NtQuerySystemInformation(SystemProcessorTimes), "
517 "status %p", status);
520 unsigned long long user_time = 0ULL, kernel_time = 0ULL, idle_time = 0ULL;
521 for (unsigned long i = 0; i < wincap.cpu_count (); i++)
523 kernel_time += (spt[i].KernelTime.QuadPart - spt[i].IdleTime.QuadPart)
525 user_time += spt[i].UserTime.QuadPart * HZ / 10000000ULL;
526 idle_time += spt[i].IdleTime.QuadPart * HZ / 10000000ULL;
529 eobuf += __small_sprintf (eobuf, "cpu %U %U %U %U\n",
530 user_time, 0ULL, kernel_time, idle_time);
531 user_time = 0ULL, kernel_time = 0ULL, idle_time = 0ULL;
532 for (unsigned long i = 0; i < wincap.cpu_count (); i++)
534 interrupt_count += spt[i].InterruptCount;
535 kernel_time = (spt[i].KernelTime.QuadPart - spt[i].IdleTime.QuadPart) * HZ / 10000000ULL;
536 user_time = spt[i].UserTime.QuadPart * HZ / 10000000ULL;
537 idle_time = spt[i].IdleTime.QuadPart * HZ / 10000000ULL;
538 eobuf += __small_sprintf (eobuf, "cpu%d %U %U %U %U\n", i,
539 user_time, 0ULL, kernel_time, idle_time);
542 status = NtQuerySystemInformation (SystemPerformanceInformation,
543 (PVOID) spi, sizeof_spi, NULL);
544 if (!NT_SUCCESS (status))
546 debug_printf ("NtQuerySystemInformation(SystemPerformanceInformation)"
547 ", status %p", status);
548 memset (spi, 0, sizeof_spi);
550 status = NtQuerySystemInformation (SystemTimeOfDayInformation,
551 (PVOID) &stodi, sizeof stodi, NULL);
552 if (!NT_SUCCESS (status))
553 debug_printf ("NtQuerySystemInformation(SystemTimeOfDayInformation), "
554 "status %p", status);
556 if (!NT_SUCCESS (status))
558 __seterrno_from_nt_status (status);
562 pages_in = spi->PagesRead;
563 pages_out = spi->PagefilePagesWritten + spi->MappedFilePagesWritten;
564 /* Note: there is no distinction made in this structure between pages read
565 from the page file and pages read from mapped files, but there is such
566 a distinction made when it comes to writing. Goodness knows why. The
567 value of swap_in, then, will obviously be wrong but its our best guess. */
568 swap_in = spi->PagesRead;
569 swap_out = spi->PagefilePagesWritten;
570 context_switches = spi->ContextSwitches;
571 boot_time = to_time_t ((FILETIME *) &stodi.BootTime.QuadPart);
573 eobuf += __small_sprintf (eobuf, "page %u %u\n"
583 destbuf = (char *) crealloc_abort (destbuf, eobuf - buf);
584 memcpy (destbuf, buf, eobuf - buf);
588 #define print(x) { bufptr = stpcpy (bufptr, (x)); }
591 format_proc_cpuinfo (void *, char *&destbuf)
593 DWORD orig_affinity_mask;
595 const int BUFSIZE = 256;
600 WCHAR w[BUFSIZE / sizeof (WCHAR)];
606 char *buf = tp.c_get ();
609 for (cpu_number = 0; ; cpu_number++)
612 __small_swprintf (cpu_key, L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION"
613 "\\System\\CentralProcessor\\%d", cpu_number);
614 if (!NT_SUCCESS (RtlCheckRegistryKey (RTL_REGISTRY_ABSOLUTE, cpu_key)))
619 orig_affinity_mask = SetThreadAffinityMask (GetCurrentThread (),
621 if (orig_affinity_mask == 0)
622 debug_printf ("SetThreadAffinityMask failed %E");
623 /* I'm not sure whether the thread changes processor immediately
624 and I'm not sure whether this function will cause the thread
628 bool has_cpuid = false;
630 if (!can_set_flag (0x00040000))
631 debug_printf ("386 processor - no cpuid");
634 debug_printf ("486 processor");
635 if (can_set_flag (0x00200000))
637 debug_printf ("processor supports CPUID instruction");
641 debug_printf ("processor does not support CPUID instruction");
646 WCHAR vendor[64], id[64];
647 UNICODE_STRING uvendor, uid;
648 RtlInitEmptyUnicodeString (&uvendor, vendor, sizeof (vendor));
649 RtlInitEmptyUnicodeString (&uid, id, sizeof (id));
651 RTL_QUERY_REGISTRY_TABLE tab[4] = {
652 { NULL, RTL_QUERY_REGISTRY_NOEXPAND | RTL_QUERY_REGISTRY_DIRECT,
653 L"VendorIdentifier", &uvendor, REG_NONE, NULL, 0 },
654 { NULL, RTL_QUERY_REGISTRY_NOEXPAND | RTL_QUERY_REGISTRY_DIRECT,
655 L"Identifier", &uid, REG_NONE, NULL, 0 },
656 { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOSTRING,
657 L"~Mhz", &cpu_mhz, REG_NONE, NULL, 0 },
658 { NULL, 0, NULL, NULL, 0, NULL, 0 }
661 RtlQueryRegistryValues (RTL_REGISTRY_ABSOLUTE, cpu_key, tab,
663 bufptr += __small_sprintf (bufptr,
668 cpu_number, &uvendor, &uid, cpu_mhz);
670 if (IsProcessorFeaturePresent (PF_3DNOW_INSTRUCTIONS_AVAILABLE))
672 if (IsProcessorFeaturePresent (PF_COMPARE_EXCHANGE_DOUBLE))
674 if (!IsProcessorFeaturePresent (PF_FLOATING_POINT_EMULATED))
676 if (IsProcessorFeaturePresent (PF_MMX_INSTRUCTIONS_AVAILABLE))
678 if (IsProcessorFeaturePresent (PF_PAE_ENABLED))
680 if (IsProcessorFeaturePresent (PF_RDTSC_INSTRUCTION_AVAILABLE))
682 if (IsProcessorFeaturePresent (PF_XMMI_INSTRUCTIONS_AVAILABLE))
684 if (IsProcessorFeaturePresent (PF_XMMI64_INSTRUCTIONS_AVAILABLE))
690 RTL_QUERY_REGISTRY_TABLE tab[2] = {
691 { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOSTRING,
692 L"~Mhz", &cpu_mhz, REG_NONE, NULL, 0 },
693 { NULL, 0, NULL, NULL, 0, NULL, 0 }
696 RtlQueryRegistryValues (RTL_REGISTRY_ABSOLUTE, cpu_key, tab,
698 bufptr += __small_sprintf (bufptr, "processor\t: %d\n", cpu_number);
699 unsigned maxf, vendor_id[4], unused;
700 cpuid (&maxf, &vendor_id[0], &vendor_id[2], &vendor_id[1], 0);
704 /* Vendor identification. */
705 bool is_amd = false, is_intel = false;
706 if (!strcmp ((char*)vendor_id, "AuthenticAMD"))
708 else if (!strcmp ((char*)vendor_id, "GenuineIntel"))
711 bufptr += __small_sprintf (bufptr, "vendor_id\t: %s\n",
715 unsigned features2, features1, extra_info, cpuid_sig;
716 cpuid (&cpuid_sig, &extra_info, &features2, &features1, 1);
717 /* unsigned extended_family = (cpuid_sig & 0x0ff00000) >> 20,
718 extended_model = (cpuid_sig & 0x000f0000) >> 16,
719 type = (cpuid_sig & 0x00003000) >> 12; */
720 unsigned family = (cpuid_sig & 0x00000f00) >> 8,
721 model = (cpuid_sig & 0x000000f0) >> 4,
722 stepping = cpuid_sig & 0x0000000f;
723 /* Not printed on Linux */
724 //unsigned brand_id = extra_info & 0x0000000f;
725 //unsigned cpu_count = (extra_info & 0x00ff0000) >> 16;
726 unsigned apic_id = (extra_info & 0xff000000) >> 24;
728 family += (cpuid_sig >> 20) & 0xff;
730 model += ((cpuid_sig >> 16) & 0x0f) << 4;
732 cpuid (&maxe, &unused, &unused, &unused, 0x80000000);
733 if (maxe >= 0x80000004)
735 cpuid (&in_buf.m[0], &in_buf.m[1], &in_buf.m[2],
736 &in_buf.m[3], 0x80000002);
737 cpuid (&in_buf.m[4], &in_buf.m[5], &in_buf.m[6],
738 &in_buf.m[7], 0x80000003);
739 cpuid (&in_buf.m[8], &in_buf.m[9], &in_buf.m[10],
740 &in_buf.m[11], 0x80000004);
745 /* Could implement a lookup table here if someone needs it. */
746 strcpy (in_buf.s, "unknown");
751 cache_alignment = 64;
752 if (features1 & (1 << 19)) /* CLFSH */
753 clflush = ((extra_info >> 8) & 0xff) << 3;
754 if (is_intel && family == 15)
755 cache_alignment = clflush * 2;
756 if (maxe >= 0x80000005) /* L1 Cache and TLB Identifiers. */
758 unsigned data_cache, inst_cache;
759 cpuid (&unused, &unused, &data_cache, &inst_cache,
762 cache_size = (inst_cache >> 24) + (data_cache >> 24);
765 if (maxe >= 0x80000006) /* L2 Cache and L2 TLB Identifiers. */
768 cpuid (&unused, &tlb, &l2, &unused, 0x80000006);
770 cache_size = l2 >> 16;
771 tlb_size = ((tlb >> 16) & 0xfff) + (tlb & 0xfff);
773 bufptr += __small_sprintf (bufptr, "cpu family\t: %d\n"
780 in_buf.s + strspn (in_buf.s, " "),
784 bufptr += __small_sprintf (bufptr, "cache size\t: %d KB\n",
787 /* Recognize multi-core CPUs. */
788 if (is_amd && maxe >= 0x80000008)
791 cpuid (&unused, &unused, &core_info, &unused, 0x80000008);
793 int max_cores = 1 + (core_info & 0xff);
796 int shift = (core_info >> 12) & 0x0f;
798 while ((1 << shift) < max_cores)
800 int core_id = apic_id & ((1 << shift) - 1);
803 bufptr += __small_sprintf (bufptr, "physical id\t: %d\n"
806 apic_id, core_id, max_cores);
809 /* Recognize Intel Hyper-Transport CPUs. */
810 else if (is_intel && (features1 & (1 << 28)) && maxf >= 4)
815 bufptr += __small_sprintf (bufptr, "fpu\t\t: %s\n"
816 "fpu_exception\t: %s\n"
817 "cpuid level\t: %d\n"
819 (features1 & (1 << 0)) ? "yes" : "no",
820 (features1 & (1 << 0)) ? "yes" : "no",
822 print ("flags\t\t:");
823 if (features1 & (1 << 0))
825 if (features1 & (1 << 1))
827 if (features1 & (1 << 2))
829 if (features1 & (1 << 3))
831 if (features1 & (1 << 4))
833 if (features1 & (1 << 5))
835 if (features1 & (1 << 6))
837 if (features1 & (1 << 7))
839 if (features1 & (1 << 8))
841 if (features1 & (1 << 9))
843 if (features1 & (1 << 11))
845 if (features1 & (1 << 12))
847 if (features1 & (1 << 13))
849 if (features1 & (1 << 14))
851 if (features1 & (1 << 15))
853 if (features1 & (1 << 16))
855 if (features1 & (1 << 17))
857 if (features1 & (1 << 18))
859 if (features1 & (1 << 19))
861 if (is_intel && features1 & (1 << 21))
863 if (is_intel && features1 & (1 << 22))
865 if (features1 & (1 << 23))
867 if (features1 & (1 << 24))
869 if (features1 & (1 << 25))
871 if (features1 & (1 << 26))
873 if (is_intel && (features1 & (1 << 27)))
875 if (features1 & (1 << 28))
879 if (features1 & (1 << 29))
881 if (features1 & (1 << 30))
883 if (features1 & (1 << 31))
887 if (is_amd && maxe >= 0x80000001)
890 cpuid (&unused, &unused, &unused, &features, 0x80000001);
892 if (features & (1 << 11))
894 if (features & (1 << 19)) /* Huh? Not in AMD64 specs. */
896 if (features & (1 << 20))
898 if (features & (1 << 22))
900 if (features & (1 << 25))
902 if (features & (1 << 26))
904 if (features & (1 << 27))
906 if (features & (1 << 29))
908 if (features & (1 << 30)) /* 31th bit is on. */
910 if (features & (1 << 31)) /* 32th bit (highest) is on. */
914 if (features2 & (1 << 0))
918 if (features2 & (1 << 2))
920 if (features2 & (1 << 3))
922 if (features2 & (1 << 4))
924 if (features2 & (1 << 5))
926 if (features2 & (1 << 6))
928 if (features2 & (1 << 7))
930 if (features2 & (1 << 8))
932 if (features2 & (1 << 9))
934 if (features2 & (1 << 10))
936 if (features2 & (1 << 12))
939 if (features2 & (1 << 13))
943 if (features2 & (1 << 14))
945 if (features2 & (1 << 15))
947 if (features2 & (1 << 18))
949 if (features2 & (1 << 19))
951 if (features2 & (1 << 20))
953 if (features2 & (1 << 21))
955 if (features2 & (1 << 22))
957 if (features2 & (1 << 23))
959 if (features2 & (1 << 25))
961 if (features2 & (1 << 26))
963 if (features2 & (1 << 27))
965 if (features2 & (1 << 28))
969 if (maxe >= 0x80000001)
972 cpuid (&unused, &unused, &features, &unused, 0x80000001);
974 if (features & (1 << 0))
976 if (features & (1 << 1))
977 print (" cmp_legacy");
980 if (features & (1 << 2))
982 if (features & (1 << 3))
984 if (features & (1 << 4))
985 print (" cr8_legacy");
986 if (features & (1 << 5))
988 if (features & (1 << 6))
990 if (features & (1 << 7))
991 print (" misalignsse");
992 if (features & (1 << 8))
993 print (" 3dnowprefetch");
994 if (features & (1 << 9))
997 if (features & (1 << 10))
1001 if (features & (1 << 11))
1003 if (features & (1 << 12))
1005 if (features & (1 << 13))
1012 /* TODO: bogomips */
1015 bufptr += __small_sprintf (bufptr,
1016 "TLB size\t: %d 4K pages\n",
1018 bufptr += __small_sprintf (bufptr, "clflush size\t: %d\n"
1019 "cache_alignment\t: %d\n",
1023 if (maxe >= 0x80000008) /* Address size. */
1025 unsigned addr_size, phys, virt;
1026 cpuid (&addr_size, &unused, &unused, &unused, 0x80000008);
1028 phys = addr_size & 0xff;
1029 virt = (addr_size >> 8) & 0xff;
1030 /* Fix an errata on Intel CPUs */
1031 if (is_intel && family == 15 && model == 3 && stepping == 4)
1033 bufptr += __small_sprintf (bufptr, "address sizes\t: "
1034 "%u bits physical, "
1035 "%u bits virtual\n",
1039 if (maxe >= 0x80000007) /* Advanced power management. */
1041 cpuid (&unused, &unused, &unused, &features2, 0x80000007);
1043 print ("power management:");
1044 if (features2 & (1 << 0))
1046 if (features2 & (1 << 1))
1048 if (features2 & (1 << 2))
1050 if (features2 & (1 << 3))
1052 if (features2 & (1 << 4))
1054 if (features2 & (1 << 5))
1056 if (features2 & (1 << 6))
1057 print (" 100mhzsteps");
1058 if (features2 & (1 << 7))
1059 print (" hwpstate");
1064 bufptr += __small_sprintf (bufptr, "cpu MHz : %d\n"
1067 IsProcessorFeaturePresent (PF_FLOATING_POINT_EMULATED) ? "no" : "yes");
1070 if (orig_affinity_mask != 0)
1071 SetThreadAffinityMask (GetCurrentThread (), orig_affinity_mask);
1075 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1076 memcpy (destbuf, buf, bufptr - buf);
1077 return bufptr - buf;
1081 format_proc_partitions (void *, char *&destbuf)
1083 OBJECT_ATTRIBUTES attr;
1089 char *buf = tp.c_get ();
1091 char *ioctl_buf = tp.c_get ();
1093 /* Open \Device object directory. */
1094 wchar_t wpath[MAX_PATH] = L"\\Device";
1095 UNICODE_STRING upath = {14, 16, wpath};
1096 InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL);
1097 status = NtOpenDirectoryObject (&dirhdl, DIRECTORY_QUERY, &attr);
1098 if (!NT_SUCCESS (status))
1100 debug_printf ("NtOpenDirectoryObject, status %p", status);
1101 __seterrno_from_nt_status (status);
1105 /* Traverse \Device directory ... */
1106 PDIRECTORY_BASIC_INFORMATION dbi = (PDIRECTORY_BASIC_INFORMATION)
1108 BOOLEAN restart = TRUE;
1109 bool got_one = false;
1111 while (NT_SUCCESS (NtQueryDirectoryObject (dirhdl, dbi, 640, TRUE, restart,
1115 PARTITION_INFORMATION_EX *pix = NULL;
1116 PARTITION_INFORMATION *pi = NULL;
1119 unsigned long long size;
1123 /* ... and check for a "Harddisk[0-9]*" entry. */
1124 if (dbi->ObjectName.Length < 9 * sizeof (WCHAR)
1125 || wcsncasecmp (dbi->ObjectName.Buffer, L"Harddisk", 8) != 0
1126 || !iswdigit (dbi->ObjectName.Buffer[8]))
1128 /* Got it. Now construct the path to the entire disk, which is
1129 "\\Device\\HarddiskX\\Partition0", and open the disk with
1130 minimum permssions. */
1131 unsigned long drive_num = wcstoul (dbi->ObjectName.Buffer + 8, NULL, 10);
1132 wcscpy (wpath, dbi->ObjectName.Buffer);
1133 PWCHAR wpart = wpath + dbi->ObjectName.Length / sizeof (WCHAR);
1134 __small_swprintf (wpart, L"\\Partition0");
1135 upath.Length = dbi->ObjectName.Length
1136 + wcslen (wpart) * sizeof (WCHAR);
1137 upath.MaximumLength = upath.Length + sizeof (WCHAR);
1138 InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE,
1140 /* Up to W2K the handle needs read access to fetch the partition info. */
1141 status = NtOpenFile (&devhdl, wincap.has_disk_ex_ioctls ()
1143 : READ_CONTROL | FILE_READ_DATA,
1144 &attr, &io, FILE_SHARE_VALID_FLAGS, 0);
1145 if (!NT_SUCCESS (status))
1147 debug_printf ("NtOpenFile(%S), status %p", &upath, status);
1148 __seterrno_from_nt_status (status);
1153 print ("major minor #blocks name\n\n");
1156 /* Fetch partition info for the entire disk to get its size. */
1157 if (wincap.has_disk_ex_ioctls ()
1158 && DeviceIoControl (devhdl, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0,
1159 ioctl_buf, NT_MAX_PATH, &bytes_read, NULL))
1161 pix = (PARTITION_INFORMATION_EX *) ioctl_buf;
1162 size = pix->PartitionLength.QuadPart;
1164 else if (DeviceIoControl (devhdl, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0,
1165 ioctl_buf, NT_MAX_PATH, &bytes_read, NULL))
1167 pi = (PARTITION_INFORMATION *) ioctl_buf;
1168 size = pi->PartitionLength.QuadPart;
1172 debug_printf ("DeviceIoControl (%S, "
1173 "IOCTL_DISK_GET_PARTITION_INFO{_EX}) %E", &upath);
1176 dev.parsedisk (drive_num, 0);
1177 bufptr += __small_sprintf (bufptr, "%5d %5d %9U %s\n",
1178 dev.get_major (), dev.get_minor (),
1179 size >> 10, dev.name + 5);
1180 /* Fetch drive layout info to get size of all partitions on the disk. */
1181 if (wincap.has_disk_ex_ioctls ()
1182 && DeviceIoControl (devhdl, IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
1183 NULL, 0, ioctl_buf, NT_MAX_PATH, &bytes_read, NULL))
1185 PDRIVE_LAYOUT_INFORMATION_EX pdlix = (PDRIVE_LAYOUT_INFORMATION_EX)
1187 part_cnt = pdlix->PartitionCount;
1188 pix = pdlix->PartitionEntry;
1190 else if (DeviceIoControl (devhdl, IOCTL_DISK_GET_DRIVE_LAYOUT,
1191 NULL, 0, ioctl_buf, NT_MAX_PATH, &bytes_read, NULL))
1193 PDRIVE_LAYOUT_INFORMATION pdli = (PDRIVE_LAYOUT_INFORMATION) ioctl_buf;
1194 part_cnt = pdli->PartitionCount;
1195 pi = pdli->PartitionEntry;
1198 debug_printf ("DeviceIoControl(%S, "
1199 "IOCTL_DISK_GET_DRIVE_LAYOUT{_EX}): %E", &upath);
1200 /* Loop over partitions. */
1202 for (DWORD i = 0; i < part_cnt; ++i)
1208 size = pix->PartitionLength.QuadPart;
1209 part_num = pix->PartitionNumber;
1214 size = pi->PartitionLength.QuadPart;
1215 /* Pre-W2K you can't rely on the partition number info for
1216 unused partitions. */
1217 if (pi->PartitionType == PARTITION_ENTRY_UNUSED
1218 || pi->PartitionType == PARTITION_EXTENDED)
1221 part_num = pi->PartitionNumber;
1224 /* A partition number of 0 denotes an extended partition or a
1225 filler entry as described in fhandler_dev_floppy::lock_partition.
1229 dev.parsedisk (drive_num, part_num);
1230 bufptr += __small_sprintf (bufptr, "%5d %5d %9U %s\n",
1231 dev.get_major (), dev.get_minor (),
1232 size >> 10, dev.name + 5);
1241 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1242 memcpy (destbuf, buf, bufptr - buf);
1243 return bufptr - buf;
1247 format_proc_self (void *, char *&destbuf)
1249 destbuf = (char *) crealloc_abort (destbuf, 16);
1250 return __small_sprintf (destbuf, "%d", getpid ());
1254 format_proc_mounts (void *, char *&destbuf)
1256 destbuf = (char *) crealloc_abort (destbuf, sizeof ("self/mounts"));
1257 return __small_sprintf (destbuf, "self/mounts");
1261 format_proc_filesystems (void *, char *&destbuf)
1264 char *buf = tp.c_get ();
1267 /* start at 1 to skip type "none" */
1268 for (int i = 1; fs_names[i].name; i++)
1269 bufptr += __small_sprintf(bufptr, "%s\t%s\n",
1270 fs_names[i].block_device ? "" : "nodev",
1273 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1274 memcpy (destbuf, buf, bufptr - buf);
1275 return bufptr - buf;
1279 format_proc_swaps (void *, char *&destbuf)
1281 unsigned long long total = 0ULL, used = 0ULL;
1282 char *filename = NULL;
1283 ssize_t filename_len;
1284 PSYSTEM_PAGEFILE_INFORMATION spi = NULL;
1286 NTSTATUS status = STATUS_SUCCESS;
1289 char *buf = tp.c_get ();
1292 spi = (PSYSTEM_PAGEFILE_INFORMATION) malloc (size);
1295 status = NtQuerySystemInformation (SystemPagefileInformation, (PVOID) spi,
1297 if (status == STATUS_INFO_LENGTH_MISMATCH)
1300 spi = (PSYSTEM_PAGEFILE_INFORMATION) malloc (size);
1302 status = NtQuerySystemInformation (SystemPagefileInformation,
1303 (PVOID) spi, size, &size);
1307 bufptr += __small_sprintf (bufptr,
1308 "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
1310 if (spi && NT_SUCCESS (status))
1312 PSYSTEM_PAGEFILE_INFORMATION spp = spi;
1315 total = (unsigned long long) spp->CurrentSize * wincap.page_size ();
1316 used = (unsigned long long) spp->TotalUsed * wincap.page_size ();
1318 filename_len = cygwin_conv_path (CCP_WIN_W_TO_POSIX,
1319 spp->FileName.Buffer, filename, 0);
1320 filename = (char *) malloc (filename_len);
1321 cygwin_conv_path (CCP_WIN_W_TO_POSIX, spp->FileName.Buffer,
1322 filename, filename_len);
1324 bufptr += sprintf (bufptr, "%-40s%-16s%-8llu%-8llu%-8d\n",
1325 filename, "file", total >> 10, used >> 10, 0);
1327 while (spp->NextEntryOffset
1328 && (spp = (PSYSTEM_PAGEFILE_INFORMATION)
1329 ((char *) spp + spp->NextEntryOffset)));
1335 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1336 memcpy (destbuf, buf, bufptr - buf);
1337 return bufptr - buf;
1341 format_proc_devices (void *, char *&destbuf)
1344 char *buf = tp.c_get ();
1347 bufptr += __small_sprintf (bufptr,
1348 "Character devices:\n"
1352 "%3d /dev/console\n"
1371 DEV_MEM_MAJOR, DEV_CONS_MAJOR, _major (FH_TTY),
1372 _major (FH_CONSOLE), _major (FH_PTMX),
1373 DEV_TAPE_MAJOR, DEV_MISC_MAJOR, DEV_SOUND_MAJOR,
1374 DEV_SERIAL_MAJOR, DEV_PTYS_MAJOR, DEV_FLOPPY_MAJOR,
1375 DEV_SD_MAJOR, DEV_CDROM_MAJOR, DEV_SD1_MAJOR,
1376 DEV_SD2_MAJOR, DEV_SD3_MAJOR, DEV_SD4_MAJOR,
1377 DEV_SD5_MAJOR, DEV_SD6_MAJOR, DEV_SD7_MAJOR);
1379 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1380 memcpy (destbuf, buf, bufptr - buf);
1381 return bufptr - buf;
1385 format_proc_misc (void *, char *&destbuf)
1388 char *buf = tp.c_get ();
1391 bufptr += __small_sprintf (bufptr,
1394 _minor (FH_CLIPBOARD), _minor (FH_WINDOWS));
1396 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1397 memcpy (destbuf, buf, bufptr - buf);
1398 return bufptr - buf;