The only problem when dealing with fgets() is that you have to use a buffer with a static length. Fuck me in the goat ass! This is extremely problematic when dealing with user input, and should be avoided.
More convenient is the non-standard getline() interface, which allows you to read strings of unlimited length and usually guarantees only one malloc() call. Apparently, it does this by allocating small chunks of stack each time getline() is called and using them to store pieces of the string, calling itself recursively if it needs more space. When the end of the line/file is reached, it allocates a buffer and unwinds. When each instance of getline() is returned to, it prepends its buffer to the malloc()'d space until it has fully unwound and you're left with your string. Clever, no?
Anyway, the moral of the story is to be clever about your fgets() use, or use getline().
Coffee: Your implementation uses the stack to store the string as well. It's silly to worry about the few bytes that the getline recursion would cost (for return address, etc.). That stack space is recovered as soon as the stack frame is dismantled and the string is put into malloced memory. Besides, I'd rather risk running out of stack space than arbitrarily truncating input with fgets.