My program is written in C for Linux, and has many functions with different patterns for return values:
1) one or two return n on success and -1>
Not an actual answer to your question, but some random comments you might find interesting:
it's normally obvious when to use case (1), but it gets ugly when unsigned types are involved - return (size_t)-1 still works, but it ain't pretty
if you're using C99, there's nothing wrong with using _Bool; imo, it's a lot cleaner than just using an int
I use return NULL instead of return 0 in pointer contexts (peronal preference), but I rarely check for it as I find it more natural to just treat the pointer as a boolean; a common case would look like this:
struct foo *foo = create_foo();
if(!foo) /* handle error */;
I try to avoid case (2); using EXIT_SUCCESS and EXIT_FAILURE might be feasible, but imo this approach only makes sense if there are more than two possible outcomes and you'll have to use an enum anyway
for more complicated programs, it might make sense to implement your own error handling scheme; there are some fairly advanced implementations using setjmp()/longjmp() around, but I prefer something errno-like with different variables for different types of errors