f21993
commit e368b12f6c16b6888dda99ba641e999b9c9643c8
f21993
Author: Florian Weimer <fweimer@redhat.com>
f21993
Date:   Mon Jan 17 10:21:34 2022 +0100
f21993
f21993
    socket: Add the __sockaddr_un_set function
f21993
    
f21993
    Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
f21993
f21993
# Conflicts:
f21993
#	socket/Makefile
f21993
f21993
diff --git a/include/sys/un.h b/include/sys/un.h
f21993
index bdbee999806930f4..152afd9fc7426d8b 100644
f21993
--- a/include/sys/un.h
f21993
+++ b/include/sys/un.h
f21993
@@ -1 +1,13 @@
f21993
 #include <socket/sys/un.h>
f21993
+
f21993
+#ifndef _ISOMAC
f21993
+
f21993
+/* Set ADDR->sun_family to AF_UNIX and ADDR->sun_path to PATHNAME.
f21993
+   Return 0 on success or -1 on failure (due to overlong PATHNAME).
f21993
+   The caller should always use sizeof (struct sockaddr_un) as the
f21993
+   socket address length, disregaring the length of PATHNAME.
f21993
+   Only concrete (non-abstract) pathnames are supported.  */
f21993
+int __sockaddr_un_set (struct sockaddr_un *addr, const char *pathname)
f21993
+  attribute_hidden;
f21993
+
f21993
+#endif /* _ISOMAC */
f21993
diff --git a/socket/Makefile b/socket/Makefile
f21993
index b41eb071507a6271..8975a65c2aabbfbc 100644
f21993
--- a/socket/Makefile
f21993
+++ b/socket/Makefile
f21993
@@ -29,10 +29,14 @@ headers	:= sys/socket.h sys/un.h bits/sockaddr.h bits/socket.h \
f21993
 routines := accept bind connect getpeername getsockname getsockopt	\
f21993
 	    listen recv recvfrom recvmsg send sendmsg sendto		\
f21993
 	    setsockopt shutdown socket socketpair isfdtype opensock	\
f21993
-	    sockatmark accept4 recvmmsg sendmmsg
f21993
+	    sockatmark accept4 recvmmsg sendmmsg sockaddr_un_set
f21993
 
f21993
 tests := tst-accept4
f21993
 
f21993
+tests-internal := \
f21993
+  tst-sockaddr_un_set \
f21993
+  # tests-internal
f21993
+
f21993
 aux	 := sa_len
f21993
 
f21993
 include ../Rules
f21993
diff --git a/socket/sockaddr_un_set.c b/socket/sockaddr_un_set.c
f21993
new file mode 100644
f21993
index 0000000000000000..0bd40dc34e3d7efc
f21993
--- /dev/null
f21993
+++ b/socket/sockaddr_un_set.c
f21993
@@ -0,0 +1,41 @@
f21993
+/* Set the sun_path member of struct sockaddr_un.
f21993
+   Copyright (C) 2022 Free Software Foundation, Inc.
f21993
+   This file is part of the GNU C Library.
f21993
+
f21993
+   The GNU C Library is free software; you can redistribute it and/or
f21993
+   modify it under the terms of the GNU Lesser General Public
f21993
+   License as published by the Free Software Foundation; either
f21993
+   version 2.1 of the License, or (at your option) any later version.
f21993
+
f21993
+   The GNU C Library is distributed in the hope that it will be useful,
f21993
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
f21993
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
f21993
+   Lesser General Public License for more details.
f21993
+
f21993
+   You should have received a copy of the GNU Lesser General Public
f21993
+   License along with the GNU C Library; if not, see
f21993
+   <https://www.gnu.org/licenses/>.  */
f21993
+
f21993
+#include <errno.h>
f21993
+#include <string.h>
f21993
+#include <sys/socket.h>
f21993
+#include <sys/un.h>
f21993
+
f21993
+int
f21993
+__sockaddr_un_set (struct sockaddr_un *addr, const char *pathname)
f21993
+{
f21993
+  size_t name_length = strlen (pathname);
f21993
+
f21993
+  /* The kernel supports names of exactly sizeof (addr->sun_path)
f21993
+     bytes, without a null terminator, but userspace does not; see the
f21993
+     SUN_LEN macro.  */
f21993
+  if (name_length >= sizeof (addr->sun_path))
f21993
+    {
f21993
+      __set_errno (EINVAL);     /* Error code used by the kernel.  */
f21993
+      return -1;
f21993
+    }
f21993
+
f21993
+  addr->sun_family = AF_UNIX;
f21993
+  memcpy (addr->sun_path, pathname, name_length + 1);
f21993
+  return 0;
f21993
+}
f21993
diff --git a/socket/tst-sockaddr_un_set.c b/socket/tst-sockaddr_un_set.c
f21993
new file mode 100644
f21993
index 0000000000000000..29c2a81afda81b5e
f21993
--- /dev/null
f21993
+++ b/socket/tst-sockaddr_un_set.c
f21993
@@ -0,0 +1,62 @@
f21993
+/* Test the __sockaddr_un_set function.
f21993
+   Copyright (C) 2022 Free Software Foundation, Inc.
f21993
+   This file is part of the GNU C Library.
f21993
+
f21993
+   The GNU C Library is free software; you can redistribute it and/or
f21993
+   modify it under the terms of the GNU Lesser General Public
f21993
+   License as published by the Free Software Foundation; either
f21993
+   version 2.1 of the License, or (at your option) any later version.
f21993
+
f21993
+   The GNU C Library is distributed in the hope that it will be useful,
f21993
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
f21993
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
f21993
+   Lesser General Public License for more details.
f21993
+
f21993
+   You should have received a copy of the GNU Lesser General Public
f21993
+   License along with the GNU C Library; if not, see
f21993
+   <https://www.gnu.org/licenses/>.  */
f21993
+
f21993
+/* Re-compile the function because the version in libc is not
f21993
+   exported.  */
f21993
+#include "sockaddr_un_set.c"
f21993
+
f21993
+#include <support/check.h>
f21993
+
f21993
+static int
f21993
+do_test (void)
f21993
+{
f21993
+  struct sockaddr_un sun;
f21993
+
f21993
+  memset (&sun, 0xcc, sizeof (sun));
f21993
+  __sockaddr_un_set (&sun, "");
f21993
+  TEST_COMPARE (sun.sun_family, AF_UNIX);
f21993
+  TEST_COMPARE (__sockaddr_un_set (&sun, ""), 0);
f21993
+
f21993
+  memset (&sun, 0xcc, sizeof (sun));
f21993
+  TEST_COMPARE (__sockaddr_un_set (&sun, "/example"), 0);
f21993
+  TEST_COMPARE_STRING (sun.sun_path, "/example");
f21993
+
f21993
+  {
f21993
+    char pathname[108];         /* Length of sun_path (ABI constant).  */
f21993
+    memset (pathname, 'x', sizeof (pathname));
f21993
+    pathname[sizeof (pathname) - 1] = '\0';
f21993
+    memset (&sun, 0xcc, sizeof (sun));
f21993
+    TEST_COMPARE (__sockaddr_un_set (&sun, pathname), 0);
f21993
+    TEST_COMPARE (sun.sun_family, AF_UNIX);
f21993
+    TEST_COMPARE_STRING (sun.sun_path, pathname);
f21993
+  }
f21993
+
f21993
+  {
f21993
+    char pathname[109];
f21993
+    memset (pathname, 'x', sizeof (pathname));
f21993
+    pathname[sizeof (pathname) - 1] = '\0';
f21993
+    memset (&sun, 0xcc, sizeof (sun));
f21993
+    errno = 0;
f21993
+    TEST_COMPARE (__sockaddr_un_set (&sun, pathname), -1);
f21993
+    TEST_COMPARE (errno, EINVAL);
f21993
+  }
f21993
+
f21993
+  return 0;
f21993
+}
f21993
+
f21993
+#include <support/test-driver.c>