The reason is that in something like
books[i].name = tmp;
You're not actually copying a string from tmp into books[i].name: you just make both point to the same location - somewhere into the buf buffer.
Try using strdup instead, as in:
books[i].name = strdup(tmp);