1 /* fhandler_proc.cc: fhandler for /proc virtual filesystem
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
10 #include "miscfuncs.h"
17 #include "shared_info.h"
19 #include "fhandler_virtual.h"
24 #include <sys/utsname.h>
25 #include <sys/param.h>
26 #include <sys/sysinfo.h>
35 #define _COMPILING_NEWLIB
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 *&);
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
}
80 #define PROC_DIR_COUNT 4
82 static const int PROC_LINK_COUNT
= (sizeof (proc_tab
) / sizeof (virt_tab_t
)) - 1;
84 /* name of the /proc filesystem */
85 const char proc
[] = "/proc";
86 const size_t proc_len
= sizeof (proc
) - 1;
88 /* bsearch compare function. */
90 proc_tab_cmp (const void *key
, const void *memb
)
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
] != '/')
99 /* Helper function to perform a binary search of the incoming pathname
100 against the alpha-sorted virtual file table. */
102 virt_tab_search (const char *path
, bool prefix
, const virt_tab_t
*table
,
105 virt_tab_t key
= { path
, 0, FH_NADA
, virt_none
, NULL
};
106 virt_tab_t
*entry
= (virt_tab_t
*) bsearch (&key
, table
, nelem
,
109 if (entry
&& (path
[entry
->name_len
] == '\0'
110 || (prefix
&& path
[entry
->name_len
] == '/')))
115 /* Auxillary function that returns the fhandler associated with the given
118 fhandler_proc::get_proc_fhandler (const char *path
)
120 debug_printf ("get_proc_fhandler(%s)", path
);
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
125 while (isdirsep (*path
))
128 /* Check if this is the root of the virtual filesystem (i.e. /proc). */
132 virt_tab_t
*entry
= virt_tab_search (path
, true, proc_tab
,
135 return entry
->fhandler
;
137 int pid
= atoi (path
);
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
)
146 bool has_subdir
= false;
148 if (isdirsep (*path
++))
155 /* The user is trying to access a non-existent subdirectory of /proc. */
158 /* Return FH_PROC so that we can return EROFS if the user is trying to
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. */
166 fhandler_proc::exists ()
168 const char *path
= get_name ();
169 debug_printf ("exists (%s)", path
);
173 virt_tab_t
*entry
= virt_tab_search (path
+ 1, false, proc_tab
,
177 fileid
= entry
- proc_tab
;
183 fhandler_proc::fhandler_proc ():
189 fhandler_proc::fstat (struct stat
*buf
)
191 const char *path
= get_name ();
192 debug_printf ("fstat (%s)", path
);
195 fhandler_base::fstat (buf
);
197 buf
->st_mode
&= ~_IFMT
& NO_W
;
201 winpids
pids ((DWORD
) 0);
203 buf
->st_mode
|= S_IFDIR
| S_IXUSR
| S_IXGRP
| S_IXOTH
;
204 buf
->st_nlink
= PROC_DIR_COUNT
+ 2 + pids
.npids
;
209 virt_tab_t
*entry
= virt_tab_search (path
+ 1, false, proc_tab
,
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
;
219 buf
->st_mode
&= NO_X
;
220 buf
->st_mode
|= S_IFREG
;
230 fhandler_proc::opendir (int fd
)
232 DIR *dir
= fhandler_virtual::opendir (fd
);
233 if (dir
&& !(dir
->__handle
= (void *) new winpids ((DWORD
) 0)))
243 fhandler_proc::closedir (DIR *dir
)
245 delete (winpids
*) dir
->__handle
;
246 return fhandler_virtual::closedir (dir
);
250 fhandler_proc::readdir (DIR *dir
, dirent
*de
)
253 if (dir
->__d_position
< PROC_LINK_COUNT
)
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
);
258 dir
->__flags
|= dirent_saw_dot
| dirent_saw_dot_dot
;
263 winpids
&pids
= *(winpids
*) dir
->__handle
;
266 for (unsigned i
= 0; i
< pids
.npids
; i
++)
267 if (found
++ == dir
->__d_position
- PROC_LINK_COUNT
)
269 __small_sprintf (de
->d_name
, "%d", pids
[i
]->pid
);
277 syscall_printf ("%d = readdir(%p, %p) (%s)", res
, dir
, de
, de
->d_name
);
282 fhandler_proc::open (int flags
, mode_t mode
)
284 int proc_file_no
= -1;
286 int res
= fhandler_virtual::open (flags
, mode
);
294 path
= get_name () + proc_len
;
298 if ((flags
& (O_CREAT
| O_EXCL
)) == (O_CREAT
| O_EXCL
))
304 else if (flags
& O_WRONLY
)
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
),
323 if (proc_tab
[i
].fhandler
!= FH_PROC
)
325 if ((flags
& (O_CREAT
| O_EXCL
)) == (O_CREAT
| O_EXCL
))
331 else if (flags
& O_WRONLY
)
345 if (proc_file_no
== -1)
360 if (flags
& O_WRONLY
)
367 fileid
= proc_file_no
;
368 if (!fill_filebuf ())
374 if (flags
& O_APPEND
)
381 set_flags ((flags
& ~O_TEXT
) | O_BINARY
);
384 syscall_printf ("%d = fhandler_proc::open(%y, 0%o)", res
, flags
, mode
);
389 fhandler_proc::fill_filebuf ()
391 if (fileid
< PROC_LINK_COUNT
&& proc_tab
[fileid
].format_func
)
393 filesize
= proc_tab
[fileid
].format_func (NULL
, filebuf
);
401 format_proc_version (void *, char *&destbuf
)
404 char *buf
= tp
.c_get ();
406 struct utsname 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
);
413 destbuf
= (char *) crealloc_abort (destbuf
, bufptr
- buf
);
414 memcpy (destbuf
, buf
, bufptr
- buf
);
419 format_proc_loadavg (void *, char *&destbuf
)
421 extern int get_process_state (DWORD dwProcessId
);
422 unsigned int running
= 0;
423 winpids
pids ((DWORD
) 0);
425 for (unsigned i
= 0; i
< pids
.npids
; i
++)
426 switch (get_process_state (i
)) {
433 double loadavg
[3] = { 0.0, 0.0, 0.0 };
434 getloadavg (loadavg
, 3);
436 #define HUNDRETHS(l) (int)((l - floor(l))*100)
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
);
447 format_proc_meminfo (void *, char *&destbuf
)
449 unsigned long long mem_total
, mem_free
, swap_total
, swap_free
;
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
;
458 destbuf
= (char *) crealloc_abort (destbuf
, 512);
459 return sprintf (destbuf
, "MemTotal: %10llu kB\n"
460 "MemFree: %10llu 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);
473 format_proc_uptime (void *, char *&destbuf
)
475 unsigned long long uptime
= 0ULL, idle_time
= 0ULL;
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
)
486 status
= NtQuerySystemInformation (SystemTimeOfDayInformation
, &stodi
,
488 if (NT_SUCCESS (status
))
489 uptime
= (stodi
.CurrentTime
.QuadPart
- stodi
.BootTime
.QuadPart
) / 100000ULL;
491 debug_printf ("NtQuerySystemInformation(SystemTimeOfDayInformation), "
492 "status %y", status
);
494 if (NT_SUCCESS (NtQuerySystemInformation (SystemPerformanceInformation
,
495 spi
, sizeof_spi
, NULL
)))
496 idle_time
= (spi
->IdleTime
.QuadPart
/ wincap
.cpu_count ())
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));
506 format_proc_stat (void *, char *&destbuf
)
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;
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
)
519 SYSTEM_TIMEOFDAY_INFORMATION stodi
;
522 char *buf
= tp
.c_get ();
525 SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION spt
[wincap
.cpu_count ()];
526 status
= NtQuerySystemInformation (SystemProcessorPerformanceInformation
,
528 sizeof spt
[0] * wincap
.cpu_count (), NULL
);
529 if (!NT_SUCCESS (status
))
530 debug_printf ("NtQuerySystemInformation(SystemProcessorPerformanceInformation), "
531 "status %y", status
);
534 unsigned long long user_time
= 0ULL, kernel_time
= 0ULL, idle_time
= 0ULL;
535 for (unsigned long i
= 0; i
< wincap
.cpu_count (); i
++)
537 kernel_time
+= (spt
[i
].KernelTime
.QuadPart
- spt
[i
].IdleTime
.QuadPart
)
539 user_time
+= spt
[i
].UserTime
.QuadPart
* HZ
/ 10000000ULL;
540 idle_time
+= spt
[i
].IdleTime
.QuadPart
* HZ
/ 10000000ULL;
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
++)
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
);
556 status
= NtQuerySystemInformation (SystemPerformanceInformation
,
557 (PVOID
) spi
, sizeof_spi
, NULL
);
558 if (!NT_SUCCESS (status
))
560 debug_printf ("NtQuerySystemInformation(SystemPerformanceInformation)"
561 ", status %y", status
);
562 memset (spi
, 0, sizeof_spi
);
564 status
= NtQuerySystemInformation (SystemTimeOfDayInformation
,
565 (PVOID
) &stodi
, sizeof stodi
, NULL
);
566 if (!NT_SUCCESS (status
))
567 debug_printf ("NtQuerySystemInformation(SystemTimeOfDayInformation), "
568 "status %y", status
);
570 if (!NT_SUCCESS (status
))
572 __seterrno_from_nt_status (status
);
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
);
587 eobuf
+= __small_sprintf (eobuf
, "page %u %u\n"
597 destbuf
= (char *) crealloc_abort (destbuf
, eobuf
- buf
);
598 memcpy (destbuf
, buf
, eobuf
- buf
);
602 #define add_size(p,s) ((p) = ((__typeof__(p))((PBYTE)(p)+(s))))
603 #define print(x) { bufptr = stpcpy (bufptr, (x)); }
605 static inline uint32_t
606 get_msb (uint32_t in
)
608 return 32 - __builtin_clz (in
);
611 static inline uint32_t
612 mask_bits (uint32_t in
)
614 uint32_t bits
= get_msb (in
) - 1;
621 format_proc_cpuinfo (void *, char *&destbuf
)
623 WCHAR cpu_key
[128], *cpu_num_p
;
624 DWORD orig_affinity_mask
= 0;
625 GROUP_AFFINITY orig_group_affinity
;
627 const int BUFSIZE
= 256;
632 WCHAR w
[BUFSIZE
/ sizeof (WCHAR
)];
638 char *buf
= tp
.c_get ();
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. */
645 if (wincap
.has_processor_groups ())
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
))
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
)
659 //num_cpu_groups = plpi->Group.MaximumGroupCount;
661 = plpi
->Group
.GroupInfo
[0].MaximumProcessorCount
;
667 cpu_num_p
= wcpcpy (cpu_key
, L
"\\Registry\\Machine\\HARDWARE\\DESCRIPTION"
668 "\\System\\CentralProcessor\\");
669 for (cpu_number
= 0; ; cpu_number
++)
671 __small_swprintf (cpu_num_p
, L
"%d", cpu_number
);
672 if (!NT_SUCCESS (RtlCheckRegistryKey (RTL_REGISTRY_ABSOLUTE
, cpu_key
)))
677 WORD cpu_group
= cpu_number
/ num_cpu_per_group
;
678 KAFFINITY cpu_mask
= 1L << (cpu_number
% num_cpu_per_group
);
680 if (wincap
.has_processor_groups ())
682 GROUP_AFFINITY affinity
= {
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. */
694 orig_affinity_mask
= SetThreadAffinityMask (GetCurrentThread (),
696 if (orig_affinity_mask
== 0)
697 debug_printf ("SetThreadAffinityMask failed %E");
699 /* I'm not sure whether the thread changes processor immediately
700 and I'm not sure whether this function will cause the thread
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 }
711 RtlQueryRegistryValues (RTL_REGISTRY_ABSOLUTE
, cpu_key
, tab
,
713 bufptr
+= __small_sprintf (bufptr
, "processor\t: %d\n", cpu_number
);
714 uint32_t maxf
, vendor_id
[4], unused
;
716 cpuid (&maxf
, &vendor_id
[0], &vendor_id
[2], &vendor_id
[1], 0x00000000);
720 /* Vendor identification. */
721 bool is_amd
= false, is_intel
= false;
722 if (!strcmp ((char*)vendor_id
, "AuthenticAMD"))
724 else if (!strcmp ((char*)vendor_id
, "GenuineIntel"))
727 bufptr
+= __small_sprintf (bufptr
, "vendor_id\t: %s\n",
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;
737 family
+= (cpuid_sig
>> 20) & 0xff;
739 model
+= ((cpuid_sig
>> 16) & 0x0f) << 4;
742 cpuid (&maxe
, &unused
, &unused
, &unused
, 0x80000000);
743 if (maxe
>= 0x80000004)
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);
755 /* Could implement a lookup table here if someone needs it. */
756 strcpy (in_buf
.s
, "unknown");
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;
767 extern long get_cpu_cache_intel (int sysc
, uint32_t maxf
);
770 /* As on Linux, don't check for L3 cache. */
771 cs
= get_cpu_cache_intel (_SC_LEVEL2_CACHE_SIZE
, maxf
);
774 cs
= get_cpu_cache_intel (_SC_LEVEL1_ICACHE_SIZE
, maxf
);
777 cs
= get_cpu_cache_intel (_SC_LEVEL1_DCACHE_SIZE
, maxf
);
783 if (cache_size
!= -1)
788 extern long get_cpu_cache_amd (int sysc
, uint32_t maxe
);
791 cs
= get_cpu_cache_amd (_SC_LEVEL3_CACHE_SIZE
, maxe
);
793 cs
= get_cpu_cache_amd (_SC_LEVEL2_CACHE_SIZE
, maxe
);
796 cs
= get_cpu_cache_amd (_SC_LEVEL1_ICACHE_SIZE
, maxe
);
799 cs
= get_cpu_cache_amd (_SC_LEVEL1_DCACHE_SIZE
, maxe
);
805 if (cache_size
!= -1)
808 bufptr
+= __small_sprintf (bufptr
, "cpu family\t: %d\n"
812 "cpu MHz\t\t: %d.000\n",
815 in_buf
.s
+ strspn (in_buf
.s
, " "),
820 bufptr
+= __small_sprintf (bufptr
, "cache size\t: %d KB\n",
823 /* Recognize multi-core CPUs. */
824 if (features1
& (1 << 28)) /* HTT */
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
;
832 uint32_t logical_bits
= 0; /* # of logical core bits in apicid. */
833 uint32_t ht_bits
= 0; /* # of thread bits in apic_id. */
838 if (maxf
>= 0x0000000b) /* topoext supported? */
840 uint32_t bits
, logical
, level
, unused
;
843 cpuid (&bits
, &logical
, &level
, &unused
,
845 /* Even if topoext is supposedly supported, it can return
847 if (bits
!= 0 && ((level
>> 8) & 0xff) == 1)
850 ht_bits
= (bits
& 0x1f);
851 siblings
= (logical
& 0xffff);
852 cpu_cores
= siblings
;
853 for (uint32_t idx
= 1; ; ++idx
)
855 cpuid (&bits
, &logical
, &level
, &initial_apic_id
,
858 uint32_t level_type
= ((level
>> 8) & 0xff);
859 if (level_type
== 0) /* Invalid */
861 if (level_type
== 2) /* Core */
863 logical_bits
= (bits
& 0x1f);
864 siblings
= (logical
& 0xffff);
865 cpu_cores
= siblings
>> ht_bits
;
871 if (!valid
&& maxf
>= 0x00000004)
873 uint32_t apic_reserved
;
875 cpuid (&apic_reserved
, &unused
, &unused
, &unused
,
877 if (apic_reserved
& 0x1f)
880 cpu_cores
= ((apic_reserved
>> 26) & 0x3f) + 1;
881 siblings
= (extra_info
>> 16) & 0xff;
882 if (siblings
<= 1) /* HT could be fused out */
884 logical_bits
= mask_bits (cpu_cores
);
889 logical_bits
= mask_bits (siblings
);
890 ht_bits
= mask_bits (siblings
/ cpu_cores
);
894 if (!valid
) /* single core, multi thread */
897 siblings
= (extra_info
>> 16) & 0xff;
898 logical_bits
= mask_bits (siblings
);
899 ht_bits
= logical_bits
;
904 if (maxe
>= 0x8000001e)
906 uint32_t cus
, core_info
;
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
;
916 else if (maxe
>= 0x80000008)
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;
925 logical_bits
= mask_bits (siblings
);
930 siblings
= (extra_info
>> 16) & 0xff;
931 cpu_cores
= siblings
;
932 logical_bits
= mask_bits (siblings
);
936 phys_id
= initial_apic_id
>> logical_bits
;
937 core_id
= (initial_apic_id
& ((1 << logical_bits
) - 1)) >> ht_bits
;
939 bufptr
+= __small_sprintf (bufptr
, "physical id\t: %d\n", phys_id
);
941 bufptr
+= __small_sprintf (bufptr
, "siblings\t: %u\n", siblings
);
942 bufptr
+= __small_sprintf (bufptr
, "core id\t\t: %d\n"
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
);
952 bufptr
+= __small_sprintf (bufptr
, "fpu\t\t: %s\n"
953 "fpu_exception\t: %s\n"
954 "cpuid level\t: %d\n"
956 (features1
& (1 << 0)) ? "yes" : "no",
957 (features1
& (1 << 0)) ? "yes" : "no",
959 print ("flags\t\t:");
960 if (features1
& (1 << 0))
962 if (features1
& (1 << 1))
964 if (features1
& (1 << 2))
966 if (features1
& (1 << 3))
968 if (features1
& (1 << 4))
970 if (features1
& (1 << 5))
972 if (features1
& (1 << 6))
974 if (features1
& (1 << 7))
976 if (features1
& (1 << 8))
978 if (features1
& (1 << 9))
980 if (features1
& (1 << 11))
982 if (features1
& (1 << 12))
984 if (features1
& (1 << 13))
986 if (features1
& (1 << 14))
988 if (features1
& (1 << 15))
990 if (features1
& (1 << 16))
992 if (features1
& (1 << 17))
994 if (features1
& (1 << 18))
996 if (features1
& (1 << 19))
998 if (is_intel
&& features1
& (1 << 21))
1000 if (is_intel
&& features1
& (1 << 22))
1002 if (features1
& (1 << 23))
1004 if (features1
& (1 << 24))
1006 if (features1
& (1 << 25))
1008 if (features1
& (1 << 26))
1010 if (is_intel
&& (features1
& (1 << 27)))
1012 if (features1
& (1 << 28))
1016 if (features1
& (1 << 29))
1018 if (features1
& (1 << 30))
1020 if (features1
& (1 << 31))
1024 if (is_amd
&& maxe
>= 0x80000001)
1026 cpuid (&unused
, &unused
, &unused
, &features1
, 0x80000001);
1028 if (features1
& (1 << 11))
1030 if (features1
& (1 << 19)) /* Huh? Not in AMD64 specs. */
1032 if (features1
& (1 << 20))
1034 if (features1
& (1 << 22))
1036 if (features1
& (1 << 25))
1037 print (" fxsr_opt");
1038 if (features1
& (1 << 26))
1040 if (features1
& (1 << 27))
1042 if (features1
& (1 << 29))
1044 if (features1
& (1 << 30)) /* 31th bit is on. */
1045 print (" 3dnowext");
1046 if (features1
& (1 << 31)) /* 32th bit (highest) is on. */
1050 if (features2
& (1 << 0))
1054 if (features2
& (1 << 2))
1056 if (features2
& (1 << 3))
1058 if (features2
& (1 << 4))
1060 if (features2
& (1 << 5))
1062 if (features2
& (1 << 6))
1064 if (features2
& (1 << 7))
1066 if (features2
& (1 << 8))
1068 if (features2
& (1 << 9))
1070 if (features2
& (1 << 10))
1072 if (features2
& (1 << 12))
1075 if (features2
& (1 << 13))
1079 if (features2
& (1 << 14))
1081 if (features2
& (1 << 15))
1083 if (features2
& (1 << 18))
1085 if (features2
& (1 << 19))
1087 if (features2
& (1 << 20))
1089 if (features2
& (1 << 21))
1091 if (features2
& (1 << 22))
1093 if (features2
& (1 << 23))
1095 if (features2
& (1 << 25))
1097 if (features2
& (1 << 26))
1099 if (features2
& (1 << 27))
1101 if (features2
& (1 << 28))
1103 if (features2
& (1 << 29))
1105 if (features2
& (1 << 30))
1107 if (features2
& (1 << 31))
1108 print (" hypervisor");
1111 if (maxe
>= 0x80000001)
1113 cpuid (&unused
, &unused
, &features1
, &unused
, 0x80000001);
1115 if (features1
& (1 << 0))
1117 if (features1
& (1 << 1))
1118 print (" cmp_legacy");
1121 if (features1
& (1 << 2))
1123 if (features1
& (1 << 3))
1125 if (features1
& (1 << 4))
1126 print (" cr8_legacy");
1127 if (features1
& (1 << 5))
1129 if (features1
& (1 << 6))
1131 if (features1
& (1 << 7))
1132 print (" misalignsse");
1133 if (features1
& (1 << 8))
1134 print (" 3dnowprefetch");
1135 if (features1
& (1 << 9))
1138 if (features1
& (1 << 10))
1142 if (features1
& (1 << 11))
1144 if (features1
& (1 << 12))
1146 if (features1
& (1 << 13))
1148 if (features1
& (1 << 15))
1150 if (features1
& (1 << 16))
1152 if (features1
& (1 << 17))
1154 if (features1
& (1 << 19))
1155 print (" nodeid_msr");
1156 if (features1
& (1 << 21))
1158 if (features1
& (1 << 22))
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");
1168 if (is_intel
) /* features scattered in various CPUID levels. */
1170 cpuid (&features1
, &unused
, &features2
, &unused
, 0x06);
1172 if (features1
& (1 << 1))
1174 if (features1
& (1 << 2))
1176 if (features2
& (1 << 3))
1179 cpuid (&features2
, &unused
, &unused
, &unused
, 0x0d, 1);
1180 if (features2
& (1 << 0))
1181 print (" xsaveopt");
1183 if (features1
& (1 << 4))
1185 if (features1
& (1 << 6))
1187 if (features1
& (1 << 0))
1190 if (is_intel
) /* Extended feature flags */
1192 cpuid (&unused
, &features1
, &unused
, &unused
, 0x07, 0);
1194 if (features1
& (1 << 0))
1195 print (" fsgsbase");
1196 if (features1
& (1 << 1))
1197 print (" tsc_adjust");
1198 if (features1
& (1 << 3))
1200 if (features1
& (1 << 4))
1202 if (features1
& (1 << 5))
1204 if (features1
& (1 << 7))
1206 if (features1
& (1 << 8))
1208 if (features1
& (1 << 9))
1210 if (features1
& (1 << 10))
1212 if (features1
& (1 << 11))
1214 if (features1
& (1 << 14))
1216 if (features1
& (1 << 16))
1218 if (features1
& (1 << 18))
1220 if (features1
& (1 << 19))
1222 if (features1
& (1 << 20))
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");
1236 /* TODO: bogomips */
1238 bufptr
+= __small_sprintf (bufptr
, "clflush size\t: %d\n"
1239 "cache_alignment\t: %d\n",
1243 if (maxe
>= 0x80000008) /* Address size. */
1245 uint32_t addr_size
, phys
, virt
;
1246 cpuid (&addr_size
, &unused
, &unused
, &unused
, 0x80000008);
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)
1253 bufptr
+= __small_sprintf (bufptr
, "address sizes\t: "
1254 "%u bits physical, "
1255 "%u bits virtual\n",
1259 if (maxe
>= 0x80000007) /* Advanced power management. */
1261 cpuid (&unused
, &unused
, &unused
, &features1
, 0x80000007);
1263 print ("power management:");
1264 if (features1
& (1 << 0))
1266 if (features1
& (1 << 1))
1268 if (features1
& (1 << 2))
1270 if (features1
& (1 << 3))
1272 if (features1
& (1 << 4))
1274 if (features1
& (1 << 5))
1276 if (features1
& (1 << 6))
1277 print (" 100mhzsteps");
1278 if (features1
& (1 << 7))
1279 print (" hwpstate");
1280 if (features1
& (1 << 9))
1282 if (features1
& (1 << 10))
1283 print (" eff_freq_ro");
1286 if (orig_affinity_mask
!= 0)
1288 if (wincap
.has_processor_groups ())
1289 SetThreadGroupAffinity (GetCurrentThread (), &orig_group_affinity
,
1292 SetThreadAffinityMask (GetCurrentThread (), orig_affinity_mask
);
1297 destbuf
= (char *) crealloc_abort (destbuf
, bufptr
- buf
);
1298 memcpy (destbuf
, buf
, bufptr
- buf
);
1299 return bufptr
- buf
;
1303 format_proc_partitions (void *, char *&destbuf
)
1305 OBJECT_ATTRIBUTES attr
;
1311 char *buf
= tp
.c_get ();
1313 char *ioctl_buf
= tp
.c_get ();
1314 PWCHAR mp_buf
= tp
.w_get ();
1315 WCHAR fpath
[MAX_PATH
];
1316 WCHAR gpath
[MAX_PATH
];
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
))
1326 debug_printf ("NtOpenDirectoryObject, status %y", status
);
1327 __seterrno_from_nt_status (status
);
1331 /* Traverse \Device directory ... */
1332 PDIRECTORY_BASIC_INFORMATION dbi
= (PDIRECTORY_BASIC_INFORMATION
)
1334 BOOLEAN restart
= TRUE
;
1335 bool got_one
= false;
1337 while (NT_SUCCESS (NtQueryDirectoryObject (dirhdl
, dbi
, 640, TRUE
, restart
,
1341 PARTITION_INFORMATION_EX
*pix
= NULL
;
1342 PARTITION_INFORMATION
*pi
= NULL
;
1345 unsigned long long size
;
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]))
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
,
1364 status
= NtOpenFile (&devhdl
, READ_CONTROL
, &attr
, &io
,
1365 FILE_SHARE_VALID_FLAGS
, 0);
1366 if (!NT_SUCCESS (status
))
1368 debug_printf ("NtOpenFile(%S), status %y", &upath
, status
);
1369 __seterrno_from_nt_status (status
);
1374 print ("major minor #blocks name win-mounts\n\n");
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
))
1381 pix
= (PARTITION_INFORMATION_EX
*) ioctl_buf
;
1382 size
= pix
->PartitionLength
.QuadPart
;
1384 else if (DeviceIoControl (devhdl
, IOCTL_DISK_GET_PARTITION_INFO
, NULL
, 0,
1385 ioctl_buf
, NT_MAX_PATH
, &bytes_read
, NULL
))
1387 pi
= (PARTITION_INFORMATION
*) ioctl_buf
;
1388 size
= pi
->PartitionLength
.QuadPart
;
1392 debug_printf ("DeviceIoControl (%S, "
1393 "IOCTL_DISK_GET_PARTITION_INFO{_EX}) %E", &upath
);
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
))
1404 PDRIVE_LAYOUT_INFORMATION_EX pdlix
= (PDRIVE_LAYOUT_INFORMATION_EX
)
1406 part_cnt
= pdlix
->PartitionCount
;
1407 pix
= pdlix
->PartitionEntry
;
1409 else if (DeviceIoControl (devhdl
, IOCTL_DISK_GET_DRIVE_LAYOUT
,
1410 NULL
, 0, ioctl_buf
, NT_MAX_PATH
, &bytes_read
, NULL
))
1412 PDRIVE_LAYOUT_INFORMATION pdli
= (PDRIVE_LAYOUT_INFORMATION
) ioctl_buf
;
1413 part_cnt
= pdli
->PartitionCount
;
1414 pi
= pdli
->PartitionEntry
;
1417 debug_printf ("DeviceIoControl(%S, "
1418 "IOCTL_DISK_GET_DRIVE_LAYOUT{_EX}): %E", &upath
);
1419 /* Loop over partitions. */
1421 for (DWORD i
= 0; i
< part_cnt
&& i
< 64; ++i
)
1427 size
= pix
->PartitionLength
.QuadPart
;
1428 part_num
= pix
->PartitionNumber
;
1433 size
= pi
->PartitionLength
.QuadPart
;
1434 part_num
= pi
->PartitionNumber
;
1437 /* A partition number of 0 denotes an extended partition or a
1438 filler entry as described in fhandler_dev_floppy::lock_partition.
1442 device
dev (drive_num
, part_num
);
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
,
1456 len
= strlen (dev
.name () + 5);
1459 for (PWCHAR p
= mp_buf
; *p
; p
= wcschr (p
, L
'\0') + 1)
1460 bufptr
+= __small_sprintf (bufptr
, " %W", p
);
1472 destbuf
= (char *) crealloc_abort (destbuf
, bufptr
- buf
);
1473 memcpy (destbuf
, buf
, bufptr
- buf
);
1474 return bufptr
- buf
;
1478 format_proc_self (void *, char *&destbuf
)
1480 destbuf
= (char *) crealloc_abort (destbuf
, 16);
1481 return __small_sprintf (destbuf
, "%d", getpid ());
1485 format_proc_cygdrive (void *, char *&destbuf
)
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 != "/"? */
1491 return dend
- destbuf
;
1495 format_proc_mounts (void *, char *&destbuf
)
1497 destbuf
= (char *) crealloc_abort (destbuf
, sizeof ("self/mounts"));
1498 return __small_sprintf (destbuf
, "self/mounts");
1502 format_proc_filesystems (void *, char *&destbuf
)
1505 char *buf
= tp
.c_get ();
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",
1514 destbuf
= (char *) crealloc_abort (destbuf
, bufptr
- buf
);
1515 memcpy (destbuf
, buf
, bufptr
- buf
);
1516 return bufptr
- buf
;
1520 format_proc_swaps (void *, char *&destbuf
)
1522 unsigned long long total
= 0ULL, used
= 0ULL;
1523 PSYSTEM_PAGEFILE_INFORMATION spi
= NULL
;
1525 NTSTATUS status
= STATUS_SUCCESS
;
1528 char *buf
= tp
.c_get ();
1531 spi
= (PSYSTEM_PAGEFILE_INFORMATION
) malloc (size
);
1534 status
= NtQuerySystemInformation (SystemPagefileInformation
, (PVOID
) spi
,
1536 if (status
== STATUS_INFO_LENGTH_MISMATCH
)
1539 spi
= (PSYSTEM_PAGEFILE_INFORMATION
) malloc (size
);
1541 status
= NtQuerySystemInformation (SystemPagefileInformation
,
1542 (PVOID
) spi
, size
, &size
);
1546 bufptr
+= __small_sprintf (bufptr
,
1547 "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
1549 if (spi
&& NT_SUCCESS (status
))
1551 PSYSTEM_PAGEFILE_INFORMATION spp
= spi
;
1552 char *filename
= tp
.c_get ();
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);
1562 while (spp
->NextEntryOffset
1563 && (spp
= (PSYSTEM_PAGEFILE_INFORMATION
)
1564 ((char *) spp
+ spp
->NextEntryOffset
)));
1570 destbuf
= (char *) crealloc_abort (destbuf
, bufptr
- buf
);
1571 memcpy (destbuf
, buf
, bufptr
- buf
);
1572 return bufptr
- buf
;
1576 format_proc_devices (void *, char *&destbuf
)
1579 char *buf
= tp
.c_get ();
1582 bufptr
+= __small_sprintf (bufptr
,
1583 "Character devices:\n"
1587 "%3d /dev/console\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
);
1614 destbuf
= (char *) crealloc_abort (destbuf
, bufptr
- buf
);
1615 memcpy (destbuf
, buf
, bufptr
- buf
);
1616 return bufptr
- buf
;
1620 format_proc_misc (void *, char *&destbuf
)
1623 char *buf
= tp
.c_get ();
1626 bufptr
+= __small_sprintf (bufptr
,
1629 _minor (FH_CLIPBOARD
), _minor (FH_WINDOWS
));
1631 destbuf
= (char *) crealloc_abort (destbuf
, bufptr
- buf
);
1632 memcpy (destbuf
, buf
, bufptr
- buf
);
1633 return bufptr
- buf
;