You are supposed to use SUN_LEN macro. Here's from /usr/include/sys/un.h on my Mac:
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
/* actual length of an initialized sockaddr_un */
#define SUN_LEN(su) \
(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
#endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
Edit:
Yes, it's not portable and not POSIX, but we work on real platforms, don't we?
The thing is that you have to zero-terminate the path and the above code is as good as sizeof( struct sockaddr_un ) but might save you a few bytes when copying from user to kernel but wastes a few cycles in strlen.
Look at how Linux handles that length (from http://lxr.linux.no/linux+v2.6.32/net/unix/af_unix.c#L200):
static int unix_mkname(struct sockaddr_un *sunaddr, int len, unsigned *hashp)
{
if (len <= sizeof(short) || len > sizeof(*sunaddr))
return -EINVAL;
if (!sunaddr || sunaddr->sun_family != AF_UNIX)
return -EINVAL;
if (sunaddr->sun_path[0]) {
/*
* This may look like an off by one error but it is a bit more
* subtle. 108 is the longest valid AF_UNIX path for a binding.
* sun_path[108] doesnt as such exist. However in kernel space
* we are guaranteed that it is a valid memory location in our
* kernel address buffer.
*/
((char *)sunaddr)[len] = 0;
len = strlen(sunaddr->sun_path)+1+sizeof(short);
return len;
}
*hashp = unix_hash_fold(csum_partial(sunaddr, len, 0));
return len;
}
Here len is directly from third argument to bind system call, but sunaddr is already copied into kernel space with that length. You can't have address longer then sizeof( sockadd_un ). Kernel does the strlen anyway.
So yes, doing sizeof( sockaddr_un ) is probably safer across the board, but telling kernel exact length doesn't hurt either.