The code reads from a specified offset to the specified number of bytes in a file
Fails with large offset, bytes

read(fd, buf, offset); reads out of buf[] bounds when offset &gt; buf_size.  Same for bytes.  This should be tested.

Unclear why buf[buf_size] is so small (5).  How about 4096 or 1 Meg?

Handle large offset

I'd expect code to handle offsets far larger than the sizeof buf.  Looping on read(fd, buf, offset); if needed.

int math

Files sizes can well exceed INT_MAX.  For offset, bytes, I'd use long long.

Unneeded loop

Rather than a for() loop for (i = 0; i &lt; rlen; i++) putchar(buf[i]);, use write(1, ...).

Missing close()

Function Limitations

OP has "not allowed to use system calls other than open, close, read, write".  What about error(), printf(), atoi(), putchar() - or are those classified differently?

With such a limit, looks like a lot of includes.

Algorithm flaw?

The first while (1) loop looks wrong.  

Either the first iteration will get the expect offset number of bytes and proceed to the 2nd while ().

Or 

it will read insufficient number of bytes (for reasons other than no -more bytes will ever exist) and loop again, trying to read offset bytes again.  I'd expect that offset would have been reduced by the previous rlen.  Without that reduction, if(len == offset) may never be satisfied as reading too many offset bytes is then possible.

I'd expect 2 while loops that are not nested.  First to read the offset bytes, next to read the bytes.

Further this could be sub-function calls.  Something like:

if (read_bytes(handle, offset, no_echo) == OK) {
  if (read_bytes(handle, bytes, echo_to_stdout) == OK) {
    success();
  }
}
fail();