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