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>
34 #define _COMPILING_NEWLIB
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 *&);
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
}
79 #define PROC_DIR_COUNT 4
81 static const int PROC_LINK_COUNT
= (sizeof (proc_tab
) / sizeof (virt_tab_t
)) - 1;
83 /* name of the /proc filesystem */
84 const char proc
[] = "/proc";
85 const size_t proc_len
= sizeof (proc
) - 1;
87 /* bsearch compare function. */
89 proc_tab_cmp (const void *key
, const void *memb
)
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
] != '/')
98 /* Helper function to perform a binary search of the incoming pathname
99 against the alpha-sorted virtual file table. */
101 virt_tab_search (const char *path
, bool prefix
, const virt_tab_t
*table
,
104 virt_tab_t key
= { path
, 0, FH_NADA
, virt_none
, NULL
};
105 virt_tab_t
*entry
= (virt_tab_t
*) bsearch (&key
, table
, nelem
,
108 if (entry
&& (path
[entry
->name_len
] == '\0'
109 || (prefix
&& path
[entry
->name_len
] == '/')))
114 /* Auxillary function that returns the fhandler associated with the given
117 fhandler_proc::get_proc_fhandler (const char *path
)
119 debug_printf ("get_proc_fhandler(%s)", path
);
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
124 while (isdirsep (*path
))
127 /* Check if this is the root of the virtual filesystem (i.e. /proc). */
131 virt_tab_t
*entry
= virt_tab_search (path
, true, proc_tab
,
134 return entry
->fhandler
;
136 int pid
= atoi (path
);
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
)
145 bool has_subdir
= false;
147 if (isdirsep (*path
++))
154 /* The user is trying to access a non-existent subdirectory of /proc. */
157 /* Return FH_PROC so that we can return EROFS if the user is trying to
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. */
165 fhandler_proc::exists ()
167 const char *path
= get_name ();
168 debug_printf ("exists (%s)", path
);
172 virt_tab_t
*entry
= virt_tab_search (path
+ 1, false, proc_tab
,
176 fileid
= entry
- proc_tab
;
182 fhandler_proc::fhandler_proc ():
188 fhandler_proc::fstat (struct stat
*buf
)
190 const char *path
= get_name ();
191 debug_printf ("fstat (%s)", path
);
194 fhandler_base::fstat (buf
);
196 buf
->st_mode
&= ~_IFMT
& NO_W
;
200 winpids
pids ((DWORD
) 0);
202 buf
->st_mode
|= S_IFDIR
| S_IXUSR
| S_IXGRP
| S_IXOTH
;
203 buf
->st_nlink
= PROC_DIR_COUNT
+ 2 + pids
.npids
;
208 virt_tab_t
*entry
= virt_tab_search (path
+ 1, false, proc_tab
,
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
;
218 buf
->st_mode
&= NO_X
;
219 buf
->st_mode
|= S_IFREG
;
229 fhandler_proc::opendir (int fd
)
231 DIR *dir
= fhandler_virtual::opendir (fd
);
232 if (dir
&& !(dir
->__handle
= (void *) new winpids ((DWORD
) 0)))
242 fhandler_proc::closedir (DIR *dir
)
244 delete (winpids
*) dir
->__handle
;
245 return fhandler_virtual::closedir (dir
);
249 fhandler_proc::readdir (DIR *dir
, dirent
*de
)
252 if (dir
->__d_position
< PROC_LINK_COUNT
)
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
);
257 dir
->__flags
|= dirent_saw_dot
| dirent_saw_dot_dot
;
262 winpids
&pids
= *(winpids
*) dir
->__handle
;
265 for (unsigned i
= 0; i
< pids
.npids
; i
++)
266 if (found
++ == dir
->__d_position
- PROC_LINK_COUNT
)
268 __small_sprintf (de
->d_name
, "%d", pids
[i
]->pid
);
276 syscall_printf ("%d = readdir(%p, %p) (%s)", res
, dir
, de
, de
->d_name
);
281 fhandler_proc::open (int flags
, mode_t mode
)
283 int proc_file_no
= -1;
285 int res
= fhandler_virtual::open (flags
, mode
);
293 path
= get_name () + proc_len
;
297 if ((flags
& (O_CREAT
| O_EXCL
)) == (O_CREAT
| O_EXCL
))
303 else if (flags
& O_WRONLY
)
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
),
322 if (proc_tab
[i
].fhandler
!= FH_PROC
)
324 if ((flags
& (O_CREAT
| O_EXCL
)) == (O_CREAT
| O_EXCL
))
330 else if (flags
& O_WRONLY
)
344 if (proc_file_no
== -1)
359 if (flags
& O_WRONLY
)
366 fileid
= proc_file_no
;
367 if (!fill_filebuf ())
373 if (flags
& O_APPEND
)
380 set_flags ((flags
& ~O_TEXT
) | O_BINARY
);
383 syscall_printf ("%d = fhandler_proc::open(%y, 0%o)", res
, flags
, mode
);
388 fhandler_proc::fill_filebuf ()
390 if (fileid
< PROC_LINK_COUNT
&& proc_tab
[fileid
].format_func
)
392 filesize
= proc_tab
[fileid
].format_func (NULL
, filebuf
);
400 format_proc_version (void *, char *&destbuf
)
403 char *buf
= tp
.c_get ();
405 struct utsname 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
);
412 destbuf
= (char *) crealloc_abort (destbuf
, bufptr
- buf
);
413 memcpy (destbuf
, buf
, bufptr
- buf
);
418 format_proc_loadavg (void *, char *&destbuf
)
420 extern int get_process_state (DWORD dwProcessId
);
421 unsigned int running
= 0;
422 winpids
pids ((DWORD
) 0);
424 for (unsigned i
= 0; i
< pids
.npids
; i
++)
425 switch (get_process_state (i
)) {
432 double loadavg
[3] = { 0.0, 0.0, 0.0 };
433 getloadavg (loadavg
, 3);
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
);
442 format_proc_meminfo (void *, char *&destbuf
)
444 unsigned long long mem_total
, mem_free
, swap_total
, swap_free
;
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
;
453 destbuf
= (char *) crealloc_abort (destbuf
, 512);
454 return sprintf (destbuf
, "MemTotal: %10llu kB\n"
455 "MemFree: %10llu 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);
468 format_proc_uptime (void *, char *&destbuf
)
470 unsigned long long uptime
= 0ULL, idle_time
= 0ULL;
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
)
481 status
= NtQuerySystemInformation (SystemTimeOfDayInformation
, &stodi
,
483 if (NT_SUCCESS (status
))
484 uptime
= (stodi
.CurrentTime
.QuadPart
- stodi
.BootTime
.QuadPart
) / 100000ULL;
486 debug_printf ("NtQuerySystemInformation(SystemTimeOfDayInformation), "
487 "status %y", status
);
489 if (NT_SUCCESS (NtQuerySystemInformation (SystemPerformanceInformation
,
490 spi
, sizeof_spi
, NULL
)))
491 idle_time
= (spi
->IdleTime
.QuadPart
/ wincap
.cpu_count ())
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));
501 format_proc_stat (void *, char *&destbuf
)
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;
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
)
514 SYSTEM_TIMEOFDAY_INFORMATION stodi
;
517 char *buf
= tp
.c_get ();
520 SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION spt
[wincap
.cpu_count ()];
521 status
= NtQuerySystemInformation (SystemProcessorPerformanceInformation
,
523 sizeof spt
[0] * wincap
.cpu_count (), NULL
);
524 if (!NT_SUCCESS (status
))
525 debug_printf ("NtQuerySystemInformation(SystemProcessorPerformanceInformation), "
526 "status %y", status
);
529 unsigned long long user_time
= 0ULL, kernel_time
= 0ULL, idle_time
= 0ULL;
530 for (unsigned long i
= 0; i
< wincap
.cpu_count (); i
++)
532 kernel_time
+= (spt
[i
].KernelTime
.QuadPart
- spt
[i
].IdleTime
.QuadPart
)
534 user_time
+= spt
[i
].UserTime
.QuadPart
* HZ
/ 10000000ULL;
535 idle_time
+= spt
[i
].IdleTime
.QuadPart
* HZ
/ 10000000ULL;
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
++)
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
);
551 status
= NtQuerySystemInformation (SystemPerformanceInformation
,
552 (PVOID
) spi
, sizeof_spi
, NULL
);
553 if (!NT_SUCCESS (status
))
555 debug_printf ("NtQuerySystemInformation(SystemPerformanceInformation)"
556 ", status %y", status
);
557 memset (spi
, 0, sizeof_spi
);
559 status
= NtQuerySystemInformation (SystemTimeOfDayInformation
,
560 (PVOID
) &stodi
, sizeof stodi
, NULL
);
561 if (!NT_SUCCESS (status
))
562 debug_printf ("NtQuerySystemInformation(SystemTimeOfDayInformation), "
563 "status %y", status
);
565 if (!NT_SUCCESS (status
))
567 __seterrno_from_nt_status (status
);
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
);
582 eobuf
+= __small_sprintf (eobuf
, "page %u %u\n"
592 destbuf
= (char *) crealloc_abort (destbuf
, eobuf
- buf
);
593 memcpy (destbuf
, buf
, eobuf
- buf
);
597 #define add_size(p,s) ((p) = ((__typeof__(p))((PBYTE)(p)+(s))))
598 #define print(x) { bufptr = stpcpy (bufptr, (x)); }
600 static inline uint32_t
601 get_msb (uint32_t in
)
603 return 32 - __builtin_clz (in
);
606 static inline uint32_t
607 mask_bits (uint32_t in
)
609 uint32_t bits
= get_msb (in
) - 1;
616 format_proc_cpuinfo (void *, char *&destbuf
)
618 WCHAR cpu_key
[128], *cpu_num_p
;
619 DWORD orig_affinity_mask
= 0;
620 GROUP_AFFINITY orig_group_affinity
;
622 const int BUFSIZE
= 256;
627 WCHAR w
[BUFSIZE
/ sizeof (WCHAR
)];
633 char *buf
= tp
.c_get ();
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. */
640 if (wincap
.has_processor_groups ())
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
))
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
)
654 //num_cpu_groups = plpi->Group.MaximumGroupCount;
656 = plpi
->Group
.GroupInfo
[0].MaximumProcessorCount
;
662 cpu_num_p
= wcpcpy (cpu_key
, L
"\\Registry\\Machine\\HARDWARE\\DESCRIPTION"
663 "\\System\\CentralProcessor\\");
664 for (cpu_number
= 0; ; cpu_number
++)
666 __small_swprintf (cpu_num_p
, L
"%d", cpu_number
);
667 if (!NT_SUCCESS (RtlCheckRegistryKey (RTL_REGISTRY_ABSOLUTE
, cpu_key
)))
672 WORD cpu_group
= cpu_number
/ num_cpu_per_group
;
673 KAFFINITY cpu_mask
= 1L << (cpu_number
% num_cpu_per_group
);
675 if (wincap
.has_processor_groups ())
677 GROUP_AFFINITY affinity
= {
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. */
689 orig_affinity_mask
= SetThreadAffinityMask (GetCurrentThread (),
691 if (orig_affinity_mask
== 0)
692 debug_printf ("SetThreadAffinityMask failed %E");
694 /* I'm not sure whether the thread changes processor immediately
695 and I'm not sure whether this function will cause the thread
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 }
706 RtlQueryRegistryValues (RTL_REGISTRY_ABSOLUTE
, cpu_key
, tab
,
708 bufptr
+= __small_sprintf (bufptr
, "processor\t: %d\n", cpu_number
);
709 uint32_t maxf
, vendor_id
[4], unused
;
711 cpuid (&maxf
, &vendor_id
[0], &vendor_id
[2], &vendor_id
[1], 0x00000000);
715 /* Vendor identification. */
716 bool is_amd
= false, is_intel
= false;
717 if (!strcmp ((char*)vendor_id
, "AuthenticAMD"))
719 else if (!strcmp ((char*)vendor_id
, "GenuineIntel"))
722 bufptr
+= __small_sprintf (bufptr
, "vendor_id\t: %s\n",
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;
732 family
+= (cpuid_sig
>> 20) & 0xff;
734 model
+= ((cpuid_sig
>> 16) & 0x0f) << 4;
737 cpuid (&maxe
, &unused
, &unused
, &unused
, 0x80000000);
738 if (maxe
>= 0x80000004)
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);
750 /* Could implement a lookup table here if someone needs it. */
751 strcpy (in_buf
.s
, "unknown");
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;
762 extern long get_cpu_cache_intel (int sysc
, uint32_t maxf
);
765 /* As on Linux, don't check for L3 cache. */
766 cs
= get_cpu_cache_intel (_SC_LEVEL2_CACHE_SIZE
, maxf
);
769 cs
= get_cpu_cache_intel (_SC_LEVEL1_ICACHE_SIZE
, maxf
);
772 cs
= get_cpu_cache_intel (_SC_LEVEL1_DCACHE_SIZE
, maxf
);
778 if (cache_size
!= -1)
783 extern long get_cpu_cache_amd (int sysc
, uint32_t maxe
);
786 cs
= get_cpu_cache_amd (_SC_LEVEL3_CACHE_SIZE
, maxe
);
788 cs
= get_cpu_cache_amd (_SC_LEVEL2_CACHE_SIZE
, maxe
);
791 cs
= get_cpu_cache_amd (_SC_LEVEL1_ICACHE_SIZE
, maxe
);
794 cs
= get_cpu_cache_amd (_SC_LEVEL1_DCACHE_SIZE
, maxe
);
800 if (cache_size
!= -1)
803 bufptr
+= __small_sprintf (bufptr
, "cpu family\t: %d\n"
807 "cpu MHz\t\t: %d.000\n",
810 in_buf
.s
+ strspn (in_buf
.s
, " "),
815 bufptr
+= __small_sprintf (bufptr
, "cache size\t: %d KB\n",
818 /* Recognize multi-core CPUs. */
819 if (features1
& (1 << 28)) /* HTT */
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
;
827 uint32_t logical_bits
= 0; /* # of logical core bits in apicid. */
828 uint32_t ht_bits
= 0; /* # of thread bits in apic_id. */
833 if (maxf
>= 0x0000000b) /* topoext supported? */
835 uint32_t bits
, logical
, level
, unused
;
838 cpuid (&bits
, &logical
, &level
, &unused
,
840 /* Even if topoext is supposedly supported, it can return
842 if (bits
!= 0 && ((level
>> 8) & 0xff) == 1)
845 ht_bits
= (bits
& 0x1f);
846 siblings
= (logical
& 0xffff);
847 cpu_cores
= siblings
;
848 for (uint32_t idx
= 1; ; ++idx
)
850 cpuid (&bits
, &logical
, &level
, &initial_apic_id
,
853 uint32_t level_type
= ((level
>> 8) & 0xff);
854 if (level_type
== 0) /* Invalid */
856 if (level_type
== 2) /* Core */
858 logical_bits
= (bits
& 0x1f);
859 siblings
= (logical
& 0xffff);
860 cpu_cores
= siblings
>> ht_bits
;
866 if (!valid
&& maxf
>= 0x00000004)
868 uint32_t apic_reserved
;
870 cpuid (&apic_reserved
, &unused
, &unused
, &unused
,
872 if (apic_reserved
& 0x1f)
875 cpu_cores
= ((apic_reserved
>> 26) & 0x3f) + 1;
876 siblings
= (extra_info
>> 16) & 0xff;
877 if (siblings
<= 1) /* HT could be fused out */
879 logical_bits
= mask_bits (cpu_cores
);
884 logical_bits
= mask_bits (siblings
);
885 ht_bits
= mask_bits (siblings
/ cpu_cores
);
889 if (!valid
) /* single core, multi thread */
892 siblings
= (extra_info
>> 16) & 0xff;
893 logical_bits
= mask_bits (siblings
);
894 ht_bits
= logical_bits
;
899 if (maxe
>= 0x8000001e)
901 uint32_t cus
, core_info
;
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
;
911 else if (maxe
>= 0x80000008)
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;
920 logical_bits
= mask_bits (siblings
);
925 siblings
= (extra_info
>> 16) & 0xff;
926 cpu_cores
= siblings
;
927 logical_bits
= mask_bits (siblings
);
931 phys_id
= initial_apic_id
>> logical_bits
;
932 core_id
= (initial_apic_id
& ((1 << logical_bits
) - 1)) >> ht_bits
;
934 bufptr
+= __small_sprintf (bufptr
, "physical id\t: %d\n", phys_id
);
936 bufptr
+= __small_sprintf (bufptr
, "siblings\t: %u\n", siblings
);
937 bufptr
+= __small_sprintf (bufptr
, "core id\t\t: %d\n"
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
);
947 bufptr
+= __small_sprintf (bufptr
, "fpu\t\t: %s\n"
948 "fpu_exception\t: %s\n"
949 "cpuid level\t: %d\n"
951 (features1
& (1 << 0)) ? "yes" : "no",
952 (features1
& (1 << 0)) ? "yes" : "no",
954 print ("flags\t\t:");
955 if (features1
& (1 << 0))
957 if (features1
& (1 << 1))
959 if (features1
& (1 << 2))
961 if (features1
& (1 << 3))
963 if (features1
& (1 << 4))
965 if (features1
& (1 << 5))
967 if (features1
& (1 << 6))
969 if (features1
& (1 << 7))
971 if (features1
& (1 << 8))
973 if (features1
& (1 << 9))
975 if (features1
& (1 << 11))
977 if (features1
& (1 << 12))
979 if (features1
& (1 << 13))
981 if (features1
& (1 << 14))
983 if (features1
& (1 << 15))
985 if (features1
& (1 << 16))
987 if (features1
& (1 << 17))
989 if (features1
& (1 << 18))
991 if (features1
& (1 << 19))
993 if (is_intel
&& features1
& (1 << 21))
995 if (is_intel
&& features1
& (1 << 22))
997 if (features1
& (1 << 23))
999 if (features1
& (1 << 24))
1001 if (features1
& (1 << 25))
1003 if (features1
& (1 << 26))
1005 if (is_intel
&& (features1
& (1 << 27)))
1007 if (features1
& (1 << 28))
1011 if (features1
& (1 << 29))
1013 if (features1
& (1 << 30))
1015 if (features1
& (1 << 31))
1019 if (is_amd
&& maxe
>= 0x80000001)
1021 cpuid (&unused
, &unused
, &unused
, &features1
, 0x80000001);
1023 if (features1
& (1 << 11))
1025 if (features1
& (1 << 19)) /* Huh? Not in AMD64 specs. */
1027 if (features1
& (1 << 20))
1029 if (features1
& (1 << 22))
1031 if (features1
& (1 << 25))
1032 print (" fxsr_opt");
1033 if (features1
& (1 << 26))
1035 if (features1
& (1 << 27))
1037 if (features1
& (1 << 29))
1039 if (features1
& (1 << 30)) /* 31th bit is on. */
1040 print (" 3dnowext");
1041 if (features1
& (1 << 31)) /* 32th bit (highest) is on. */
1045 if (features2
& (1 << 0))
1049 if (features2
& (1 << 2))
1051 if (features2
& (1 << 3))
1053 if (features2
& (1 << 4))
1055 if (features2
& (1 << 5))
1057 if (features2
& (1 << 6))
1059 if (features2
& (1 << 7))
1061 if (features2
& (1 << 8))
1063 if (features2
& (1 << 9))
1065 if (features2
& (1 << 10))
1067 if (features2
& (1 << 12))
1070 if (features2
& (1 << 13))
1074 if (features2
& (1 << 14))
1076 if (features2
& (1 << 15))
1078 if (features2
& (1 << 18))
1080 if (features2
& (1 << 19))
1082 if (features2
& (1 << 20))
1084 if (features2
& (1 << 21))
1086 if (features2
& (1 << 22))
1088 if (features2
& (1 << 23))
1090 if (features2
& (1 << 25))
1092 if (features2
& (1 << 26))
1094 if (features2
& (1 << 27))
1096 if (features2
& (1 << 28))
1098 if (features2
& (1 << 29))
1100 if (features2
& (1 << 30))
1102 if (features2
& (1 << 31))
1103 print (" hypervisor");
1106 if (maxe
>= 0x80000001)
1108 cpuid (&unused
, &unused
, &features1
, &unused
, 0x80000001);
1110 if (features1
& (1 << 0))
1112 if (features1
& (1 << 1))
1113 print (" cmp_legacy");
1116 if (features1
& (1 << 2))
1118 if (features1
& (1 << 3))
1120 if (features1
& (1 << 4))
1121 print (" cr8_legacy");
1122 if (features1
& (1 << 5))
1124 if (features1
& (1 << 6))
1126 if (features1
& (1 << 7))
1127 print (" misalignsse");
1128 if (features1
& (1 << 8))
1129 print (" 3dnowprefetch");
1130 if (features1
& (1 << 9))
1133 if (features1
& (1 << 10))
1137 if (features1
& (1 << 11))
1139 if (features1
& (1 << 12))
1141 if (features1
& (1 << 13))
1143 if (features1
& (1 << 15))
1145 if (features1
& (1 << 16))
1147 if (features1
& (1 << 17))
1149 if (features1
& (1 << 19))
1150 print (" nodeid_msr");
1151 if (features1
& (1 << 21))
1153 if (features1
& (1 << 22))
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");
1163 if (is_intel
) /* features scattered in various CPUID levels. */
1165 cpuid (&features1
, &unused
, &features2
, &unused
, 0x06);
1167 if (features1
& (1 << 1))
1169 if (features1
& (1 << 2))
1171 if (features2
& (1 << 3))
1174 cpuid (&features2
, &unused
, &unused
, &unused
, 0x0d, 1);
1175 if (features2
& (1 << 0))
1176 print (" xsaveopt");
1178 if (features1
& (1 << 4))
1180 if (features1
& (1 << 6))
1182 if (features1
& (1 << 0))
1185 if (is_intel
) /* Extended feature flags */
1187 cpuid (&unused
, &features1
, &unused
, &unused
, 0x07, 0);
1189 if (features1
& (1 << 0))
1190 print (" fsgsbase");
1191 if (features1
& (1 << 1))
1192 print (" tsc_adjust");
1193 if (features1
& (1 << 3))
1195 if (features1
& (1 << 4))
1197 if (features1
& (1 << 5))
1199 if (features1
& (1 << 7))
1201 if (features1
& (1 << 8))
1203 if (features1
& (1 << 9))
1205 if (features1
& (1 << 10))
1207 if (features1
& (1 << 11))
1209 if (features1
& (1 << 14))
1211 if (features1
& (1 << 16))
1213 if (features1
& (1 << 18))
1215 if (features1
& (1 << 19))
1217 if (features1
& (1 << 20))
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");
1231 /* TODO: bogomips */
1233 bufptr
+= __small_sprintf (bufptr
, "clflush size\t: %d\n"
1234 "cache_alignment\t: %d\n",
1238 if (maxe
>= 0x80000008) /* Address size. */
1240 uint32_t addr_size
, phys
, virt
;
1241 cpuid (&addr_size
, &unused
, &unused
, &unused
, 0x80000008);
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)
1248 bufptr
+= __small_sprintf (bufptr
, "address sizes\t: "
1249 "%u bits physical, "
1250 "%u bits virtual\n",
1254 if (maxe
>= 0x80000007) /* Advanced power management. */
1256 cpuid (&unused
, &unused
, &unused
, &features1
, 0x80000007);
1258 print ("power management:");
1259 if (features1
& (1 << 0))
1261 if (features1
& (1 << 1))
1263 if (features1
& (1 << 2))
1265 if (features1
& (1 << 3))
1267 if (features1
& (1 << 4))
1269 if (features1
& (1 << 5))
1271 if (features1
& (1 << 6))
1272 print (" 100mhzsteps");
1273 if (features1
& (1 << 7))
1274 print (" hwpstate");
1275 if (features1
& (1 << 9))
1277 if (features1
& (1 << 10))
1278 print (" eff_freq_ro");
1281 if (orig_affinity_mask
!= 0)
1283 if (wincap
.has_processor_groups ())
1284 SetThreadGroupAffinity (GetCurrentThread (), &orig_group_affinity
,
1287 SetThreadAffinityMask (GetCurrentThread (), orig_affinity_mask
);
1292 destbuf
= (char *) crealloc_abort (destbuf
, bufptr
- buf
);
1293 memcpy (destbuf
, buf
, bufptr
- buf
);
1294 return bufptr
- buf
;
1298 format_proc_partitions (void *, char *&destbuf
)
1300 OBJECT_ATTRIBUTES attr
;
1306 char *buf
= tp
.c_get ();
1308 char *ioctl_buf
= tp
.c_get ();
1309 PWCHAR mp_buf
= tp
.w_get ();
1310 WCHAR fpath
[MAX_PATH
];
1311 WCHAR gpath
[MAX_PATH
];
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
))
1321 debug_printf ("NtOpenDirectoryObject, status %y", status
);
1322 __seterrno_from_nt_status (status
);
1326 /* Traverse \Device directory ... */
1327 PDIRECTORY_BASIC_INFORMATION dbi
= (PDIRECTORY_BASIC_INFORMATION
)
1329 BOOLEAN restart
= TRUE
;
1330 bool got_one
= false;
1332 while (NT_SUCCESS (NtQueryDirectoryObject (dirhdl
, dbi
, 640, TRUE
, restart
,
1336 PARTITION_INFORMATION_EX
*pix
= NULL
;
1337 PARTITION_INFORMATION
*pi
= NULL
;
1340 unsigned long long size
;
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]))
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
,
1359 status
= NtOpenFile (&devhdl
, READ_CONTROL
, &attr
, &io
,
1360 FILE_SHARE_VALID_FLAGS
, 0);
1361 if (!NT_SUCCESS (status
))
1363 debug_printf ("NtOpenFile(%S), status %y", &upath
, status
);
1364 __seterrno_from_nt_status (status
);
1369 print ("major minor #blocks name win-mounts\n\n");
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
))
1376 pix
= (PARTITION_INFORMATION_EX
*) ioctl_buf
;
1377 size
= pix
->PartitionLength
.QuadPart
;
1379 else if (DeviceIoControl (devhdl
, IOCTL_DISK_GET_PARTITION_INFO
, NULL
, 0,
1380 ioctl_buf
, NT_MAX_PATH
, &bytes_read
, NULL
))
1382 pi
= (PARTITION_INFORMATION
*) ioctl_buf
;
1383 size
= pi
->PartitionLength
.QuadPart
;
1387 debug_printf ("DeviceIoControl (%S, "
1388 "IOCTL_DISK_GET_PARTITION_INFO{_EX}) %E", &upath
);
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
))
1399 PDRIVE_LAYOUT_INFORMATION_EX pdlix
= (PDRIVE_LAYOUT_INFORMATION_EX
)
1401 part_cnt
= pdlix
->PartitionCount
;
1402 pix
= pdlix
->PartitionEntry
;
1404 else if (DeviceIoControl (devhdl
, IOCTL_DISK_GET_DRIVE_LAYOUT
,
1405 NULL
, 0, ioctl_buf
, NT_MAX_PATH
, &bytes_read
, NULL
))
1407 PDRIVE_LAYOUT_INFORMATION pdli
= (PDRIVE_LAYOUT_INFORMATION
) ioctl_buf
;
1408 part_cnt
= pdli
->PartitionCount
;
1409 pi
= pdli
->PartitionEntry
;
1412 debug_printf ("DeviceIoControl(%S, "
1413 "IOCTL_DISK_GET_DRIVE_LAYOUT{_EX}): %E", &upath
);
1414 /* Loop over partitions. */
1416 for (DWORD i
= 0; i
< part_cnt
&& i
< 64; ++i
)
1422 size
= pix
->PartitionLength
.QuadPart
;
1423 part_num
= pix
->PartitionNumber
;
1428 size
= pi
->PartitionLength
.QuadPart
;
1429 part_num
= pi
->PartitionNumber
;
1432 /* A partition number of 0 denotes an extended partition or a
1433 filler entry as described in fhandler_dev_floppy::lock_partition.
1437 device
dev (drive_num
, part_num
);
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
,
1451 len
= strlen (dev
.name () + 5);
1454 for (PWCHAR p
= mp_buf
; *p
; p
= wcschr (p
, L
'\0') + 1)
1455 bufptr
+= __small_sprintf (bufptr
, " %W", p
);
1467 destbuf
= (char *) crealloc_abort (destbuf
, bufptr
- buf
);
1468 memcpy (destbuf
, buf
, bufptr
- buf
);
1469 return bufptr
- buf
;
1473 format_proc_self (void *, char *&destbuf
)
1475 destbuf
= (char *) crealloc_abort (destbuf
, 16);
1476 return __small_sprintf (destbuf
, "%d", getpid ());
1480 format_proc_cygdrive (void *, char *&destbuf
)
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 != "/"? */
1486 return dend
- destbuf
;
1490 format_proc_mounts (void *, char *&destbuf
)
1492 destbuf
= (char *) crealloc_abort (destbuf
, sizeof ("self/mounts"));
1493 return __small_sprintf (destbuf
, "self/mounts");
1497 format_proc_filesystems (void *, char *&destbuf
)
1500 char *buf
= tp
.c_get ();
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",
1509 destbuf
= (char *) crealloc_abort (destbuf
, bufptr
- buf
);
1510 memcpy (destbuf
, buf
, bufptr
- buf
);
1511 return bufptr
- buf
;
1515 format_proc_swaps (void *, char *&destbuf
)
1517 unsigned long long total
= 0ULL, used
= 0ULL;
1518 PSYSTEM_PAGEFILE_INFORMATION spi
= NULL
;
1520 NTSTATUS status
= STATUS_SUCCESS
;
1523 char *buf
= tp
.c_get ();
1526 spi
= (PSYSTEM_PAGEFILE_INFORMATION
) malloc (size
);
1529 status
= NtQuerySystemInformation (SystemPagefileInformation
, (PVOID
) spi
,
1531 if (status
== STATUS_INFO_LENGTH_MISMATCH
)
1534 spi
= (PSYSTEM_PAGEFILE_INFORMATION
) malloc (size
);
1536 status
= NtQuerySystemInformation (SystemPagefileInformation
,
1537 (PVOID
) spi
, size
, &size
);
1541 bufptr
+= __small_sprintf (bufptr
,
1542 "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
1544 if (spi
&& NT_SUCCESS (status
))
1546 PSYSTEM_PAGEFILE_INFORMATION spp
= spi
;
1547 char *filename
= tp
.c_get ();
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);
1557 while (spp
->NextEntryOffset
1558 && (spp
= (PSYSTEM_PAGEFILE_INFORMATION
)
1559 ((char *) spp
+ spp
->NextEntryOffset
)));
1565 destbuf
= (char *) crealloc_abort (destbuf
, bufptr
- buf
);
1566 memcpy (destbuf
, buf
, bufptr
- buf
);
1567 return bufptr
- buf
;
1571 format_proc_devices (void *, char *&destbuf
)
1574 char *buf
= tp
.c_get ();
1577 bufptr
+= __small_sprintf (bufptr
,
1578 "Character devices:\n"
1582 "%3d /dev/console\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
);
1609 destbuf
= (char *) crealloc_abort (destbuf
, bufptr
- buf
);
1610 memcpy (destbuf
, buf
, bufptr
- buf
);
1611 return bufptr
- buf
;
1615 format_proc_misc (void *, char *&destbuf
)
1618 char *buf
= tp
.c_get ();
1621 bufptr
+= __small_sprintf (bufptr
,
1624 _minor (FH_CLIPBOARD
), _minor (FH_WINDOWS
));
1626 destbuf
= (char *) crealloc_abort (destbuf
, bufptr
- buf
);
1627 memcpy (destbuf
, buf
, bufptr
- buf
);
1628 return bufptr
- buf
;