In my country, we drive on the right side of the street. Couldn't I instead drive on the left side? Yes, I would be perfectly capable of doing so. Would I want to? Not if I want to avoid the drastic consequences of encountering my fellow drivers who are following the convention.
You say certain words in an certain manner to communicate certain ideas and information to others. Couldn't you use entirely different words and manner? Yes, you are perfectly capable of doing so, but nobody would be able to understand you.
I started with computers as a computer technician (pre-PC). In one training block, our instructor told us that computers are based on communication. On signals being sent, received, and acted upon. On protocols being followed. If any component decided to send entirely different signals instead of the ones agreed upon, then communication would break down and the computer would not be able to function.
The exit code convention is that zero indicates success and non-zero indicates failure. You are perfectly capable of not following that convention, but by doing so communication would break down and things would not work. For example, while you can specify specific non-zero values to report different kinds of errors, script writers who use your program won't know about them unless they read your documentation, assuming that you even provide them with documentation. But how many programmers consult the documentation for everything? You have demonstrated that you don't. The only thing they know for sure is that the program will return a code of zero to indicate success. In changing the rules out from under them by returning a non-zero for success, you only succeed in causing problems for everybody.
There are many good reasons for following convention and extremely few for not following convention.
I remember a few of the error codes in Borland C++, such as 2 for "file not found", which could be used as guidelines for assigning specific codes for specific errors. You can find your C compiler's error codes in errno.h; from MinGW gcc's (code values in other compilers may vary widely):
* Error numbers.
* TODO: Can't be sure of some of these assignments, I guessed from the
* names given by strerror and the defines in the Cygnus errno.h. A lot
* of the names from the Cygnus errno.h are not represented, and a few
* of the descriptions returned by strerror do not obviously match
* their error naming.
#define EPERM 1 /* Operation not permitted */
#define ENOFILE 2 /* No such file or directory */
#define ENOENT 2
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted function call */
#define EIO 5 /* Input/output error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Arg list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file descriptor */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Resource temporarily unavailable */
#define ENOMEM 12 /* Not enough space */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
/* 15 - Unknown Error */
#define EBUSY 16 /* strerror reports "Resource device" */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Improper link (cross-device link?) */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* Too many open files in system */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Inappropriate I/O control operation */
/* 26 - Unknown Error */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Invalid seek (seek on a pipe?) */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Domain error (math functions) */
#define ERANGE 34 /* Result too large (possibly too small) */
/* 35 - Unknown Error */
#define EDEADLOCK 36 /* Resource deadlock avoided (non-Cyg) */
#define EDEADLK 36
/* 37 - Unknown Error */
#define ENAMETOOLONG 38 /* Filename too long (91 in Cyg?) */
#define ENOLCK 39 /* No locks available (46 in Cyg?) */
#define ENOSYS 40 /* Function not implemented (88 in Cyg?) */
#define ENOTEMPTY 41 /* Directory not empty (90 in Cyg?) */
#define EILSEQ 42 /* Illegal byte sequence */
Just as a thought, solely for use as guidelines.
Of course, getting that specific would be with the assumption that a script writer would need or be able to make use of that information. We do know that he has to at the very least be able to tell whether your program ran successfully or not.