66using System . Runtime . InteropServices ;
77using System . Text ;
88
9- using size_t = System . IntPtr ;
10-
119// This implements shim for sysctl calls.
1210// They are available on BSD systems - FreeBSD, OSX and others.
1311// Linux has sysctl() but it is deprecated as well as it is missing sysctlbyname()
@@ -17,68 +15,69 @@ internal static partial class Interop
1715 internal static partial class Sys
1816 {
1917 [ LibraryImport ( Libraries . SystemNative , EntryPoint = "SystemNative_Sysctl" , SetLastError = true ) ]
20- private static unsafe partial int Sysctl ( int * name , int namelen , void * value , size_t * len ) ;
21-
22- // This is 'raw' sysctl call, only wrapped to allocate memory if needed
23- // caller always needs to free returned buffer using Marshal.FreeHGlobal()
18+ private static unsafe partial int Sysctl ( int * name , uint namelen , void * value , nuint * len ) ;
2419
25- internal static unsafe void Sysctl ( ReadOnlySpan < int > name , ref byte * value , ref int len )
20+ private static unsafe void Sysctl ( ReadOnlySpan < int > name , ref byte * value , ref uint len )
2621 {
27- fixed ( int * ptr = & MemoryMarshal . GetReference ( name ) )
22+ fixed ( int * name_ptr = & MemoryMarshal . GetReference ( name ) )
2823 {
29- Sysctl ( ptr , name . Length , ref value , ref len ) ;
30- }
31- }
24+ uint name_len = ( uint ) name . Length ;
25+ nuint bytesLength = len ;
26+ int ret ;
27+ bool autoSize = ( value == null && len == 0 ) ;
3228
33- private static unsafe void Sysctl ( int * name , int name_len , ref byte * value , ref int len )
34- {
35- nint bytesLength = len ;
36- int ret = - 1 ;
37- bool autoSize = ( value == null && len == 0 ) ;
38-
39- if ( autoSize )
40- {
41- // do one try to see how much data we need
42- ret = Sysctl ( name , name_len , value , & bytesLength ) ;
43- if ( ret != 0 )
29+ if ( autoSize )
4430 {
45- throw new InvalidOperationException ( SR . Format ( SR . InvalidSysctl , * name , Marshal . GetLastPInvokeError ( ) ) ) ;
31+ // do one try to see how much data we need
32+ ret = Sysctl ( name , name_len , value , & bytesLength ) ;
33+ if ( ret != 0 )
34+ {
35+ ThrowInvalidSysctlException ( name , Marshal . GetLastPInvokeError ( ) ) ;
36+ }
37+ value = ( byte * ) NativeMemory . Alloc ( bytesLength ) ;
4638 }
47- value = ( byte * ) Marshal . AllocHGlobal ( ( int ) bytesLength ) ;
48- }
4939
50- ret = Sysctl ( name , name_len , value , & bytesLength ) ;
51- while ( autoSize && ret != 0 && GetLastErrorInfo ( ) . Error == Error . ENOMEM )
52- {
53- // Do not use ReAllocHGlobal() here: we don't care about
54- // previous contents, and proper checking of value returned
55- // will make code more complex.
56- Marshal . FreeHGlobal ( ( IntPtr ) value ) ;
57- if ( ( int ) bytesLength == int . MaxValue )
58- {
59- throw new OutOfMemoryException ( ) ;
60- }
61- if ( ( int ) bytesLength >= int . MaxValue / 2 )
62- {
63- bytesLength = int . MaxValue ;
64- }
65- else
40+ ret = Sysctl ( name , name_len , value , & bytesLength ) ;
41+ while ( autoSize && ret != 0 && GetLastErrorInfo ( ) . Error == Error . ENOMEM )
6642 {
67- bytesLength = ( int ) bytesLength * 2 ;
43+ // Do not realloc here: we don't care about
44+ // previous contents, and proper checking of value returned
45+ // will make code more complex.
46+ NativeMemory . Free ( value ) ;
47+ if ( ( int ) bytesLength == int . MaxValue )
48+ {
49+ throw new OutOfMemoryException ( ) ;
50+ }
51+ if ( ( int ) bytesLength >= int . MaxValue / 2 )
52+ {
53+ bytesLength = int . MaxValue ;
54+ }
55+ else
56+ {
57+ bytesLength *= 2 ;
58+ }
59+ value = ( byte * ) NativeMemory . Alloc ( bytesLength ) ;
60+ ret = Sysctl ( name , name_len , value , & bytesLength ) ;
6861 }
69- value = ( byte * ) Marshal . AllocHGlobal ( bytesLength ) ;
70- ret = Sysctl ( name , name_len , value , & bytesLength ) ;
71- }
72- if ( ret != 0 )
73- {
74- if ( autoSize )
62+ if ( ret != 0 )
7563 {
76- Marshal . FreeHGlobal ( ( IntPtr ) value ) ;
64+ nint errno = Marshal . GetLastPInvokeError ( ) ;
65+ if ( autoSize )
66+ {
67+ NativeMemory . Free ( value ) ;
68+ }
69+ ThrowInvalidSysctlException ( name , errno ) ;
7770 }
78- throw new InvalidOperationException ( SR . Format ( SR . InvalidSysctl , * name , Marshal . GetLastPInvokeError ( ) ) ) ;
71+
72+ len = ( uint ) bytesLength ;
7973 }
74+ }
8075
81- len = ( int ) bytesLength ;
76+ static void ThrowInvalidSysctlException ( ReadOnlySpan < int > name , nint errno )
77+ {
78+ throw new InvalidOperationException ( SR . Format ( SR . InvalidSysctl ,
79+ string . Join ( "," , name . ToArray ( ) )
80+ errno) ) ;
8281 }
8382 }
8483}
0 commit comments