They messed up strcpy() so they introduced strncpy()...
That's not actually the case. strncpy() wasn't introduced as some kind of "safer strcpy()", it was built specifically to deal with strings stored in the manner of original UNIX directory entries - a fixed-width array where any unused space is padded out with NULs. That's why it worked the way it did - such a string that filled the whole array with no NUL at all was still valid.
The major problem with strncpy() was always its name - the "str" prefix was (obvious in hindsight) taken by people to mean that it dealt with ordinary C NUL-terminated strings, whereas the reality was that only its source argument was supposed to be such a string. It should have had a different name (this is illustrated perfectly by the similarly-named strncat(), which does deal only with ordinary C strings), but by the time of standardisation that ship had sailed. Probably it was niche enough that it just should have been left out of C89 altogether.
That's not actually the case. strncpy() wasn't introduced as some kind of "safer strcpy()", it was built specifically to deal with strings stored in the manner of original UNIX directory entries - a fixed-width array where any unused space is padded out with NULs. That's why it worked the way it did - such a string that filled the whole array with no NUL at all was still valid.
The major problem with strncpy() was always its name - the "str" prefix was (obvious in hindsight) taken by people to mean that it dealt with ordinary C NUL-terminated strings, whereas the reality was that only its source argument was supposed to be such a string. It should have had a different name (this is illustrated perfectly by the similarly-named strncat(), which does deal only with ordinary C strings), but by the time of standardisation that ship had sailed. Probably it was niche enough that it just should have been left out of C89 altogether.