Im having no luck with this external command:
/usr/bin/printf "[%lu] CHANGE_SVC_EVENT_HANDLER;<HOST>;<SERVICE>;ack_service\n" >> /usr/local/nagios/var/rw/nagios.cmd
Nagios.log shows:
[1647021762] EXTERNAL COMMAND: CHANGE_SVC_EVENT_HANDLER;<HOST>;<SERVICE>;ack_service
[1647021762] Error: External command failed -> CHANGE_SVC_EVENT_HANDLER;<HOST>;<SERVICE> ack_service
[1647021762] External command [1647021762] CHANGE_SVC_EVENT_HANDLER;<HOST>;<SERVICE>;ack_service returned error Command failed
I am submitting other external commands in the same way with no problems.
For the service Im using,
--Event Handler (EH) is enabled.
--I have an existing EH which differs from the one Im trying to switch to.
In nagios.cfg I have check_external_commands=1
Any thoughts?
The debug log isnt any help either:
[1647022292.354006] [256.2] [pid=10560] Read 78 bytes from command worker
[1647022292.354040] [256.1] [pid=10560] Read raw external command '[1647021762] CHANGE_SVC_EVENT_HANDLER;<HOST>;<SERVICE>;ack_service'
[1647022292.354045] [001.0] [pid=10560] process_external_command1()
[1647022292.354049] [128.2] [pid=10560] Raw command entry: [1647021762] CHANGE_SVC_EVENT_HANDLER;<HOST>;<SERVICE>;ack_service
[1647022292.354094] [064.1] [pid=10560] Making callbacks (type 2)...
[1647022292.354100] [064.2] [pid=10560] Callback #1 (type 2) return code = 0
[1647022292.354104] [064.1] [pid=10560] Making callbacks (type 17)...
[1647022292.354107] [064.2] [pid=10560] Callback #1 (type 17) return code = 0
[1647022292.354110] [001.0] [pid=10560] process_external_command2()
[1647022292.354113] [128.1] [pid=10560] External Command Type: 126
[1647022292.354116] [128.1] [pid=10560] Command Entry Time: 1647021762
[1647022292.354119] [128.1] [pid=10560] Command Arguments: <HOST>;<SERVICE>;ack_service
[1647022292.354130] [064.1] [pid=10560] Making callbacks (type 2)...
[1647022292.354133] [064.2] [pid=10560] Callback #1 (type 2) return code = 0
[1647022292.354136] [064.1] [pid=10560] Making callbacks (type 17)...
[1647022292.354139] [064.2] [pid=10560] Callback #1 (type 17) return code = 0
[1647022292.354151] [064.1] [pid=10560] Making callbacks (type 2)...
[1647022292.354154] [064.2] [pid=10560] Callback #1 (type 2) return code = 0
[1647022292.354157] [4096.2] [pid=10560] ## 1 descriptors had input
Well here's the reason. Would have been nice if the error indicated what's going on!
https://github.com/NagiosEnterprises/nagioscore/commit/3207e91193cb507401858a6136fc6e3fc257a236
The following macros are disabled:
CHANGE_GLOBAL_HOST_EVENT_HANDLER
CHANGE_GLOBAL_SVC_EVENT_HANDLER
CHANGE_HOST_EVENT_HANDLER
CHANGE_SVC_EVENT_HANDLER
CHANGE_HOST_CHECK_COMMAND
CHANGE_SVC_CHECK_COMMAND
Related
Background
I am trying to use the Basic Model Interface (BMI) to initialize the dflowfm model (that I have compiled from source to produce executables and shared libraries) from a fortran program.
I was able to do this successfully using a python wrapper by openearth.
However, on my fortran program, this fails with a segmentation fault that doesn't tell me much.
After some digging around, I (think) I was able to locate the source code that points to the function/subroutine that I want to call to initialize the model.
Any help is highly appreciated!
Issue
Below is my fortran program where I try to call the routine from the shared library as both a subroutine and function. Both fail with the error: forrtl: severe (174): SIGSEGV, segmentation fault occurred pointing the trace to the function/subroutine call. Here is the full trace:
forrtl: severe (174): SIGSEGV, segmentation fault occurred
Image PC Routine Line Source
libpthread-2.31.s 00007F04C9E19140 Unknown Unknown Unknown
libdflowfm.so.0.0 00007F04CB517080 Unknown Unknown Unknown
libdflowfm.so.0.0 00007F04CB517319 Unknown Unknown Unknown
testbmifort 000000000040F2E1 MAIN__ 39 bmi_fort-test.f90
testbmifort 000000000040F25D Unknown Unknown Unknown
libc-2.31.so 00007F04C9C4CD0A __libc_start_main Unknown Unknown
testbmifort 000000000040F17A Unknown Unknown Unknown
Debugging trace:
39 call init(sharedDLLHandle, c_config_file, strln)
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
0x00007f03c2181080 in GetDllProcedure () from /opt/dflowfm/lib/libdflowfm.so.0
(gdb) bt
#0 0x00007f03c2181080 in GetDllProcedure () from /opt/dflowfm/lib/libdflowfm.so.0
#1 0x00007f03c2181319 in bmi_initialize_ () from /opt/dflowfm/lib/libdflowfm.so.0
#2 0x000000000040f384 in test_df_bmi () at bmi_fort-test.f90:39
#3 0x000000000040f25d in main ()
#4 0x00007f03c08b6d0a in __libc_start_main (main=0x40f240 <main>, argc=1, argv=0x7fff9bf4d658, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fff9bf4d648)
at ../csu/libc-start.c:308
#5 0x000000000040f17a in _start ()
bmi_fort-test.f90
compiled as ifort bmi_fort-test.f90 -L/opt/dflowfm/lib/ -ldflowfm -o testbmifort -traceback -warn interface -O0
(in case you are wondering the shared library has been compiled with ifort too)
module bmi
use iso_c_binding
implicit none
integer(C_INT64_T), BIND(C, name="MAXSTRLEN") :: MAXSTRLEN
! interface
! integer(C_INT64_T) function init(config) result(iresult) bind(C, name='bmi_initialize_')
! use iso_c_binding
! character*(c_char) :: config
! end function
! end interface
interface
subroutine init(sharedDLLHandle, config, strln) bind(C, name='bmi_initialize_')
use iso_c_binding
type(c_ptr), value :: sharedDLLHandle
! integer(C_INT64_T), pointer :: dll_ptr
character*(c_char) :: config
integer(c_int) :: strln
end subroutine
end interface
end module bmi
program test_df_bmi
use iso_c_binding
use bmi
type(c_ptr) :: sharedDLLHandle
! integer(C_INT64_T), pointer :: dll_ptr
character*(c_char) :: c_config_file
character(*), parameter :: config_file = "/home/bmi-python/test_data/e02_f14_c040_westerscheldt/westerscheldt.mdu"
integer(C_INT64_T) :: iresult
integer(c_int) :: strln
c_config_file = "/home/bmi-python/test_data/e02_f14_c040_westerscheldt/westerscheldt.mdu"
strln = len(config_file)
! iresult = init(c_config_file)
call init(sharedDLLHandle, c_config_file, strln)
end program test_df_bmi
The shortened output from the command nm -D /opt/dflowfm/lib/libdflowfm.so reveals the existence of the procedure I wish to call: 00000000015a5300 T bmi_initialize_.
If I understand correctly from a few stackoverflow posts, the underscore at the end must mean it is a C routine.
Now, here are some scraps from the source files that I think resulted in the production of the routine I wish to call (the entire source tree is too huge to attach; I did an expression search in the source tree to filter out all the places that could be relevant and traced them back to these two snippets from two source files):
sf1.f90 (source)
...
!> The initialize() function accepts a string argument that
!! gives the name (and path) of its "main input file", called
!! a configuration file. This function should perform all tasks
!! that are to take place before entering the model's time loop.
integer(c_int) function initialize(c_config_file) result(c_iresult) bind(C, name="initialize")
!DEC$ ATTRIBUTES DLLEXPORT :: initialize
use iso_c_binding, only: c_char
...
character(kind=c_char),intent(in) :: c_config_file(MAXSTRLEN)
character(len=strlen(c_config_file)) :: config_file
! Extra local variables
integer :: inerr ! number of the initialisation error
...
c_iresult = 0 ! TODO: is this return value BMI-compliant?
#ifdef HAVE_MPI
...
! Store the name
config_file = char_array_to_string(c_config_file, strlen(c_config_file))
! Now we can initialize with the config_file
...
! TODO: check why these are needed to avoid a segfault
KNX = 8
MXB = 10
MAXLAN = 500
MAXPOL = MAXLAN
...
CALL INIDAT()
call api_loadmodel(config_file)
...
c_iresult = flowinit()
time_user = tstart_user
! Just terminate if we get an error....
! if (inerr > 0) stop
! initialize = 0
end function initialize
...
sf2.c (source)
...
long STDCALL BMI_INITIALIZE(int64_t * sharedDLLHandle,
char * config_file,
int config_file_len)
{
typedef (STDCALL * MyProc)(chvoid *ar *);
MyProc proc = (MyProc)GetDllProcedure(sharedDLLHandle, "initialize");
long error = -1;
char * c_config_file = strFcpy(config_file, config_file_len);
RemoveTrailingBlanks_dll(c_config_file);
if (proc != NULL)
{
error = 0;
(void *)(*proc)(c_config_file);
}
free(c_config_file); c_config_file = NULL;
return error;
}
...
Side question:
Is there a way to check the necessary arguments and data types of the arguments of this routine from the shared library?
Additional info
This is the python program that was successfully able to initialize and run the model using the library:
df_bmi-test.py
import bmi.wrapper as bw
dflowfm = bw.BMIWrapper(engine='dflowfm', configfile='test_data/retracted/path.mdu')
dflowfm.initialize()
Here is the part of bmi.wrapper (source) I think is relevant to set this up:
...
def wrap(func):
"""Return wrapped function with type conversion and sanity checks.
"""
#functools.wraps(func, assigned=('restype', 'argtypes'))
def wrapped(*args):
if len(args) != len(func.argtypes):
logger.warn("{} {} not of same length",
args, func.argtypes)
typed_args = []
for (arg, argtype) in zip(args, func.argtypes):
if argtype == c_char_p:
# create a string buffer for strings
typed_arg = create_string_buffer(arg)
else:
# for other types, use the type to do the conversion
if hasattr(argtype, 'contents'):
# type is a pointer
typed_arg = argtype(argtype._type_(arg))
else:
typed_arg = argtype(arg)
typed_args.append(typed_arg)
result = func(*typed_args)
if hasattr(result, 'contents'):
return result.contents
else:
return result
return wrapped
...
def _load_library(self):
"""Return the fortran library, loaded with """
path = self._library_path()
logger.info("Loading library from path {}".format(path))
library_dir = os.path.dirname(path)
if platform.system() == 'Windows':
import win32api
olddir = os.getcwd()
os.chdir(library_dir)
win32api.SetDllDirectory('.')
result = cdll.LoadLibrary(path)
if platform.system() == 'Windows':
os.chdir(olddir)
return result
def initialize(self, configfile=None):
"""Initialize and load the Fortran library (and model, if applicable).
The Fortran library is loaded and ctypes is used to annotate functions
inside the library. The Fortran library's initialization is called.
Normally a path to an ``*.ini`` model file is passed to the
:meth:`__init__`. If so, that model is loaded. Note that
:meth:`_load_model` changes the working directory to that of the model.
"""
if configfile is not None:
self.configfile = configfile
try:
self.configfile
except AttributeError:
raise ValueError("Specify configfile during construction or during initialize")
abs_name = os.path.abspath(self.configfile)
os.chdir(os.path.dirname(self.configfile) or '.')
logmsg = "Loading model {} in directory {}".format(
self.configfile,
os.path.abspath(os.getcwd())
)
logger.info(logmsg)
# Fortran init function.
self.library.initialize.argtypes = [c_char_p]
self.library.initialize.restype = None
# initialize by abs_name because we already chdirred
# if configfile is a relative path we would have a problem
ierr = wrap(self.library.initialize)(abs_name)
if ierr:
errormsg = "Loading model {config} failed with exit code {code}"
raise RuntimeError(errormsg.format(config=self.configfile,
code=ierr))
...
i've checked following URL: Lua os.execute return value
I've made a program with C which returns 111 or 222.
Here is part of my code.
if (stat == NULL)
{
system("echo \"stat is NULL\"");
return 111;
}
else
{
system("echo \"stat is NOT NULL\"");
return 222;
}
when i run this at Linux like this, ~/c-program; echo $?, it prints
stat is NULL
111
or,
stat is NOT NULL
222
at my terminal.
or like this,
~/c-program
echo $?
it also prints same way like ~/c-program; echo $?
I need to run that program via Lua. Here is part of my lua script.
local foo = io.popen(~/c-program; echo $?)
local bar = foo:read("*a")
foo:close()
if (tonumber(bar) == 111) then
os.execute("echo 111")
elseif (tonumber(bar) == 222) then
os.execute("echo 222")
else
os.execute("echo \"something is wrong\"")
os.execute("echo "..bar)
end
this prints like this
something is wrong
Even it has a script that prints the value of bar, it does not print.
I thought that ``os.execute("echo "..bar)``` syntax is wrong, but it's not.
i tried like this at https://www.lua.org/cgi-bin/demo
local bar = 111
if (tonumber(bar) == 111) then
print("bar is "..bar)
elseif (tonumber(bar) == 222) then
print("bar is "..bar)
else
print("something is wrong")
print("bar is "..bar)
end
it prints bar is 111. In case bar's value is 333, it also prints something is wrong
So, how should i do to use that c-program's return value as a Lua's variable?
local foo = io.popen(~/c-program; echo $?) looks wrong: popen expects a string, and I have no idea what that unquoted stuff will look like to the Lua parser.
If it did work, it would give "stat is NULL" or "stat is not NULL" followed by the exit code of the C program. It would be tricky to get the number from that, since tonumber will NOT skip past non-number text to find one. It would be simpler to get the exit code directly:
First, skip the echo $? part of the command, so that the shell call will just run the C program and nothing else.
If the Lua code doesn't need the output "stat is NULL" or "stat is not NULL", use just os.execute instead of io.popen.
Documentation for os.execute says
Its first result is true if the command terminated successfully, or fail otherwise. After this first result the function returns a string plus a number, as follows:
"exit": the command terminated normally; the following number is the exit status of the command.
"signal": the command was terminated by a signal; the following number is the signal that terminated the command.
And documentation for file:close() says
When closing a file handle created with io.popen, file:close returns the same values returned by os.execute.
So you should be able to do any one of
-- Don't need the output text, and allow c-program to print it.
local ok, how, code = os.execute("~/c-program")
-- OR, Don't need the output text, and make sure it's not printed anywhere.
local ok, how, code = os.execute("~/c-program >/dev/null")
-- OR, Need the output text within Lua
local foo = io.popen("~/c-program")
do_stuff(foo)
local ok, how, code = foo:close()
followed by
if how == "exit" then
if code == 111 then
print("Got 111")
elseif code == 222 then
print("Got 222")
else
print("Exited with code " .. code)
end
elseif how == "signal" then
print("Stopped by signal " .. code)
else
print("What happened?")
end
A Program can exit in two different ways...
An exit code like 0 (On Linux that means: OK - No Error)
Textoutput...
a) Normal: stdout
b) Error: stderr
With Lua you can produce an errorless exit code wit: os.exit(0)
And an Error with: os.exit(1)
Also, like in other languages, it is common to use echo or/and print to produce dynamic output i.e. like XML/HTML/CSS/Javascript code.
Example for returning error code 1 in Lua Standalone:
$ lua
Lua 5.4.4 Copyright (C) 1994-2022 Lua.org, PUC-Rio
> rc = 1
> if rc ~= 0 then
>> io.output(io.stderr)
>> io.write('ERROR - EXIT\n')
>> os.exit(rc)
>> end
ERROR - EXIT
$ echo $?
1
$
...so in case of an error stderr is used to put out the errortext and the exit code of 1 can be used as a condition for further processing (in bash/shellscript).
Something to read about exit command and code...
https://linuxize.com/post/bash-exit/
Now lets check what os.execute() is returning...
> os.execute('echo "Hello World"')
Hello World
true exit 0
os.execute() is returning three values and you want the third one.
You can grab it then by defining three locals with os.execute() and use only the last one...
local one, two, three = os.execute('~/c-program')
print(three)
return three
Does the WriteFile function signal the event passed in via the lpOverlapped parameter if it completes synchronously and succeeds? Does it signal the event if it fails synchronously? I have opened the handle to a file with the FILE_FLAG_OVERLAPPED flag. I wasn't to able to figure this out from the documentation and couldn't repro this case easily in code.
first of all this question related not only to WriteFile but to any asynchronous I/O function - almost all functions which get pointer to an OVERLAPPED structure. because for all this functions IRP (I/O request packet) (look it definition in wdm.h) is allocated. hEvent handle from OVERLAPPED converted to object pointer and stored in PKEVENT UserEvent; member of IRP. the event is set (or not set) exactly when IRP is completed in IopCompleteRequest routine. the IRP completion function is common for all I/O api, so and rules (when completion fire) is related to all. unfortunately this is very bad documented. the win32 layer (compare NT layer) added additional ,very thin, issues here.
based on wrk src code, we can see that I/O Manager fire completion (was 3 types - event, apc and iocp (mutually exclusive)) for asynchronous io when
!NT_ERROR( irp->IoStatus.Status ) or irp->PendingReturned.
if we use native api, which direct return NTSTATUS - when (ULONG)status < 0xc0000000. but here was very problematic range 0x80000000 <= status < 0xc0000000 or NT_WARNING(status) when unclear - are completion (even set, apc or packet to iocp queue) will be set. this is because before allocate IRP I/O Manager do some basic checks and can return error from here. usually I/O Manager return errors from NT_ERROR(status) , which correct mean that will be no completion (event will be not set)), but exist and rarely exceptions. for example for ReadDirectoryChangesW (or ZwNotifyChangeDirectoryFile) the lpBuffer pointer must be DWORD-aligned (aligned exactly as FILE_NOTIFY_INFORMATION) otherwise I/O Manager return STATUS_DATATYPE_MISALIGNMENT (0x80000002) from NT_WARNING range. but will be no completion (event set) in this case, because function fail before allocate IRP. from another case, if we call FSCTL_FILESYSTEM_GET_STATISTICS with not large enough buffer - file system driver (not I/O Manager ) return STATUS_BUFFER_OVERFLOW (0x80000005). but because at this point IRP already allocated and code not from NT_ERROR range - will be event set.
so if error from I/O Manager (before IRP allocated) - will be no completion. otherwise if error from driver (to which passed IRP) completion will be if function return !NT_ERROR(status). as result if we get:
NT_SUCCESS(status) (the STATUS_PENDING (0x103) is part of this) - will
be
completion
NT_ERROR(status) will be no completion
NT_WARNING(status) - unclear, depend this error from I/O Manager
(no) or driver(yes)
but with win32 layer make situation more worse. because unclear how it interpret NT_WARNING(status) - most win32 api interpret this as error - return false and set last error (converted from status). but some api - for example ReadDirectoryChangesW interpret this as success code - return true and not set last error. as result if we call ReadDirectoryChangesW with bad aligned buffer (but valid other parameters) - it return.. true and not set any error. but api call is really fail. the ZwNotifyChangeDirectoryFile internal return STATUS_DATATYPE_MISALIGNMENT here.
from another side, if DeviceIoControl for FSCTL_FILESYSTEM_GET_STATISTICS fail (return false) with code ERROR_MORE_DATA (converted from STATUS_BUFFER_OVERFLOW) event(completion) will be set in this case.
also by win32 error code we can not understand - are initial status was NT_ERROR or NT_WARNING code - conversion (RtlNtStatusToDosError) status to win32 error lost this info
problem with NT_WARNING(status) range, begin from vista, can be resolved if we use IOCP completion (instead event) and set FILE_SKIP_COMPLETION_PORT_ON_SUCCESS on file - in this case I/O manager queue a completion entry to the port, when and only when STATUS_PENDING will be returned by native api call. for win32 layer this usually mean that api return false and last error is ERROR_IO_PENDING. exceptions - WriteFileEx, ReadFileEx which return true here. however this not help in case ReadDirectoryChangesW anyway (I assume that this is windows bug)
also read FILE_SKIP_SET_EVENT_ON_HANDLE section - this implicitly say when explicit event (from overlapped) set in case asynchronous function - when request returns with a success code, or the error returned is ERROR_IO_PENDING. but here question - what is success code ? true returned by win32 api ? not always, as visible from FSCTL_FILESYSTEM_GET_STATISTICS - the ERROR_MORE_DATA (STATUS_BUFFER_OVERFLOW) also success code. or STATUS_NO_MORE_FILES returned by NtQueryDirectoryFile also success code - event (apc or iocp completion) will be set. but same NtQueryDirectoryFile can return STATUS_DATATYPE_MISALIGNMENT, when FileInformation bad aligned - this is fail code, because returned from I/O Manager before allocate IRP
the NT_WARNING status in most case is success code (will be completion), but win32 layer in most case interpret it as fail code (return false).
code example for tests:
ULONG BOOL_TO_ERROR(BOOL fOk)
{
return fOk ? NOERROR : GetLastError();
}
void CheckEventState(HANDLE hEvent, ULONG err, NTSTATUS status = RtlGetLastNtStatus())
{
DbgPrint("error = %u(%x)", err, err ? status : STATUS_SUCCESS);
switch (WaitForSingleObject(hEvent, 0))
{
case WAIT_OBJECT_0:
DbgPrint("Signaled\n");
break;
case WAIT_TIMEOUT:
DbgPrint("NON signaled\n");
break;
default:
DbgPrint("error=%u\n", GetLastError());
}
#if 1
EVENT_BASIC_INFORMATION ebi;
if (0 <= ZwQueryEvent(hEvent, EventBasicInformation, &ebi, sizeof(ebi), 0))
{
DbgPrint("EventState = %x\n", ebi.EventState);
}
#endif
}
void demoIoEvent()
{
WCHAR sz[MAX_PATH];
GetSystemDirectoryW(sz, RTL_NUMBER_OF(sz));
HANDLE hFile = CreateFileW(sz, 0, FILE_SHARE_VALID_FLAGS, 0,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED|FILE_FLAG_BACKUP_SEMANTICS, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
FILESYSTEM_STATISTICS fs;
OVERLAPPED ov = {};
if (ov.hEvent = CreateEvent(0, TRUE, FALSE, 0))
{
FILE_NOTIFY_INFORMATION fni;
IO_STATUS_BLOCK iosb;
// STATUS_DATATYPE_MISALIGNMENT from I/O manager
// event will be not set
NTSTATUS status = ZwNotifyChangeDirectoryFile(hFile, ov.hEvent, 0, 0, &iosb,
(FILE_NOTIFY_INFORMATION*)(1 + (PBYTE)&fni), 1, FILE_NOTIFY_VALID_MASK, FALSE);
CheckEventState(ov.hEvent, ERROR_NOACCESS, status);
// windows bug ! ReadDirectoryChangesW return .. true and no last error
// but really api fail. event will be not set and no notifications
ULONG err = BOOL_TO_ERROR(ReadDirectoryChangesW(hFile,
(FILE_NOTIFY_INFORMATION*)(1 + (PBYTE)&fni), 1, 0, FILE_NOTIFY_VALID_MASK, 0, &ov, 0));
CheckEventState(ov.hEvent, err);
// fail with ERROR_INSUFFICIENT_BUFFER (STATUS_BUFFER_TOO_SMALL)
// NT_ERROR(c0000023) - event will be not set
err = BOOL_TO_ERROR(DeviceIoControl(hFile,
FSCTL_FILESYSTEM_GET_STATISTICS, 0, 0, 0, 0, 0, &ov));
CheckEventState(ov.hEvent, err);
// ERROR_MORE_DATA (STATUS_BUFFER_OVERFLOW)
// !NT_ERROR(80000005) - event will be set
// note - win 32 api return false and error != ERROR_IO_PENDING
err = BOOL_TO_ERROR(DeviceIoControl(hFile,
FSCTL_FILESYSTEM_GET_STATISTICS, 0, 0, &fs, sizeof(fs), 0, &ov));
CheckEventState(ov.hEvent, err);
if (err == ERROR_MORE_DATA)
{
SYSTEM_INFO si;
GetSystemInfo(&si);
ULONG cb = si.dwNumberOfProcessors * fs.SizeOfCompleteStructure;
union {
PVOID pv;
PBYTE pb;
PFILESYSTEM_STATISTICS pfs;
};
pv = alloca(cb);
// must be NOERROR(0) here
// !NT_ERROR(0) - event will be set
err = BOOL_TO_ERROR(DeviceIoControl(hFile, FSCTL_FILESYSTEM_GET_STATISTICS, 0, 0,
pv, cb, 0, &ov));
CheckEventState(ov.hEvent, err);
if (!err && GetOverlappedResult(hFile, &ov, &cb, FALSE))
{
do
{
// use pfs here
} while (pb += fs.SizeOfCompleteStructure, --si.dwNumberOfProcessors);
}
}
CloseHandle(ov.hEvent);
}
CloseHandle(hFile);
}
}
and output:
error = 998(80000002)NON signaled
EventState = 0
error = 0(0)NON signaled
EventState = 0
error = 122(c0000023)NON signaled
EventState = 0
error = 234(80000005)Signaled
EventState = 1
error = 0(0)Signaled
EventState = 1
I am using next EvtIoWrite callback function in my file-system filter driver:
VOID
MyDriverEvtIoWrite(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN size_t UnusedLength
)
{
WDFFILEOBJECT file;
file = WdfRequestGetFileObject(Request);
if (file != NULL)
{
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "File is not null!\n"));
}
}
i got allways null file object and never see "File is not null!" message. Why?
According to the WdfRequestGetFileObject method
Return value
WdfRequestGetFileObject returns a handle to the framework file object,
if the framework has created a file object for the specified request.
Otherwise, this method returns NULL. (A driver typically tests for a
NULL return value only if it sets the WdfFileObjectCanBeOptional bit
flag in the WDF_FILEOBJECT_CONFIG structure.) A bug check occurs if
the driver supplies an invalid object handle. Remarks
The WdfRequestGetFileObject method returns NULL if either:
Your driver > has not called WdfDeviceInitSetFileObjectConfig and specified a
WDF_FILEOBJECT_CLASS value that causes the framework to create file
objects.
Another driver sent a read, write, or I/O control request to
your driver without first sending a request type of
WdfRequestTypeCreate.
But i respect this rules. Here MyDriverEvtDeviceAdd function.
NTSTATUS
MyDriverEvtDeviceAdd(
IN WDFDRIVER Driver,
IN PWDFDEVICE_INIT DeviceInit
)
{
WDF_FILEOBJECT_CONFIG_INIT(
&fileConfig,
AAVolProcessFileCreate,
WDF_NO_EVENT_CALLBACK,
WDF_NO_EVENT_CALLBACK // not interested in Cleanup
);
fileConfig.FileObjectClass = WdfFileObjectWdfCanUseFsContext;
WDF_OBJECT_ATTRIBUTES attributes;
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
WdfDeviceInitSetFileObjectConfig(DeviceInit,
&fileConfig,
&attributes);
}
I'm trying to use gaddr2line to print a prettier version of backtrace symbols. I'm just getting the addresses from backtrace() then feeding them to gaddr2line by executing it using popen. Using addr2line under linux works fine, but for some reason I'm getting strange errors when using gaddr2line on OS X. When trying this on Mac OS I keep getting BFD: ... : unknown load command ... I saw some posts metioning GDB, so I tried installing that with homebrew, but that didn't help.
Here is my code:
// set to the maximum possible path size
char exe_path[4096];
// Used to check if an error occured while setting up command
bool error = false;
// Check if we are running on Mac OS or not, and select appropriate command
char* command;
#ifdef __APPLE__
// Check if 'gaddr2line' function is available, if not exit
if( !system( "which gaddr2line > /dev/null 2>&1" ) ) {
command = "gaddr2line -Cfspe";
pid_t pid = getpid();
int path_length = proc_pidpath( pid, exe_path, sizeof( exe_path ) );
if( path_length <= 0 ) {
writeLog( SIMPLOG_LOGGER, "Unable to get execution path. Defaulting to standard backtrace." );
error = true;
}
exe_path[path_length] = 0;
} else {
writeLog( SIMPLOG_LOGGER, "Function 'gaddr2line' unavailable. Defaulting to standard backtrace. Please install package 'binutils' for better stacktrace output." );
error = true;
}
#endif
Here is the output:
gaddr2line -Cfspe /Users/nate/git/SimpleLogger/build/test 7408927
BFD: /Users/nate/git/SimpleLogger/build/test: unknown load command 0x2a
BFD: /Users/nate/git/SimpleLogger/build/test: unknown load command 0x28
BFD: /Users/nate/git/SimpleLogger/build/test: unknown load command 0x29
BFD: /Users/nate/git/SimpleLogger/build/test: unknown load command 0x2b