There are two aspects: the ways system calls signal that an error occurred, and the way what error occurred is reported.
Most system calls signal that an error occurred by returning -1, but this is not completely universal (for example, some system calls are always successful, e.g.
If you know an error occurred, the error code is always in
errno¹. There are standard values defined in
errno.h, and every unix variants adds a few of its own. Error codes are known by constants whose name begins with
E; the numeric values vary from OS to OS. These error codes are standard (e.g.
EACCESS always means “permission denied”,
EIO always means “input/output error”, …), but what precisely each error message means depends on the system call.
The standard functions
perror provide error messages that you can display to a user.
Note that if no error occurred during the last system call or C library function call,
errno may contain garbage.