1 | /* Copyright (C) 1992-2024 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. |
3 | |
4 | The GNU C Library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2.1 of the License, or (at your option) any later version. |
8 | |
9 | The GNU C Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library; if not, see |
16 | <https://www.gnu.org/licenses/>. */ |
17 | |
18 | #include <errno.h> |
19 | #include <sys/socket.h> |
20 | #include <hurd.h> |
21 | #include <hurd/fd.h> |
22 | #include <hurd/socket.h> |
23 | #include <hurd/paths.h> |
24 | #include <fcntl.h> |
25 | #include <stddef.h> |
26 | #include <hurd/ifsock.h> |
27 | #include <sys/un.h> |
28 | #include "hurd/hurdsocket.h" |
29 | |
30 | /* Give the socket FD the local address ADDR (which is LEN bytes long). */ |
31 | int |
32 | __bind (int fd, __CONST_SOCKADDR_ARG addrarg, socklen_t len) |
33 | { |
34 | addr_port_t aport; |
35 | error_t err; |
36 | const struct sockaddr_un *addr = addrarg.__sockaddr_un__; |
37 | |
38 | if (addr->sun_family == AF_LOCAL) |
39 | { |
40 | char *name = _hurd_sun_path_dupa (addr, len); |
41 | /* For the local domain, we must create a node in the filesystem |
42 | using the ifsock translator and then fetch the address from it. */ |
43 | file_t dir, node, ifsock; |
44 | char *n; |
45 | |
46 | dir = __file_name_split (name, &n); |
47 | if (dir == MACH_PORT_NULL) |
48 | return -1; |
49 | |
50 | /* Create a new, unlinked node in the target directory. */ |
51 | err = __dir_mkfile (dir, O_CREAT, 0666 & ~_hurd_umask, &node); |
52 | |
53 | if (! err) |
54 | { |
55 | /* Set the node's translator to make it a local-domain socket. */ |
56 | err = __file_set_translator (node, |
57 | FS_TRANS_EXCL | FS_TRANS_SET, |
58 | FS_TRANS_EXCL | FS_TRANS_SET, 0, |
59 | _HURD_IFSOCK, sizeof _HURD_IFSOCK, |
60 | MACH_PORT_NULL, |
61 | MACH_MSG_TYPE_COPY_SEND); |
62 | if (! err) |
63 | { |
64 | enum retry_type doretry; |
65 | char retryname[1024]; |
66 | /* Get a port to the ifsock translator. */ |
67 | err = __dir_lookup (node, "" , 0, 0, &doretry, retryname, &ifsock); |
68 | if (! err && (doretry != FS_RETRY_NORMAL || retryname[0] != '\0')) |
69 | err = EADDRINUSE; |
70 | } |
71 | if (! err) |
72 | { |
73 | /* Get the address port. */ |
74 | err = __ifsock_getsockaddr (ifsock, &aport); |
75 | if (err == MIG_BAD_ID || err == EOPNOTSUPP) |
76 | err = EGRATUITOUS; |
77 | if (! err) |
78 | { |
79 | /* Link the node, now a socket with proper mode, into the |
80 | target directory. */ |
81 | err = __dir_link (dir, node, n, 1); |
82 | if (err == EEXIST) |
83 | err = EADDRINUSE; |
84 | if (err) |
85 | __mach_port_deallocate (__mach_task_self (), aport); |
86 | } |
87 | __mach_port_deallocate (__mach_task_self (), ifsock); |
88 | } |
89 | __mach_port_deallocate (__mach_task_self (), node); |
90 | } |
91 | __mach_port_deallocate (__mach_task_self (), dir); |
92 | |
93 | if (err) |
94 | return __hurd_fail (err); |
95 | } |
96 | else |
97 | err = EIEIO; |
98 | |
99 | err = HURD_DPORT_USE (fd, |
100 | ({ |
101 | if (err) |
102 | err = __socket_create_address (port, |
103 | addr->sun_family, |
104 | (char *) addr, len, |
105 | &aport); |
106 | if (! err) |
107 | { |
108 | err = __socket_bind (port, aport); |
109 | __mach_port_deallocate (__mach_task_self (), |
110 | aport); |
111 | } |
112 | err; |
113 | })); |
114 | |
115 | return err ? __hurd_dfail (fd, err) : 0; |
116 | } |
117 | |
118 | weak_alias (__bind, bind) |
119 | |