FPPS4/sys/kern/kern_sysctl.pas

932 lines
22 KiB
Plaintext

unit kern_sysctl;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
const
CTL_MAXNAME=24; // largest number of components supported
CTLTYPE =$f; // Mask for the type
CTLTYPE_NODE =1; // name is a node
CTLTYPE_INT =2; // name describes an integer
CTLTYPE_STRING=3; // name describes a string
CTLTYPE_S64 =4; // name describes a signed 64-bit number
CTLTYPE_OPAQUE=5; // name describes a structure
CTLTYPE_STRUCT=CTLTYPE_OPAQUE; // name describes a structure
CTLTYPE_UINT =6; // name describes an unsigned integer
CTLTYPE_LONG =7; // name describes a long
CTLTYPE_ULONG =8; // name describes an unsigned long
CTLTYPE_U64 =9; // name describes an unsigned 64-bit number
CTLFLAG_RD =$80000000; // Allow reads of variable
CTLFLAG_WR =$40000000; // Allow writes to the variable
CTLFLAG_RW =(CTLFLAG_RD or CTLFLAG_WR);
CTLFLAG_ANYBODY=$10000000; // All users can set this var
CTLFLAG_SECURE =$08000000; // Permit set only if securelevel<=0
CTLFLAG_PRISON =$04000000; // Prisoned roots can fiddle
CTLFLAG_DYN =$02000000; // Dynamic oid - can be freed
CTLFLAG_SKIP =$01000000; // Skip this sysctl when listing
CTLMASK_SECURE =$00F00000; // Secure level
CTLFLAG_TUN =$00080000; // Tunable variable
CTLFLAG_RDTUN =(CTLFLAG_RD or CTLFLAG_TUN);
CTLFLAG_RWTUN =(CTLFLAG_RW or CTLFLAG_TUN);
CTLFLAG_MPSAFE =$00040000; // Handler is MP safe
CTLFLAG_VNET =$00020000; // Prisons with vnet can fiddle
CTLFLAG_DYING =$00010000; // oid is being removed
CTLFLAG_CAPRD =$00008000; // Can be read in capability mode
CTLFLAG_CAPWR =$00004000; // Can be written in capability mode
CTLFLAG_CAPRW =(CTLFLAG_CAPRD or CTLFLAG_CAPWR);
OID_AUTO=(-1);
CTL_AUTO_START=$100;
//Top-level identifiers
CTL_UNSPEC = 0; // unused
CTL_KERN = 1; // "high kernel": proc, limits
CTL_VM = 2; // virtual memory
CTL_VFS = 3; // filesystem, mount type is next
CTL_NET = 4; // network, see socket.h
CTL_DEBUG = 5; // debugging parameters
CTL_HW = 6; // generic cpu/io
CTL_MACHDEP = 7; // machine dependent
CTL_USER = 8; // user-level
CTL_P1003_1B= 9; // POSIX 1003.1B
CTL_MAXID =10; // number of valid top-level ids
//CTL_KERN identifiers
KERN_PROC =14;
KERN_USRSTACK=33;
KERN_ARND =37;
KERN_SMP =$100; //(OID_AUTO) Kernel SMP
KERN_SCHED =$101; //(OID_AUTO) Scheduler
//CTL_VM subtypes
KERN_VM_PS4DEV=1; //vm parameters for PS4 (DevKit only)
//KERN_PROC subtypes
KERN_PROC_APPINFO =35; //Application information
KERN_PROC_SDK_VERSION =36; //SDK version of the executable file
KERN_PROC_IDTABLE =37; //ID table information
KERN_PROC_SANITIZER =41; //kern_sanitizer (Sanitizing mode)
KERN_PROC_PTC =43; //Process time counter (value at program start)
KERN_PROC_TEXT_SEGMENT=44; //kern_dynlib_get_libkernel_text_segment
//KERN_SMP subtypes
KERN_CPUS=$100; //(OID_AUTO) Number of CPUs online
//KERN_SCHED subtypes
KERN_SCHED_CPUSETSIZE=$100; //(OID_AUTO) sizeof(cpuset_t)
//CTL_HW identifiers
HW_MACHINE = 1; // string: machine class
HW_MODEL = 2; // string: specific machine model
HW_NCPU = 3; // int: number of cpus
HW_BYTEORDER = 4; // int: machine byte order
HW_PHYSMEM = 5; // int: total memory
HW_USERMEM = 6; // int: non-kernel memory
HW_PAGESIZE = 7; // int: software page size
HW_DISKNAMES = 8; // strings: disk drive names
HW_DISKSTATS = 9; // struct: diskstats[]
HW_FLOATINGPT =10; // int: has HW floating point?
HW_MACHINE_ARCH=11; // string: machine architecture
HW_REALMEM =12; // int: 'real' memory
HW_MAXID =13; // number of valid hw ids
//MACHDEP subtypes
MACHDEP_TSC_FREQ=$100; //(OID_AUTO) Time Stamp Counter frequency
//KERN_VM_PS4DEV subtypes
KERN_VM_PS4DEV_TRCMEM_TOTAL=$100; //(OID_AUTO) trace memory total
KERN_VM_PS4DEV_TRCMEM_AVAIL=$101; //(OID_AUTO) trace memory available
//SYSCTL_HANDLER_ARGS oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req
type
p_sysctl_req=^t_sysctl_req;
t_sysctl_func=function(req:p_sysctl_req;p:Pointer;s:QWORD):Integer;
t_sysctl_req=record
td :Pointer; //p_kthread
lock :Integer;
oldptr :Pointer;
oldlen :QWORD;
oldidx :QWORD;
oldfunc :t_sysctl_func;
newptr :Pointer;
newlen :QWORD;
newidx :QWORD;
newfunc :t_sysctl_func;
validlen:QWORD;
flags :Integer;
end;
p_sysctl_oid=^t_sysctl_oid;
t_oid_handler=function(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
t_sysctl_oid=record
oid_arg1 :Pointer;
oid_arg2 :Integer;
oid_kind :DWORD;
oid_name :PInteger;
oid_handler:t_oid_handler;
end;
function sys___sysctl(name :PInteger;
namelen:DWORD;
old :Pointer;
oldlenp:PQWORD;
new :Pointer;
newlen :QWORD):Integer;
procedure sysctl_register_all(); //SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0);
implementation
uses
errno,
systm,
vfile,
vmparam,
vm_map,
kern_thr,
kern_sx,
time,
md_arc4random,
md_proc;
var
sysctllock :t_sx;
sysctlmemlock:t_sx;
procedure sysctl_register_all();
begin
sx_init(@sysctlmemlock, 'sysctl mem');
sx_init(@sysctllock , 'sysctl lock');
end;
procedure SYSCTL_XLOCK(); inline;
begin
sx_xlock(@sysctllock)
end;
procedure SYSCTL_XUNLOCK(); inline;
begin
sx_xunlock(@sysctllock);
end;
procedure SYSCTL_ASSERT_XLOCKED(); inline;
begin
sx_assert(@sysctllock)
end;
function SYSCTL_IN(req:p_sysctl_req;p:Pointer;s:QWORD):Integer; inline;
begin
Result:=req^.newfunc(req,p,s);
end;
function SYSCTL_OUT(req:p_sysctl_req;p:Pointer;s:QWORD):Integer; inline;
begin
Result:=req^.oldfunc(req,p,s);
end;
function SYSCTL_HANDLE(noid:p_sysctl_oid;
name:PInteger;
kind:DWORD;
func:Pointer):Integer; inline;
begin
noid^.oid_name :=name+1;
noid^.oid_kind :=kind;
noid^.oid_arg1 :=nil;
noid^.oid_arg2 :=0;
noid^.oid_handler:=t_oid_handler(func);
Result:=0
end;
function SYSCTL_HANDLE(noid:p_sysctl_oid;
name:PInteger;
kind:DWORD;
arg1:Pointer;
func:Pointer):Integer; inline;
begin
noid^.oid_name :=name+1;
noid^.oid_kind :=kind;
noid^.oid_arg1 :=arg1;
noid^.oid_arg2 :=0;
noid^.oid_handler:=t_oid_handler(func);
Result:=0
end;
function SYSCTL_HANDLE(noid:p_sysctl_oid;
name:PInteger;
kind:DWORD;
arg2:Integer;
func:Pointer):Integer; inline;
begin
noid^.oid_name :=name+1;
noid^.oid_kind :=kind;
noid^.oid_arg1 :=nil;
noid^.oid_arg2 :=arg2;
noid^.oid_handler:=t_oid_handler(func);
Result:=0
end;
function SYSCTL_HANDLE(noid:p_sysctl_oid;
name:PInteger;
kind:DWORD;
arg1:Pointer;
arg2:Integer;
func:Pointer):Integer; inline;
begin
noid^.oid_name :=name+1;
noid^.oid_kind :=kind;
noid^.oid_arg1 :=arg1;
noid^.oid_arg2 :=arg2;
noid^.oid_handler:=t_oid_handler(func);
Result:=0
end;
//Transfer function to/from user space.
function sysctl_old_user(req:p_sysctl_req;p:Pointer;l:QWORD):Integer;
var
i,len,origidx:QWORD;
error:Integer;
begin
origidx:=req^.oldidx;
Inc(req^.oldidx,l);
if (req^.oldptr=nil) then
begin
Exit(0);
end;
i:=l;
len:=req^.validlen;
if (len <= origidx) then
begin
i:=0;
end else
begin
if (i > len - origidx) then
begin
i:=len - origidx;
end;
//if (req^.lock=REQ_WIRED) then
//begin
// error:=copyout_nofault(p, req^.oldptr + origidx, i);
//end else
begin
error:=copyout(p, req^.oldptr + origidx, i);
end;
if (error<>0) then
begin
Exit(error);
end;
end;
if (i < l) then
begin
Exit(ENOMEM);
end;
Exit(0);
end;
function sysctl_new_user(req:p_sysctl_req;p:Pointer;l:QWORD):Integer;
var
error:Integer;
begin
if (req^.newptr=nil) then
begin
Exit(0);
end;
if ((req^.newlen - req^.newidx) < l) then
begin
Exit(EINVAL);
end;
error:=copyin(req^.newptr + req^.newidx, p, l);
Inc(req^.newidx,l);
Exit(error);
end;
//Exit(ENOTDIR);
//Exit(ENOENT);
function sysctl_kern_proc_idtable(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
begin
//get idtable key count
Exit(ENOENT); //sceSblACMgrIsSystemUcred
end;
function sysctl_kern_usrstack(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
begin
Result:=SYSCTL_OUT(req,@g_vmspace.sv_usrstack,SizeOf(Pointer));
end;
function sysctl_kern_arandom(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
var
len:Integer;
data:array[0..254] of Byte;
begin
len:=256;
if (req^.oldlen < 256) then
begin
len:=req^.oldlen;
end;
arc4rand(@data,len,0);
Result:=SYSCTL_OUT(req,@data,len);
end;
const
//eLoadOptions
LOAD_OPTIONS_DEFAULT =$0000;
LOAD_OPTIONS_LOAD_SUSPENDED =$0001;
LOAD_OPTIONS_USE_SYSTEM_LIBRARY_VERIFICATION =$0002;
LOAD_OPTIONS_SLV_MODE_WARN =$0004;
LOAD_OPTIONS_ARG_STACK_SIZE =$0008;
LOAD_OPTIONS_FULL_DEBUG_REQUIRED =$0010;
//mmap_flags
//bit 1 -> is_big_app
//bit 2 -> first find addr is (1 shl 33) ->
// _sceKernelMapFlexibleMemory
// _sceKernelMapDirectMemory
// sceKernelMapDirectMemory2
//excp_flags
//bit 1 -> use in [libkernel_exception] ->
// -> sceKernelInstallExceptionHandler
// -> sceKernelRemoveExceptionHandler
// -> sceKernelAddGpuExceptionEvent
// -> sceKernelDeleteGpuExceptionEvent
// -> sceKernelBacktraceSelf
//bit 2 -> sys_mdbg_service
type
TCUSANAME=array[0..9] of AnsiChar;
PSCE_APP_ENV=^TSCE_APP_ENV;
TSCE_APP_ENV=packed record
AppId :Integer; //4
mmap_flags :Integer; //4
excp_flags :Integer; //4
AppType :Integer; //4 5?
CUSANAME :TCUSANAME; //10
debug_level:Byte; //1
slv_flags :Byte; //1 eLoadOptions
f_1c :Byte;
f_1d :Byte;
f_1e :Byte;
f_1f :Byte;
f_20 :QWORD;
f_28 :Integer;
f_2c :Integer;
f_30 :Integer;
f_34 :Integer;
f_38 :QWORD;
f_40 :QWORD;
end;
{$IF sizeof(TSCE_APP_ENV)<>72}{$STOP sizeof(TSCE_APP_ENV)<>72}{$ENDIF}
var
G_APPINFO:TSCE_APP_ENV;
function sysctl_kern_proc_appinfo(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
var
pid:Integer;
APPINFO:TSCE_APP_ENV;
begin
if (req^.oldlen > 72) then Exit(EINVAL);
pid:=PInteger(arg1)^;
if (pid<>g_pid) then Exit(EINVAL);
//G_APPINFO.mmap_flags:=G_APPINFO.mmap_flags or 1;
if (p_proc.p_sce_replay_exec<>0) then
begin
G_APPINFO.mmap_flags:=G_APPINFO.mmap_flags or 2;
end;
//sceSblACMgrIsSystemUcred()!=0 -> any proc
//sceSblACMgrIsSystemUcred()==0 -> cur proc
Result:=SYSCTL_OUT(req,@G_APPINFO,SizeOf(TSCE_APP_ENV));
if (Result=0) and (req^.newlen=SizeOf(TSCE_APP_ENV)) then
begin
Result:=SYSCTL_IN(req,@APPINFO,SizeOf(TSCE_APP_ENV));
if (Result=0) then
begin
G_APPINFO:=APPINFO;
if (p_proc.p_sce_replay_exec<>0) then
begin
G_APPINFO.mmap_flags:=G_APPINFO.mmap_flags or 2;
end;
end;
end;
end;
function sysctl_kern_proc_sanitizer(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
var
Sanitizer:Integer;
begin
Sanitizer:=0;
Result:=SYSCTL_OUT(req,@Sanitizer,SizeOf(Integer));
end;
function sysctl_kern_proc_ptc(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
begin
Result:=SYSCTL_OUT(req,@p_proc.p_ptc,SizeOf(Int64));
end;
function sysctl_handle_int(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
var
tmpout:Integer;
begin
if (arg1<>nil) then
begin
tmpout:=PInteger(arg1)^;
end else
begin
tmpout:=arg2;
end;
Result:=SYSCTL_OUT(req,@tmpout,SizeOf(Integer));
if (Result<>0) or (req^.newptr=nil) then Exit;
if (arg1=nil) then Exit(EPERM);
Result:=SYSCTL_IN(req, arg1, sizeof(Integer));
end;
function sysctl_handle_64(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
var
tmpout:QWORD;
begin
if (arg1=nil) then
begin
Exit(EINVAL);
end;
tmpout:=PInteger(arg1)^;
Result:=SYSCTL_OUT(req,@tmpout,SizeOf(QWORD));
if (Result<>0) or (req^.newptr=nil) then Exit;
if (arg1=nil) then Exit(EPERM);
Result:=SYSCTL_IN(req, arg1, sizeof(QWORD));
end;
function name2oid(name:pchar;oid,len:PInteger):Integer;
begin
Result:=0;
case RawByteString(name) of
'kern.smp.cpus':
begin
oid[0]:=CTL_KERN;
oid[1]:=KERN_SMP;
oid[2]:=KERN_CPUS;
len^ :=3;
end;
'kern.proc.ptc':
begin
oid[0]:=CTL_KERN;
oid[1]:=KERN_PROC;
oid[2]:=KERN_PROC_PTC;
len^ :=3;
end;
'kern.sched.cpusetsize':
begin
oid[0]:=CTL_KERN;
oid[1]:=KERN_SCHED;
oid[2]:=KERN_SCHED_CPUSETSIZE;
len^ :=3;
end;
'machdep.tsc_freq':
begin
oid[0]:=CTL_MACHDEP;
oid[1]:=MACHDEP_TSC_FREQ;
len^ :=2;
end;
'vm.ps4dev.trcmem_total':
begin
oid[0]:=CTL_VM;
oid[1]:=KERN_VM_PS4DEV;
oid[2]:=KERN_VM_PS4DEV_TRCMEM_TOTAL;
len^ :=3;
end;
'vm.ps4dev.trcmem_avail':
begin
oid[0]:=CTL_VM;
oid[1]:=KERN_VM_PS4DEV;
oid[2]:=KERN_VM_PS4DEV_TRCMEM_AVAIL;
len^ :=3;
end;
else
Writeln(StdErr,'Unhandled name2oid:',name);
Assert(False);
Result:=ENOENT;
end;
end;
function sysctl_sysctl_name2oid(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
var
new:array[0..MAXPATHLEN] of AnsiChar;
oid:array[0..CTL_MAXNAME-1] of Integer;
len:Integer;
begin
if (req^.newlen=0) then Exit(ENOENT);
if (req^.newlen >= MAXPATHLEN) then Exit(ENAMETOOLONG);
FillChar(new,SizeOf(new),0);
Result:=SYSCTL_IN(req, @new, req^.newlen);
if (Result<>0) then Exit;
Result:=name2oid(@new, @oid, @len);
if (Result<>0) then Exit;
Result:=SYSCTL_OUT(req, @oid, len*sizeof(Integer));
end;
function sysctl_kern_proc(name:PInteger;namelen:DWORD;noid:p_sysctl_oid;req:p_sysctl_req):Integer;
begin
if (namelen=0) then Exit(ENOTDIR);
Result:=ENOENT;
case name[0] of
KERN_PROC_APPINFO :Result:=SYSCTL_HANDLE(noid,name,$C0040001,@sysctl_kern_proc_appinfo);
KERN_PROC_SANITIZER:Result:=SYSCTL_HANDLE(noid,name,$80040001,@sysctl_kern_proc_sanitizer);
KERN_PROC_PTC :Result:=SYSCTL_HANDLE(noid,name,$90040009,@sysctl_kern_proc_ptc);
else
begin
Writeln(StdErr,'Unhandled sysctl_kern_proc:',name[0]);
Assert(False);
end;
end;
end;
function sysctl_kern_smp(name:PInteger;namelen:DWORD;noid:p_sysctl_oid;req:p_sysctl_req):Integer;
const
smp_cpus=8;
begin
if (namelen=0) then Exit(ENOTDIR);
Result:=ENOENT;
case name[0] of
KERN_CPUS:Result:=SYSCTL_HANDLE(noid,name,$80048002,smp_cpus,@sysctl_handle_int);
else
begin
Writeln(StdErr,'Unhandled sysctl_kern_smp:',name[0]);
Assert(False);
end;
end;
end;
function sysctl_kern_sched(name:PInteger;namelen:DWORD;noid:p_sysctl_oid;req:p_sysctl_req):Integer;
begin
if (namelen=0) then Exit(ENOTDIR);
Result:=ENOENT;
case name[0] of
KERN_SCHED_CPUSETSIZE:Result:=SYSCTL_HANDLE(noid,name,$80040002,8,@sysctl_handle_int);
else
begin
Writeln(StdErr,'Unhandled sysctl_kern_sched:',name[0]);
Assert(False);
end;
end;
end;
function sysctl_kern(name:PInteger;namelen:DWORD;noid:p_sysctl_oid;req:p_sysctl_req):Integer;
begin
if (namelen=0) then Exit(ENOTDIR);
Result:=ENOENT;
case name[0] of
KERN_PROC :Result:=sysctl_kern_proc(name+1,namelen-1,noid,req);
KERN_USRSTACK:Result:=SYSCTL_HANDLE(noid,name,$80008008,@sysctl_kern_usrstack);
KERN_ARND :Result:=SYSCTL_HANDLE(noid,name,$80048005,@sysctl_kern_arandom);
KERN_SMP :Result:=sysctl_kern_smp (name+1,namelen-1,noid,req);
KERN_SCHED :Result:=sysctl_kern_sched(name+1,namelen-1,noid,req);
else
begin
Writeln(StdErr,'Unhandled sysctl_kern:',name[0]);
Assert(False);
end;
end;
end;
function sysctl_sysctl(name:PInteger;namelen:DWORD;noid:p_sysctl_oid;req:p_sysctl_req):Integer;
begin
if (namelen=0) then Exit(ENOTDIR);
Result:=ENOENT;
case name[0] of
3:Result:=SYSCTL_HANDLE(noid,name,$D004C002,@sysctl_sysctl_name2oid);
else
begin
Writeln(StdErr,'Unhandled sysctl_sysctl:',name[0]);
Assert(False);
end;
end;
end;
function sysctl_hw(name:PInteger;namelen:DWORD;noid:p_sysctl_oid;req:p_sysctl_req):Integer;
begin
if (namelen=0) then Exit(ENOTDIR);
Result:=ENOENT;
case name[0] of
HW_PAGESIZE:Result:=SYSCTL_HANDLE(noid,name,$80048002,PAGE_SIZE,@sysctl_handle_int);
else
begin
Writeln(StdErr,'Unhandled sysctl_hw:',name[0]);
Assert(False);
end;
end;
end;
function sysctl_machdep_tsc_freq(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
var
freq:QWORD;
begin
freq:=System.InterlockedExchangeAdd64(tsc_freq,0);
if (freq=0) then Exit(EOPNOTSUPP);
Result:=sysctl_handle_64(oidp, @freq, 0, req);
if (Result=0) and (req^.newptr<>nil) then
begin
System.InterlockedExchange64(tsc_freq,freq);
end;
end;
function sysctl_machdep(name:PInteger;namelen:DWORD;noid:p_sysctl_oid;req:p_sysctl_req):Integer;
begin
if (namelen=0) then Exit(ENOTDIR);
Result:=ENOENT;
case name[0] of
MACHDEP_TSC_FREQ:Result:=SYSCTL_HANDLE(noid,name,$C0000009,@sysctl_machdep_tsc_freq);
else
begin
Writeln(StdErr,'Unhandled sysctl_machdep:',name[0]);
Assert(False);
end;
end;
end;
function sysctl_find_oid(name :PInteger;
namelen:DWORD;
noid :p_sysctl_oid;
req :p_sysctl_req):Integer;
begin
if (namelen=0) then Exit(ENOENT);
Result:=ENOENT;
case name[0] of
CTL_UNSPEC :Result:=sysctl_sysctl (name+1,namelen-1,noid,req);
CTL_KERN :Result:=sysctl_kern (name+1,namelen-1,noid,req);
CTL_HW :Result:=sysctl_hw (name+1,namelen-1,noid,req);
CTL_MACHDEP:Result:=sysctl_machdep(name+1,namelen-1,noid,req);
else
begin
Writeln(StdErr,'Unhandled sysctl_root:',name[0]);
Assert(False);
end;
end;
end;
function sysctl_root(oidp:p_sysctl_oid;
arg1:PInteger;
arg2:DWORD;
req :p_sysctl_req):Integer;
var
oid:t_sysctl_oid;
indx:Integer;
begin
oid:=Default(t_sysctl_oid);
Result:=sysctl_find_oid(arg1, arg2, @oid, req);
if (Result<>0) then Exit;
if (oid.oid_handler=nil) then Exit(EINVAL);
if (oid.oid_name =nil) then Exit(EINVAL);
// Is this sysctl writable?
if (req^.newptr<>nil) and ((oid.oid_kind and CTLFLAG_WR)=0) then
begin
Exit(EPERM);
end;
// Is this sysctl writable by only privileged users?
if (req^.newptr<>nil) and ((oid.oid_kind and CTLFLAG_ANYBODY)=0) then
begin
//if (oid^.oid_kind and CTLFLAG_PRISON)
// priv:=PRIV_SYSCTL_WRITEJAIL;
//else
// priv:=PRIV_SYSCTL_WRITE;
//
//error:=priv_check(req^.td, priv);
//
//if (error<>0) then Ext(error);
Exit(EPERM);
end;
indx:=oid.oid_name-arg1;
if ((oid.oid_kind and CTLTYPE)=CTLTYPE_NODE) then
begin
arg1:=arg1 + indx;
arg2:=arg2 - indx;
end else
begin
arg1:=oid.oid_arg1;
arg2:=oid.oid_arg2;
end;
Result:=oid.oid_handler(@oid, arg1, arg2, req);
end;
function userland_sysctl(name :PInteger;
namelen :DWORD;
old :Pointer;
oldlenp :PQWORD;
inkernel:Integer;
new :Pointer;
newlen :QWORD;
retval :PQWORD;
flags :Integer):Integer;
var
error,memlocked:Integer;
req:t_sysctl_req;
begin
error:=0;
req:=Default(t_sysctl_req);
req.td :=curkthread;
req.flags:=flags;
if (oldlenp<>nil) then
begin
if (inkernel<>0) then
begin
req.oldlen:=oldlenp^;
end else
begin
error:=copyin(oldlenp, @req.oldlen, sizeof(Pointer));
if (error<>0) then Exit(error);
end;
end;
req.validlen:=req.oldlen;
if (old<>nil) then
begin
//if (!useracc(old, req.oldlen, VM_PROT_WRITE))
// Exit(EFAULT);
req.oldptr:=old;
end;
if (new<>nil) then
begin
//if (!useracc(new, newlen, VM_PROT_READ))
// Exit(EFAULT);
req.newlen:=newlen;
req.newptr:=new;
end;
req.oldfunc:=@sysctl_old_user;
req.newfunc:=@sysctl_new_user;
//req.lock:=REQ_UNWIRED;
if (req.oldlen > PAGE_SIZE) then
begin
memlocked:=1;
sx_xlock(@sysctlmemlock);
end else
begin
memlocked:=0;
end;
repeat
req.oldidx:=0;
req.newidx:=0;
SYSCTL_XLOCK();
error:=sysctl_root(nil, name, namelen, @req);
SYSCTL_XUNLOCK();
if (error<>EAGAIN) then
begin
break;
end;
//kern_yield(PRI_USER);
until false;
//if (req.lock=REQ_WIRED) and (req.validlen > 0) then
//begin
// vsunlock(req.oldptr, req.validlen);
//end;
if (memlocked<>0) then
begin
sx_xunlock(@sysctlmemlock);
end;
if (error<>0) and (error<>ENOMEM) then
begin
Exit(error);
end;
if (retval<>nil) then
begin
if (req.oldptr<>nil) and (req.oldidx > req.validlen) then
retval^:=req.validlen
else
retval^:=req.oldidx;
end;
Exit(error);
end;
function sys___sysctl(name :PInteger;
namelen:DWORD;
old :Pointer;
oldlenp:PQWORD;
new :Pointer;
newlen :QWORD):Integer;
var
error,i:Integer;
_name:array[0..CTL_MAXNAME-1] of Integer;
j:QWORD;
begin
if (namelen > CTL_MAXNAME) or (namelen < 2) then
begin
Exit(EINVAL);
end;
error:=copyin(name, @_name, namelen * sizeof(Integer));
if (error<>0) then Exit(error);
error:=userland_sysctl(@_name,
namelen,
old,
oldlenp,
0,
new,
newlen,
@j,
0);
if (error<>0) and (error<>ENOMEM) then
begin
Exit(error);
end;
if (oldlenp<>nil) then
begin
i:=copyout(@j, oldlenp, sizeof(j));
if (i<>0) then
begin
Exit(i);
end;
end;
Exit(error);
end;
end.