I understand the temptation of "Let's just use an int return type, that way later on we can easily let them indicate different flavours of error if we want". But then you leave yourself open to this.
The full-BDSM approach is for every component Foo that works with callbacks like this to define its own FooResult type with no automatic type conversions to it. In C, enum suffices, though a determined idiot can just cast to override; using FooResult as defined below makes it harder to accidentally do the wrong thing:
enum FooResultImpl { FOO_SUCCESS_IMPL, FOO_FAILURE_IMPL };
struct FooResult {
enum FooResultImpl USE_A_CONVERSION_FUNCTION_INSTEAD_OF_ACCESSING_THIS_DIRECTLY;
} FOO_SUCCESS = { FOO_SUCCESS_IMPL }, FOO_FAILURE = { FOO_FAILURE_IMPL };
(Yes, it's still possible to get an erroneous value in there at initialisation time without having to type out "USE_A_CONV..." -- but this is C, you can only do so much. You can't even prevent a FooResult variable from containing uninitialised garbage...)