| @@ -1,842 +1,840 @@ | | | @@ -1,842 +1,840 @@ |
1 | /* $NetBSD: puffs_portal.c,v 1.10 2019/05/23 11:13:17 kre Exp $ */ | | 1 | /* $NetBSD: puffs_portal.c,v 1.11 2023/04/04 20:39:36 rillig Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2007 Antti Kantee. All Rights Reserved. | | 4 | * Copyright (c) 2007 Antti Kantee. All Rights Reserved. |
5 | * Development was supported by the Finnish Cultural Foundation. | | 5 | * Development was supported by the Finnish Cultural Foundation. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
15 | * | | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS | | 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS |
17 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | | 17 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | | 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | | 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | | 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 | * SUCH DAMAGE. | | 26 | * SUCH DAMAGE. |
27 | */ | | 27 | */ |
28 | | | 28 | |
29 | #include <sys/cdefs.h> | | 29 | #include <sys/cdefs.h> |
30 | #ifndef lint | | 30 | #ifndef lint |
31 | __RCSID("$NetBSD: puffs_portal.c,v 1.10 2019/05/23 11:13:17 kre Exp $"); | | 31 | __RCSID("$NetBSD: puffs_portal.c,v 1.11 2023/04/04 20:39:36 rillig Exp $"); |
32 | #endif /* !lint */ | | 32 | #endif /* !lint */ |
33 | | | 33 | |
34 | #include <sys/types.h> | | 34 | #include <sys/types.h> |
35 | #include <sys/wait.h> | | 35 | #include <sys/wait.h> |
36 | #include <sys/socket.h> | | 36 | #include <sys/socket.h> |
37 | | | 37 | |
38 | #include <assert.h> | | 38 | #include <assert.h> |
39 | #include <err.h> | | 39 | #include <err.h> |
40 | #include <errno.h> | | 40 | #include <errno.h> |
41 | #include <mntopts.h> | | 41 | #include <mntopts.h> |
42 | #include <paths.h> | | 42 | #include <paths.h> |
43 | #include <poll.h> | | 43 | #include <poll.h> |
44 | #include <puffs.h> | | 44 | #include <puffs.h> |
45 | #include <stdio.h> | | 45 | #include <stdio.h> |
46 | #include <stdlib.h> | | 46 | #include <stdlib.h> |
47 | #include <string.h> | | 47 | #include <string.h> |
48 | #include <unistd.h> | | 48 | #include <unistd.h> |
49 | #include <util.h> | | 49 | #include <util.h> |
50 | | | 50 | |
51 | #include "portald.h" | | 51 | #include "portald.h" |
52 | | | 52 | |
53 | struct portal_node { | | 53 | struct portal_node { |
54 | char *path; | | 54 | char *path; |
55 | int fd; | | 55 | int fd; |
56 | }; | | 56 | }; |
57 | | | 57 | |
58 | __dead static void usage(void); | | 58 | __dead static void usage(void); |
59 | | | 59 | |
60 | PUFFSOP_PROTOS(portal); | | 60 | PUFFSOP_PROTOS(portal) |
61 | | | 61 | |
62 | #define PORTAL_ROOT NULL | | 62 | #define PORTAL_ROOT NULL |
63 | #define METADATASIZE (sizeof(int) + sizeof(size_t)) | | 63 | #define METADATASIZE (sizeof(int) + sizeof(size_t)) |
64 | | | 64 | |
65 | qelem q; | | 65 | qelem q; |
66 | int readcfg, sigchild; | | 66 | int readcfg, sigchild; |
67 | const char *cfg; | | 67 | const char *cfg; |
68 | | | 68 | |
69 | static void | | 69 | static void |
70 | usage(void) | | 70 | usage(void) |
71 | { | | 71 | { |
72 | | | 72 | |
73 | errx(1, "usage: %s [-o options] /path/portal.conf mount_point", | | 73 | errx(1, "usage: %s [-o options] /path/portal.conf mount_point", |
74 | getprogname()); | | 74 | getprogname()); |
75 | } | | 75 | } |
76 | | | 76 | |
77 | static void | | 77 | static void |
78 | sighup(int sig) | | 78 | sighup(int sig) |
79 | { | | 79 | { |
80 | | | 80 | |
81 | readcfg = 1; | | 81 | readcfg = 1; |
82 | } | | 82 | } |
83 | | | 83 | |
84 | static void | | 84 | static void |
85 | sigcry(int sig) | | 85 | sigcry(int sig) |
86 | { | | 86 | { |
87 | | | 87 | |
88 | sigchild = 1; | | 88 | sigchild = 1; |
89 | } | | 89 | } |
90 | | | 90 | |
91 | static void | | 91 | static void |
92 | portal_loopfn(struct puffs_usermount *pu) | | 92 | portal_loopfn(struct puffs_usermount *pu) |
93 | { | | 93 | { |
94 | | | 94 | |
95 | if (readcfg) | | 95 | if (readcfg) |
96 | conf_read(&q, cfg); | | 96 | conf_read(&q, cfg); |
97 | readcfg = 0; | | 97 | readcfg = 0; |
98 | | | 98 | |
99 | if (sigchild) { | | 99 | if (sigchild) { |
100 | sigchild = 0; | | 100 | sigchild = 0; |
101 | while (waitpid(-1, NULL, WNOHANG) != -1) | | 101 | while (waitpid(-1, NULL, WNOHANG) != -1) |
102 | continue; | | 102 | continue; |
103 | } | | 103 | } |
104 | } | | 104 | } |
105 | | | 105 | |
106 | #define PUFBUF_FD 1 | | 106 | #define PUFBUF_FD 1 |
107 | #define PUFBUF_DATA 2 | | 107 | #define PUFBUF_DATA 2 |
108 | | | 108 | |
109 | #define CMSIZE (sizeof(struct cmsghdr) + sizeof(int)) | | 109 | #define CMSIZE (sizeof(struct cmsghdr) + sizeof(int)) |
110 | | | 110 | |
111 | /* receive file descriptor produced by our child process */ | | 111 | /* receive file descriptor produced by our child process */ |
112 | static int | | 112 | static int |
113 | readfd(struct puffs_framebuf *pufbuf, int fd, int *done) | | 113 | readfd(struct puffs_framebuf *pufbuf, int fd, int *done) |
114 | { | | 114 | { |
115 | struct cmsghdr *cmp; | | 115 | struct cmsghdr *cmp; |
116 | struct msghdr msg; | | 116 | struct msghdr msg; |
117 | struct iovec iov; | | 117 | struct iovec iov; |
118 | ssize_t n; | | 118 | ssize_t n; |
119 | int error, rv; | | 119 | int error, rv; |
120 | | | 120 | |
121 | rv = 0; | | 121 | rv = 0; |
122 | cmp = emalloc(CMSG_SPACE(sizeof(int))); | | 122 | cmp = emalloc(CMSG_SPACE(sizeof(int))); |
123 | | | 123 | |
124 | iov.iov_base = &error; | | 124 | iov.iov_base = &error; |
125 | iov.iov_len = sizeof(int); | | 125 | iov.iov_len = sizeof(int); |
126 | msg.msg_iov = &iov; | | 126 | msg.msg_iov = &iov; |
127 | msg.msg_iovlen = 1; | | 127 | msg.msg_iovlen = 1; |
128 | msg.msg_name = NULL; | | 128 | msg.msg_name = NULL; |
129 | msg.msg_namelen = 0; | | 129 | msg.msg_namelen = 0; |
130 | msg.msg_control = cmp; | | 130 | msg.msg_control = cmp; |
131 | msg.msg_controllen = CMSG_SPACE(sizeof(int)); | | 131 | msg.msg_controllen = CMSG_SPACE(sizeof(int)); |
132 | | | 132 | |
133 | n = recvmsg(fd, &msg, 0); | | 133 | n = recvmsg(fd, &msg, 0); |
134 | if (n == -1) { | | 134 | if (n == -1) { |
135 | rv = errno; | | 135 | rv = errno; |
136 | goto out; | | 136 | goto out; |
137 | } | | 137 | } |
138 | if (n == 0) { | | 138 | if (n == 0) { |
139 | rv = ECONNRESET; | | 139 | rv = ECONNRESET; |
140 | goto out; | | 140 | goto out; |
141 | } | | 141 | } |
142 | | | 142 | |
143 | /* the data for the server */ | | 143 | /* the data for the server */ |
144 | puffs_framebuf_putdata_atoff(pufbuf, 0, &error, sizeof(int)); | | 144 | puffs_framebuf_putdata_atoff(pufbuf, 0, &error, sizeof(int)); |
145 | if (error) { | | 145 | if (error) { |
146 | rv = error; | | 146 | rv = error; |
147 | goto out; | | 147 | goto out; |
148 | } | | 148 | } |
149 | puffs_framebuf_putdata_atoff(pufbuf, sizeof(int), | | 149 | puffs_framebuf_putdata_atoff(pufbuf, sizeof(int), |
150 | CMSG_DATA(cmp), sizeof(int)); | | 150 | CMSG_DATA(cmp), sizeof(int)); |
151 | *done = 1; | | 151 | *done = 1; |
152 | | | 152 | |
153 | out: | | 153 | out: |
154 | free(cmp); | | 154 | free(cmp); |
155 | return rv; | | 155 | return rv; |
156 | } | | 156 | } |
157 | | | 157 | |
158 | /* | | 158 | /* |
159 | * receive data from provider | | 159 | * receive data from provider |
160 | * | | 160 | * |
161 | * XXX: should read directly into the buffer and adjust offsets | | 161 | * XXX: should read directly into the buffer and adjust offsets |
162 | * instead of doing memcpy | | 162 | * instead of doing memcpy |
163 | */ | | 163 | */ |
164 | static int | | 164 | static int |
165 | readdata(struct puffs_framebuf *pufbuf, int fd, int *done) | | 165 | readdata(struct puffs_framebuf *pufbuf, int fd, int *done) |
166 | { | | 166 | { |
167 | char buf[1024]; | | 167 | char buf[1024]; |
168 | size_t max; | | 168 | size_t max; |
169 | ssize_t n; | | 169 | ssize_t n; |
170 | size_t moved; | | 170 | size_t moved; |
171 | | | 171 | |
172 | /* don't override metadata */ | | 172 | /* don't override metadata */ |
173 | if (puffs_framebuf_telloff(pufbuf) == 0) | | 173 | if (puffs_framebuf_telloff(pufbuf) == 0) |
174 | puffs_framebuf_seekset(pufbuf, METADATASIZE); | | 174 | puffs_framebuf_seekset(pufbuf, METADATASIZE); |
175 | puffs_framebuf_getdata_atoff(pufbuf, sizeof(int), &max, sizeof(size_t)); | | 175 | puffs_framebuf_getdata_atoff(pufbuf, sizeof(int), &max, sizeof(size_t)); |
176 | moved = puffs_framebuf_tellsize(pufbuf) - METADATASIZE; | | 176 | moved = puffs_framebuf_tellsize(pufbuf) - METADATASIZE; |
177 | assert(max >= moved); | | 177 | assert(max >= moved); |
178 | max -= moved; | | 178 | max -= moved; |
179 | | | 179 | |
180 | do { | | 180 | do { |
181 | n = read(fd, buf, MIN(sizeof(buf), max)); | | 181 | n = read(fd, buf, MIN(sizeof(buf), max)); |
182 | if (n == 0) { | | 182 | if (n == 0) { |
183 | /* | | 183 | /* |
184 | * Deal with EOF here by closing the file descriptor | | 184 | * Deal with EOF here by closing the file descriptor |
185 | * and thus causing an error on subsequent accesses. | | 185 | * and thus causing an error on subsequent accesses. |
186 | * This is the last kevent notification we are going | | 186 | * This is the last kevent notification we are going |
187 | * to be getting for regular files. | | 187 | * to be getting for regular files. |
188 | */ | | 188 | */ |
189 | close(fd); | | 189 | close(fd); |
190 | if (moved) | | 190 | if (moved) |
191 | break; | | 191 | break; |
192 | else | | 192 | else |
193 | return -1; /* caught by read */ | | 193 | return -1; /* caught by read */ |
194 | } | | 194 | } |
195 | if (n < 0) { | | 195 | if (n < 0) { |
196 | if (moved) | | 196 | if (moved) |
197 | return 0; | | 197 | return 0; |
198 | | | 198 | |
199 | if (errno != EAGAIN) | | 199 | if (errno != EAGAIN) |
200 | return errno; | | 200 | return errno; |
201 | else | | 201 | else |
202 | return 0; | | 202 | return 0; |
203 | } | | 203 | } |
204 | | | 204 | |
205 | puffs_framebuf_putdata(pufbuf, buf, n); | | 205 | puffs_framebuf_putdata(pufbuf, buf, n); |
206 | moved += n; | | 206 | moved += n; |
207 | max -= n; | | 207 | max -= n; |
208 | } while (max > 0); | | 208 | } while (max > 0); |
209 | | | 209 | |
210 | *done = 1; | | 210 | *done = 1; |
211 | | | 211 | |
212 | return 0; | | 212 | return 0; |
213 | } | | 213 | } |
214 | | | 214 | |
215 | static int | | 215 | static int |
216 | portal_frame_rf(struct puffs_usermount *pu, struct puffs_framebuf *pufbuf, | | 216 | portal_frame_rf(struct puffs_usermount *pu, struct puffs_framebuf *pufbuf, |
217 | int fd, int *done) | | 217 | int fd, int *done) |
218 | { | | 218 | { |
219 | int type; | | 219 | int type; |
220 | | | 220 | |
221 | if (puffs_framebuf_getdata_atoff(pufbuf, 0, &type, sizeof(int)) == -1) | | 221 | if (puffs_framebuf_getdata_atoff(pufbuf, 0, &type, sizeof(int)) == -1) |
222 | return EINVAL; | | 222 | return EINVAL; |
223 | | | 223 | |
224 | if (type == PUFBUF_FD) | | 224 | if (type == PUFBUF_FD) |
225 | return readfd(pufbuf, fd, done); | | 225 | return readfd(pufbuf, fd, done); |
226 | else if (type == PUFBUF_DATA) | | 226 | else if (type == PUFBUF_DATA) |
227 | return readdata(pufbuf, fd, done); | | 227 | return readdata(pufbuf, fd, done); |
228 | else | | 228 | else |
229 | abort(); | | 229 | abort(); |
230 | } | | 230 | } |
231 | | | 231 | |
232 | static int | | 232 | static int |
233 | portal_frame_wf(struct puffs_usermount *pu, struct puffs_framebuf *pufbuf, | | 233 | portal_frame_wf(struct puffs_usermount *pu, struct puffs_framebuf *pufbuf, |
234 | int fd, int *done) | | 234 | int fd, int *done) |
235 | { | | 235 | { |
236 | void *win; | | 236 | void *win; |
237 | size_t pbsize, pboff, winlen; | | 237 | size_t pbsize, pboff, winlen; |
238 | ssize_t n; | | 238 | ssize_t n; |
239 | int error; | | 239 | int error; |
240 | | | 240 | |
241 | pboff = puffs_framebuf_telloff(pufbuf); | | 241 | pboff = puffs_framebuf_telloff(pufbuf); |
242 | pbsize = puffs_framebuf_tellsize(pufbuf); | | 242 | pbsize = puffs_framebuf_tellsize(pufbuf); |
243 | error = 0; | | 243 | error = 0; |
244 | | | 244 | |
245 | do { | | 245 | do { |
246 | assert(pbsize > pboff); | | 246 | assert(pbsize > pboff); |
247 | winlen = pbsize - pboff; | | 247 | winlen = pbsize - pboff; |
248 | if (puffs_framebuf_getwindow(pufbuf, pboff, &win, &winlen)==-1) | | 248 | if (puffs_framebuf_getwindow(pufbuf, pboff, &win, &winlen)==-1) |
249 | return errno; | | 249 | return errno; |
250 | n = write(fd, win, winlen); | | 250 | n = write(fd, win, winlen); |
251 | if (n == 0) { | | 251 | if (n == 0) { |
252 | if (pboff != 0) | | 252 | if (pboff != 0) |
253 | break; | | 253 | break; |
254 | else | | 254 | else |
255 | return -1; /* caught by node_write */ | | 255 | return -1; /* caught by node_write */ |
256 | } | | 256 | } |
257 | if (n < 0) { | | 257 | if (n < 0) { |
258 | if (pboff != 0) | | 258 | if (pboff != 0) |
259 | break; | | 259 | break; |
260 | | | 260 | |
261 | if (errno != EAGAIN) | | 261 | if (errno != EAGAIN) |
262 | return errno; | | 262 | return errno; |
263 | return 0; | | 263 | return 0; |
264 | } | | 264 | } |
265 | | | 265 | |
266 | pboff += n; | | 266 | pboff += n; |
267 | puffs_framebuf_seekset(pufbuf, pboff); | | 267 | puffs_framebuf_seekset(pufbuf, pboff); |
268 | } while (pboff != pbsize); | | 268 | } while (pboff != pbsize); |
269 | | | 269 | |
270 | *done = 1; | | 270 | *done = 1; |
271 | puffs_framebuf_putdata_atoff(pufbuf, 0, &pboff, sizeof(size_t)); | | 271 | puffs_framebuf_putdata_atoff(pufbuf, 0, &pboff, sizeof(size_t)); |
272 | return error; | | 272 | return error; |
273 | } | | 273 | } |
274 | | | 274 | |
275 | /* transfer file descriptor to master file server */ | | 275 | /* transfer file descriptor to master file server */ |
276 | static int | | 276 | static int |
277 | sendfd(int s, int fd, int error) | | 277 | sendfd(int s, int fd, int error) |
278 | { | | 278 | { |
279 | struct cmsghdr *cmp; | | 279 | struct cmsghdr *cmp; |
280 | struct msghdr msg; | | 280 | struct msghdr msg; |
281 | struct iovec iov; | | 281 | struct iovec iov; |
282 | ssize_t n; | | 282 | ssize_t n; |
283 | int rv; | | 283 | int rv; |
284 | | | 284 | |
285 | rv = 0; | | 285 | rv = 0; |
286 | cmp = emalloc(CMSG_LEN(sizeof(int))); | | 286 | cmp = emalloc(CMSG_LEN(sizeof(int))); |
287 | | | 287 | |
288 | iov.iov_base = &error; | | 288 | iov.iov_base = &error; |
289 | iov.iov_len = sizeof(int); | | 289 | iov.iov_len = sizeof(int); |
290 | | | 290 | |
291 | msg.msg_iov = &iov; | | 291 | msg.msg_iov = &iov; |
292 | msg.msg_iovlen = 1; | | 292 | msg.msg_iovlen = 1; |
293 | msg.msg_name = NULL; | | 293 | msg.msg_name = NULL; |
294 | msg.msg_namelen = 0; | | 294 | msg.msg_namelen = 0; |
295 | if (error == 0) { | | 295 | if (error == 0) { |
296 | cmp->cmsg_level = SOL_SOCKET; | | 296 | cmp->cmsg_level = SOL_SOCKET; |
297 | cmp->cmsg_type = SCM_RIGHTS; | | 297 | cmp->cmsg_type = SCM_RIGHTS; |
298 | cmp->cmsg_len = CMSG_LEN(sizeof(int)); | | 298 | cmp->cmsg_len = CMSG_LEN(sizeof(int)); |
299 | | | 299 | |
300 | msg.msg_control = cmp; | | 300 | msg.msg_control = cmp; |
301 | msg.msg_controllen = CMSG_LEN(sizeof(int)); | | 301 | msg.msg_controllen = CMSG_LEN(sizeof(int)); |
302 | *(int *)CMSG_DATA(cmp) = fd; | | 302 | *(int *)CMSG_DATA(cmp) = fd; |
303 | } else { | | 303 | } else { |
304 | msg.msg_control = NULL; | | 304 | msg.msg_control = NULL; |
305 | msg.msg_controllen = 0; | | 305 | msg.msg_controllen = 0; |
306 | } | | 306 | } |
307 | | | 307 | |
308 | n = sendmsg(s, &msg, 0); | | 308 | n = sendmsg(s, &msg, 0); |
309 | if (n == -1) | | 309 | if (n == -1) |
310 | rv = errno; | | 310 | rv = errno; |
311 | else if (n < (ssize_t)sizeof(int)) | | 311 | else if (n < (ssize_t)sizeof(int)) |
312 | rv = EPROTO; | | 312 | rv = EPROTO; |
313 | | | 313 | |
314 | free(cmp); | | 314 | free(cmp); |
315 | return rv; | | 315 | return rv; |
316 | } | | 316 | } |
317 | | | 317 | |
318 | /* | | 318 | /* |
319 | * Produce I/O file descriptor by forking (like original portald). | | 319 | * Produce I/O file descriptor by forking (like original portald). |
320 | * | | 320 | * |
321 | * child: run provider and transfer produced fd to parent | | 321 | * child: run provider and transfer produced fd to parent |
322 | * parent: yield until child produces fd. receive it and store it. | | 322 | * parent: yield until child produces fd. receive it and store it. |
323 | */ | | 323 | */ |
324 | static int | | 324 | static int |
325 | provide(struct puffs_usermount *pu, struct portal_node *portn, | | 325 | provide(struct puffs_usermount *pu, struct portal_node *portn, |
326 | struct portal_cred *portc, char **v) | | 326 | struct portal_cred *portc, char **v) |
327 | { | | 327 | { |
328 | struct puffs_cc *pcc = puffs_cc_getcc(pu); | | 328 | struct puffs_cc *pcc = puffs_cc_getcc(pu); |
329 | struct puffs_framebuf *pufbuf; | | 329 | struct puffs_framebuf *pufbuf; |
330 | int s[2]; | | 330 | int s[2]; |
331 | int fd, error; | | 331 | int fd, error; |
332 | int data; | | 332 | int data; |
333 | | | 333 | |
334 | pufbuf = puffs_framebuf_make(); | | 334 | pufbuf = puffs_framebuf_make(); |
335 | if (pufbuf == NULL) | | 335 | if (pufbuf == NULL) |
336 | return ENOMEM; | | 336 | return ENOMEM; |
337 | | | 337 | |
338 | data = PUFBUF_FD; | | 338 | data = PUFBUF_FD; |
339 | if (puffs_framebuf_putdata(pufbuf, &data, sizeof(int)) == -1) | | 339 | if (puffs_framebuf_putdata(pufbuf, &data, sizeof(int)) == -1) |
340 | goto bad; | | 340 | goto bad; |
341 | | | 341 | |
342 | if (socketpair(AF_LOCAL, SOCK_STREAM, 0, s) == -1) | | 342 | if (socketpair(AF_LOCAL, SOCK_STREAM, 0, s) == -1) |
343 | goto bad; | | 343 | goto bad; |
344 | | | 344 | |
345 | switch (fork()) { | | 345 | switch (fork()) { |
346 | case -1: | | 346 | case -1: |
347 | close(s[0]); close(s[1]); | | 347 | close(s[0]); close(s[1]); |
348 | goto bad; | | 348 | goto bad; |
349 | case 0: | | 349 | case 0: |
350 | close(s[0]); | | 350 | close(s[0]); |
351 | error = activate_argv(portc, portn->path, v, &fd); | | 351 | error = activate_argv(portc, portn->path, v, &fd); |
352 | sendfd(s[1], fd, error); | | 352 | sendfd(s[1], fd, error); |
353 | exit(0); | | 353 | exit(0); |
354 | default: | | 354 | default: |
355 | close(s[1]); | | 355 | close(s[1]); |
356 | puffs_framev_addfd(pu, s[0], PUFFS_FBIO_READ); | | 356 | puffs_framev_addfd(pu, s[0], PUFFS_FBIO_READ); |
357 | puffs_framev_enqueue_directreceive(pcc, s[0], pufbuf, 0); | | 357 | puffs_framev_enqueue_directreceive(pcc, s[0], pufbuf, 0); |
358 | puffs_framev_removefd(pu, s[0], 0); | | 358 | puffs_framev_removefd(pu, s[0], 0); |
359 | close(s[0]); | | 359 | close(s[0]); |
360 | | | 360 | |
361 | if (puffs_framebuf_tellsize(pufbuf) < sizeof(int)) { | | 361 | if (puffs_framebuf_tellsize(pufbuf) < sizeof(int)) { |
362 | errno = EIO; | | 362 | errno = EIO; |
363 | goto bad; | | 363 | goto bad; |
364 | } | | 364 | } |
365 | puffs_framebuf_getdata_atoff(pufbuf, 0, &error, sizeof(int)); | | 365 | puffs_framebuf_getdata_atoff(pufbuf, 0, &error, sizeof(int)); |
366 | if (error) { | | 366 | if (error) { |
367 | errno = error; | | 367 | errno = error; |
368 | goto bad; | | 368 | goto bad; |
369 | } | | 369 | } |
370 | | | 370 | |
371 | if (puffs_framebuf_tellsize(pufbuf) != 2*sizeof(int)) { | | 371 | if (puffs_framebuf_tellsize(pufbuf) != 2*sizeof(int)) { |
372 | errno = EIO; | | 372 | errno = EIO; |
373 | goto bad; | | 373 | goto bad; |
374 | } | | 374 | } |
375 | | | 375 | |
376 | puffs_framebuf_getdata_atoff(pufbuf, sizeof(int), | | 376 | puffs_framebuf_getdata_atoff(pufbuf, sizeof(int), |
377 | &fd, sizeof(int)); | | 377 | &fd, sizeof(int)); |
378 | puffs_framebuf_destroy(pufbuf); | | 378 | puffs_framebuf_destroy(pufbuf); |
379 | | | 379 | |
380 | data = 1; | | 380 | data = 1; |
381 | if (ioctl(fd, FIONBIO, &data) == -1) | | 381 | if (ioctl(fd, FIONBIO, &data) == -1) |
382 | return errno; | | 382 | return errno; |
383 | | | 383 | |
384 | if (puffs_framev_addfd(pu, fd, PUFFS_FBIO_WRITE) == -1) | | 384 | if (puffs_framev_addfd(pu, fd, PUFFS_FBIO_WRITE) == -1) |
385 | return errno; | | 385 | return errno; |
386 | | | 386 | |
387 | portn->fd = fd; | | 387 | portn->fd = fd; |
388 | return 0; | | 388 | return 0; |
389 | } | | 389 | } |
390 | | | 390 | |
391 | bad: | | 391 | bad: |
392 | puffs_framebuf_destroy(pufbuf); | | 392 | puffs_framebuf_destroy(pufbuf); |
393 | return errno; | | 393 | return errno; |
394 | } | | 394 | } |
395 | | | 395 | |
396 | int | | 396 | int |
397 | main(int argc, char *argv[]) | | 397 | main(int argc, char *argv[]) |
398 | { | | 398 | { |
399 | extern char *optarg; | | | |
400 | extern int optind; | | | |
401 | struct puffs_usermount *pu; | | 399 | struct puffs_usermount *pu; |
402 | struct puffs_ops *pops; | | 400 | struct puffs_ops *pops; |
403 | mntoptparse_t mp; | | 401 | mntoptparse_t mp; |
404 | int pflags, mntflags; | | 402 | int pflags, mntflags; |
405 | int detach; | | 403 | int detach; |
406 | int ch; | | 404 | int ch; |
407 | | | 405 | |
408 | setprogname(argv[0]); | | 406 | setprogname(argv[0]); |
409 | | | 407 | |
410 | mntflags = pflags = 0; | | 408 | mntflags = pflags = 0; |
411 | detach = 1; | | 409 | detach = 1; |
412 | while ((ch = getopt(argc, argv, "o:s")) != -1) { | | 410 | while ((ch = getopt(argc, argv, "o:s")) != -1) { |
413 | switch (ch) { | | 411 | switch (ch) { |
414 | case 'o': | | 412 | case 'o': |
415 | mp = getmntopts(optarg, puffsmopts, &mntflags, &pflags); | | 413 | mp = getmntopts(optarg, puffsmopts, &mntflags, &pflags); |
416 | if (mp == NULL) | | 414 | if (mp == NULL) |
417 | err(1, "getmntopts"); | | 415 | err(1, "getmntopts"); |
418 | freemntopts(mp); | | 416 | freemntopts(mp); |
419 | break; | | 417 | break; |
420 | case 's': /* stay on top */ | | 418 | case 's': /* stay on top */ |
421 | detach = 0; | | 419 | detach = 0; |
422 | break; | | 420 | break; |
423 | default: | | 421 | default: |
424 | usage(); | | 422 | usage(); |
425 | /*NOTREACHED*/ | | 423 | /*NOTREACHED*/ |
426 | } | | 424 | } |
427 | } | | 425 | } |
428 | pflags |= PUFFS_KFLAG_NOCACHE | PUFFS_KFLAG_LOOKUP_FULLPNBUF; | | 426 | pflags |= PUFFS_KFLAG_NOCACHE | PUFFS_KFLAG_LOOKUP_FULLPNBUF; |
429 | if (pflags & PUFFS_FLAG_OPDUMP) | | 427 | if (pflags & PUFFS_FLAG_OPDUMP) |
430 | detach = 0; | | 428 | detach = 0; |
431 | argc -= optind; | | 429 | argc -= optind; |
432 | argv += optind; | | 430 | argv += optind; |
433 | | | 431 | |
434 | if (argc != 2) | | 432 | if (argc != 2) |
435 | usage(); | | 433 | usage(); |
436 | | | 434 | |
437 | PUFFSOP_INIT(pops); | | 435 | PUFFSOP_INIT(pops); |
438 | | | 436 | |
439 | PUFFSOP_SETFSNOP(pops, unmount); | | 437 | PUFFSOP_SETFSNOP(pops, unmount); |
440 | PUFFSOP_SETFSNOP(pops, sync); | | 438 | PUFFSOP_SETFSNOP(pops, sync); |
441 | PUFFSOP_SETFSNOP(pops, statvfs); | | 439 | PUFFSOP_SETFSNOP(pops, statvfs); |
442 | | | 440 | |
443 | PUFFSOP_SET(pops, portal, node, lookup); | | 441 | PUFFSOP_SET(pops, portal, node, lookup); |
444 | PUFFSOP_SET(pops, portal, node, getattr); | | 442 | PUFFSOP_SET(pops, portal, node, getattr); |
445 | PUFFSOP_SET(pops, portal, node, setattr); | | 443 | PUFFSOP_SET(pops, portal, node, setattr); |
446 | PUFFSOP_SET(pops, portal, node, open); | | 444 | PUFFSOP_SET(pops, portal, node, open); |
447 | PUFFSOP_SET(pops, portal, node, read); | | 445 | PUFFSOP_SET(pops, portal, node, read); |
448 | PUFFSOP_SET(pops, portal, node, write); | | 446 | PUFFSOP_SET(pops, portal, node, write); |
449 | PUFFSOP_SET(pops, portal, node, seek); | | 447 | PUFFSOP_SET(pops, portal, node, seek); |
450 | PUFFSOP_SET(pops, portal, node, poll); | | 448 | PUFFSOP_SET(pops, portal, node, poll); |
451 | PUFFSOP_SET(pops, portal, node, inactive); | | 449 | PUFFSOP_SET(pops, portal, node, inactive); |
452 | PUFFSOP_SET(pops, portal, node, reclaim); | | 450 | PUFFSOP_SET(pops, portal, node, reclaim); |
453 | | | 451 | |
454 | pu = puffs_init(pops, _PATH_PUFFS, "portal", NULL, pflags); | | 452 | pu = puffs_init(pops, _PATH_PUFFS, "portal", NULL, pflags); |
455 | if (pu == NULL) | | 453 | if (pu == NULL) |
456 | err(1, "init"); | | 454 | err(1, "init"); |
457 | | | 455 | |
458 | if (signal(SIGHUP, sighup) == SIG_ERR) | | 456 | if (signal(SIGHUP, sighup) == SIG_ERR) |
459 | warn("cannot set sighup handler"); | | 457 | warn("cannot set sighup handler"); |
460 | if (signal(SIGCHLD, sigcry) == SIG_ERR) | | 458 | if (signal(SIGCHLD, sigcry) == SIG_ERR) |
461 | err(1, "cannot set sigchild handler"); | | 459 | err(1, "cannot set sigchild handler"); |
462 | if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) | | 460 | if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) |
463 | err(1, "cannot ignore sigpipe"); | | 461 | err(1, "cannot ignore sigpipe"); |
464 | | | 462 | |
465 | readcfg = 0; | | 463 | readcfg = 0; |
466 | cfg = argv[0]; | | 464 | cfg = argv[0]; |
467 | if (*cfg != '/') | | 465 | if (*cfg != '/') |
468 | errx(1, "need absolute path for config"); | | 466 | errx(1, "need absolute path for config"); |
469 | q.q_forw = q.q_back = &q; | | 467 | q.q_forw = q.q_back = &q; |
470 | if (conf_read(&q, cfg) == -1) | | 468 | if (conf_read(&q, cfg) == -1) |
471 | err(1, "cannot read cfg \"%s\"", cfg); | | 469 | err(1, "cannot read cfg \"%s\"", cfg); |
472 | | | 470 | |
473 | puffs_ml_setloopfn(pu, portal_loopfn); | | 471 | puffs_ml_setloopfn(pu, portal_loopfn); |
474 | puffs_framev_init(pu, portal_frame_rf, portal_frame_wf, NULL,NULL,NULL); | | 472 | puffs_framev_init(pu, portal_frame_rf, portal_frame_wf, NULL,NULL,NULL); |
475 | | | 473 | |
476 | if (detach) | | 474 | if (detach) |
477 | if (puffs_daemon(pu, 1, 1) == -1) | | 475 | if (puffs_daemon(pu, 1, 1) == -1) |
478 | err(1, "puffs_daemon"); | | 476 | err(1, "puffs_daemon"); |
479 | | | 477 | |
480 | if (puffs_mount(pu, argv[1], mntflags, PORTAL_ROOT) == -1) | | 478 | if (puffs_mount(pu, argv[1], mntflags, PORTAL_ROOT) == -1) |
481 | err(1, "mount"); | | 479 | err(1, "mount"); |
482 | if (puffs_mainloop(pu) == -1) | | 480 | if (puffs_mainloop(pu) == -1) |
483 | err(1, "mainloop"); | | 481 | err(1, "mainloop"); |
484 | | | 482 | |
485 | return 0; | | 483 | return 0; |
486 | } | | 484 | } |
487 | | | 485 | |
488 | static struct portal_node * | | 486 | static struct portal_node * |
489 | makenode(const char *path) | | 487 | makenode(const char *path) |
490 | { | | 488 | { |
491 | struct portal_node *portn; | | 489 | struct portal_node *portn; |
492 | | | 490 | |
493 | portn = emalloc(sizeof(struct portal_node)); | | 491 | portn = emalloc(sizeof(struct portal_node)); |
494 | portn->path = estrdup(path); | | 492 | portn->path = estrdup(path); |
495 | portn->fd = -1; | | 493 | portn->fd = -1; |
496 | | | 494 | |
497 | return portn; | | 495 | return portn; |
498 | } | | 496 | } |
499 | | | 497 | |
500 | static void | | 498 | static void |
501 | credtr(struct portal_cred *portc, const struct puffs_cred *puffc, int mode) | | 499 | credtr(struct portal_cred *portc, const struct puffs_cred *puffc, int mode) |
502 | { | | 500 | { |
503 | memset(portc, 0, sizeof(struct portal_cred)); | | 501 | memset(portc, 0, sizeof(struct portal_cred)); |
504 | | | 502 | |
505 | portc->pcr_flag = mode; | | 503 | portc->pcr_flag = mode; |
506 | puffs_cred_getuid(puffc, &portc->pcr_uid); | | 504 | puffs_cred_getuid(puffc, &portc->pcr_uid); |
507 | puffs_cred_getgid(puffc, &portc->pcr_gid); | | 505 | puffs_cred_getgid(puffc, &portc->pcr_gid); |
508 | puffs_cred_getgroups(puffc, portc->pcr_groups, | | 506 | puffs_cred_getgroups(puffc, portc->pcr_groups, |
509 | (short *)&portc->pcr_ngroups); | | 507 | (short *)&portc->pcr_ngroups); |
510 | } | | 508 | } |
511 | | | 509 | |
512 | /* | | 510 | /* |
513 | * XXX: we could also simply already resolve the name at this stage | | 511 | * XXX: we could also simply already resolve the name at this stage |
514 | * instead of deferring it to open. But doing it in open is how the | | 512 | * instead of deferring it to open. But doing it in open is how the |
515 | * original portald does it, and I don't want to introduce any funny | | 513 | * original portald does it, and I don't want to introduce any funny |
516 | * incompatibilities. | | 514 | * incompatibilities. |
517 | */ | | 515 | */ |
518 | int | | 516 | int |
519 | portal_node_lookup(struct puffs_usermount *pu, puffs_cookie_t opc, | | 517 | portal_node_lookup(struct puffs_usermount *pu, puffs_cookie_t opc, |
520 | struct puffs_newinfo *pni, const struct puffs_cn *pcn) | | 518 | struct puffs_newinfo *pni, const struct puffs_cn *pcn) |
521 | { | | 519 | { |
522 | struct portal_node *portn; | | 520 | struct portal_node *portn; |
523 | | | 521 | |
524 | assert(opc == PORTAL_ROOT); | | 522 | assert(opc == PORTAL_ROOT); |
525 | | | 523 | |
526 | if (pcn->pcn_nameiop != NAMEI_LOOKUP | | 524 | if (pcn->pcn_nameiop != NAMEI_LOOKUP |
527 | && pcn->pcn_nameiop != NAMEI_CREATE) | | 525 | && pcn->pcn_nameiop != NAMEI_CREATE) |
528 | return EOPNOTSUPP; | | 526 | return EOPNOTSUPP; |
529 | | | 527 | |
530 | portn = makenode(pcn->pcn_name); | | 528 | portn = makenode(pcn->pcn_name); |
531 | puffs_newinfo_setcookie(pni, portn); | | 529 | puffs_newinfo_setcookie(pni, portn); |
532 | puffs_newinfo_setvtype(pni, VREG); | | 530 | puffs_newinfo_setvtype(pni, VREG); |
533 | | | 531 | |
534 | pcn->pcn_flags &= ~NAMEI_REQUIREDIR; | | 532 | pcn->pcn_flags &= ~NAMEI_REQUIREDIR; |
535 | pcn->pcn_consume = strlen(pcn->pcn_name) - pcn->pcn_namelen; | | 533 | pcn->pcn_consume = strlen(pcn->pcn_name) - pcn->pcn_namelen; |
536 | | | 534 | |
537 | return 0; | | 535 | return 0; |
538 | } | | 536 | } |
539 | | | 537 | |
540 | unsigned int fakeid = 3; | | 538 | unsigned int fakeid = 3; |
541 | | | 539 | |
542 | /* XXX: libpuffs'ize */ | | 540 | /* XXX: libpuffs'ize */ |
543 | int | | 541 | int |
544 | portal_node_getattr(struct puffs_usermount *pu, puffs_cookie_t opc, | | 542 | portal_node_getattr(struct puffs_usermount *pu, puffs_cookie_t opc, |
545 | struct vattr *va, const struct puffs_cred *pcr) | | 543 | struct vattr *va, const struct puffs_cred *pcr) |
546 | { | | 544 | { |
547 | struct timeval tv; | | 545 | struct timeval tv; |
548 | struct timespec ts; | | 546 | struct timespec ts; |
549 | int res = 0; | | 547 | int res = 0; |
550 | | | 548 | |
551 | puffs_vattr_null(va); | | 549 | puffs_vattr_null(va); |
552 | if (opc == PORTAL_ROOT) { | | 550 | if (opc == PORTAL_ROOT) { |
553 | va->va_type = VDIR; | | 551 | va->va_type = VDIR; |
554 | va->va_mode = 0777; | | 552 | va->va_mode = 0777; |
555 | va->va_nlink = 2; | | 553 | va->va_nlink = 2; |
556 | va->va_uid = va->va_gid = 0; | | 554 | va->va_uid = va->va_gid = 0; |
557 | #if 0 /* XXX Huh? */ | | 555 | #if 0 /* XXX Huh? */ |
558 | va->va_fileid = fakeid++; | | 556 | va->va_fileid = fakeid++; |
559 | #else | | 557 | #else |
560 | va->va_fileid = 2; /*XXX; ROOTINO*/ | | 558 | va->va_fileid = 2; /*XXX; ROOTINO*/ |
561 | #endif | | 559 | #endif |
562 | va->va_size = va->va_bytes = 0; | | 560 | va->va_size = va->va_bytes = 0; |
563 | va->va_gen = 0; | | 561 | va->va_gen = 0; |
564 | va->va_rdev = PUFFS_VNOVAL; | | 562 | va->va_rdev = PUFFS_VNOVAL; |
565 | va->va_blocksize = DEV_BSIZE; | | 563 | va->va_blocksize = DEV_BSIZE; |
566 | | | 564 | |
567 | gettimeofday(&tv, NULL); | | 565 | gettimeofday(&tv, NULL); |
568 | TIMEVAL_TO_TIMESPEC(&tv, &ts); | | 566 | TIMEVAL_TO_TIMESPEC(&tv, &ts); |
569 | va->va_atime = va->va_ctime = va->va_mtime = | | 567 | va->va_atime = va->va_ctime = va->va_mtime = |
570 | va->va_birthtime = ts; | | 568 | va->va_birthtime = ts; |
571 | } else { | | 569 | } else { |
572 | /* cheat for now */ | | 570 | /* cheat for now */ |
573 | int error; | | 571 | int error; |
574 | int newfd; | | 572 | int newfd; |
575 | struct stat st; | | 573 | struct stat st; |
576 | struct portal_node *portn = opc; | | 574 | struct portal_node *portn = opc; |
577 | struct portal_cred portc; | | 575 | struct portal_cred portc; |
578 | char **v = conf_match(&q, portn->path); | | 576 | char **v = conf_match(&q, portn->path); |
579 | | | 577 | |
580 | if (v == NULL) | | 578 | if (v == NULL) |
581 | return ENOENT; | | 579 | return ENOENT; |
582 | if (portn->fd == -1) { | | 580 | if (portn->fd == -1) { |
583 | credtr(&portc, pcr, 0777); | | 581 | credtr(&portc, pcr, 0777); |
584 | error = provide(pu, portn, &portc, v); | | 582 | error = provide(pu, portn, &portc, v); |
585 | if (error) | | 583 | if (error) |
586 | return error; | | 584 | return error; |
587 | newfd = 1; | | 585 | newfd = 1; |
588 | } else | | 586 | } else |
589 | newfd = 0; | | 587 | newfd = 0; |
590 | | | 588 | |
591 | if (fstat(portn->fd, &st) == -1) | | 589 | if (fstat(portn->fd, &st) == -1) |
592 | res = errno; | | 590 | res = errno; |
593 | else { | | 591 | else { |
594 | #if 0 | | 592 | #if 0 |
595 | va->va_type = S_ISDIR(st.st_mode) ? VDIR : VREG; /* XXX */ | | 593 | va->va_type = S_ISDIR(st.st_mode) ? VDIR : VREG; /* XXX */ |
596 | #else | | 594 | #else |
597 | va->va_type = puffs_mode2vt(st.st_mode); | | 595 | va->va_type = puffs_mode2vt(st.st_mode); |
598 | #endif | | 596 | #endif |
599 | /* puffs supplies S_IFMT bits later */ | | 597 | /* puffs supplies S_IFMT bits later */ |
600 | va->va_mode = (st.st_mode & ~S_IFMT); | | 598 | va->va_mode = (st.st_mode & ~S_IFMT); |
601 | | | 599 | |
602 | va->va_nlink = st.st_nlink ? st.st_nlink : 1; | | 600 | va->va_nlink = st.st_nlink ? st.st_nlink : 1; |
603 | va->va_uid = st.st_uid; | | 601 | va->va_uid = st.st_uid; |
604 | va->va_gid = st.st_gid; | | 602 | va->va_gid = st.st_gid; |
605 | va->va_fileid = st.st_ino ? st.st_ino : fakeid++; | | 603 | va->va_fileid = st.st_ino ? st.st_ino : fakeid++; |
606 | va->va_size = va->va_bytes = st.st_size; | | 604 | va->va_size = va->va_bytes = st.st_size; |
607 | va->va_gen = 0; | | 605 | va->va_gen = 0; |
608 | va->va_rdev = st.st_rdev; | | 606 | va->va_rdev = st.st_rdev; |
609 | va->va_blocksize = st.st_blksize; | | 607 | va->va_blocksize = st.st_blksize; |
610 | va->va_atime = st.st_atim; | | 608 | va->va_atime = st.st_atim; |
611 | va->va_ctime = st.st_ctim; | | 609 | va->va_ctime = st.st_ctim; |
612 | va->va_mtime = st.st_mtim; | | 610 | va->va_mtime = st.st_mtim; |
613 | va->va_birthtime = st.st_birthtim; | | 611 | va->va_birthtime = st.st_birthtim; |
614 | } | | 612 | } |
615 | if (newfd) { | | 613 | if (newfd) { |
616 | puffs_framev_removefd(pu, portn->fd, 0); | | 614 | puffs_framev_removefd(pu, portn->fd, 0); |
617 | close(portn->fd); | | 615 | close(portn->fd); |
618 | portn->fd = -1; | | 616 | portn->fd = -1; |
619 | } | | 617 | } |
620 | } | | 618 | } |
621 | | | 619 | |
622 | return res; | | 620 | return res; |
623 | } | | 621 | } |
624 | | | 622 | |
625 | /* for writing, just pretend we care */ | | 623 | /* for writing, just pretend we care */ |
626 | int | | 624 | int |
627 | portal_node_setattr(struct puffs_usermount *pu, puffs_cookie_t opc, | | 625 | portal_node_setattr(struct puffs_usermount *pu, puffs_cookie_t opc, |
628 | const struct vattr *va, const struct puffs_cred *pcr) | | 626 | const struct vattr *va, const struct puffs_cred *pcr) |
629 | { | | 627 | { |
630 | | | 628 | |
631 | return 0; | | 629 | return 0; |
632 | } | | 630 | } |
633 | | | 631 | |
634 | int | | 632 | int |
635 | portal_node_open(struct puffs_usermount *pu, puffs_cookie_t opc, int mode, | | 633 | portal_node_open(struct puffs_usermount *pu, puffs_cookie_t opc, int mode, |
636 | const struct puffs_cred *pcr) | | 634 | const struct puffs_cred *pcr) |
637 | { | | 635 | { |
638 | struct portal_node *portn = opc; | | 636 | struct portal_node *portn = opc; |
639 | struct portal_cred portc; | | 637 | struct portal_cred portc; |
640 | char **v; | | 638 | char **v; |
641 | | | 639 | |
642 | if (opc == PORTAL_ROOT) | | 640 | if (opc == PORTAL_ROOT) |
643 | return 0; | | 641 | return 0; |
644 | | | 642 | |
645 | if (mode & O_NONBLOCK) | | 643 | if (mode & O_NONBLOCK) |
646 | return EOPNOTSUPP; | | 644 | return EOPNOTSUPP; |
647 | | | 645 | |
648 | v = conf_match(&q, portn->path); | | 646 | v = conf_match(&q, portn->path); |
649 | if (v == NULL) | | 647 | if (v == NULL) |
650 | return ENOENT; | | 648 | return ENOENT; |
651 | | | 649 | |
652 | credtr(&portc, pcr, mode); | | 650 | credtr(&portc, pcr, mode); |
653 | return provide(pu, portn, &portc, v); | | 651 | return provide(pu, portn, &portc, v); |
654 | } | | 652 | } |
655 | | | 653 | |
656 | int | | 654 | int |
657 | portal_node_read(struct puffs_usermount *pu, puffs_cookie_t opc, | | 655 | portal_node_read(struct puffs_usermount *pu, puffs_cookie_t opc, |
658 | uint8_t *buf, off_t offset, size_t *resid, | | 656 | uint8_t *buf, off_t offset, size_t *resid, |
659 | const struct puffs_cred *pcr, int ioflag) | | 657 | const struct puffs_cred *pcr, int ioflag) |
660 | { | | 658 | { |
661 | struct puffs_cc *pcc = puffs_cc_getcc(pu); | | 659 | struct puffs_cc *pcc = puffs_cc_getcc(pu); |
662 | struct portal_node *portn = opc; | | 660 | struct portal_node *portn = opc; |
663 | struct puffs_framebuf *pufbuf; | | 661 | struct puffs_framebuf *pufbuf; |
664 | size_t xfersize, winsize, boff; | | 662 | size_t xfersize, winsize, boff; |
665 | void *win; | | 663 | void *win; |
666 | int rv, error; | | 664 | int rv, error; |
667 | int data, dummy; | | 665 | int data, dummy; |
668 | | | 666 | |
669 | assert(opc != PORTAL_ROOT); | | 667 | assert(opc != PORTAL_ROOT); |
670 | error = 0; | | 668 | error = 0; |
671 | | | 669 | |
672 | /* if we can't (re-)enable it, treat it as EOF */ | | 670 | /* if we can't (re-)enable it, treat it as EOF */ |
673 | rv = puffs_framev_enablefd(pu, portn->fd, PUFFS_FBIO_READ); | | 671 | rv = puffs_framev_enablefd(pu, portn->fd, PUFFS_FBIO_READ); |
674 | if (rv == -1) | | 672 | if (rv == -1) |
675 | return 0; | | 673 | return 0; |
676 | | | 674 | |
677 | pufbuf = puffs_framebuf_make(); | | 675 | pufbuf = puffs_framebuf_make(); |
678 | data = PUFBUF_DATA; | | 676 | data = PUFBUF_DATA; |
679 | puffs_framebuf_putdata(pufbuf, &data, sizeof(int)); | | 677 | puffs_framebuf_putdata(pufbuf, &data, sizeof(int)); |
680 | puffs_framebuf_putdata(pufbuf, resid, sizeof(size_t)); | | 678 | puffs_framebuf_putdata(pufbuf, resid, sizeof(size_t)); |
681 | | | 679 | |
682 | /* if we are doing nodelay, do read directly */ | | 680 | /* if we are doing nodelay, do read directly */ |
683 | if (ioflag & PUFFS_IO_NDELAY) { | | 681 | if (ioflag & PUFFS_IO_NDELAY) { |
684 | rv = readdata(pufbuf, portn->fd, &dummy); | | 682 | rv = readdata(pufbuf, portn->fd, &dummy); |
685 | if (rv != 0) { | | 683 | if (rv != 0) { |
686 | error = rv; | | 684 | error = rv; |
687 | goto out; | | 685 | goto out; |
688 | } | | 686 | } |
689 | } else { | | 687 | } else { |
690 | rv = puffs_framev_enqueue_directreceive(pcc, | | 688 | rv = puffs_framev_enqueue_directreceive(pcc, |
691 | portn->fd, pufbuf, 0); | | 689 | portn->fd, pufbuf, 0); |
692 | | | 690 | |
693 | if (rv == -1) { | | 691 | if (rv == -1) { |
694 | error = errno; | | 692 | error = errno; |
695 | goto out; | | 693 | goto out; |
696 | } | | 694 | } |
697 | } | | 695 | } |
698 | | | 696 | |
699 | xfersize = puffs_framebuf_tellsize(pufbuf) - METADATASIZE; | | 697 | xfersize = puffs_framebuf_tellsize(pufbuf) - METADATASIZE; |
700 | if (xfersize == 0) { | | 698 | if (xfersize == 0) { |
701 | assert(ioflag & PUFFS_IO_NDELAY); | | 699 | assert(ioflag & PUFFS_IO_NDELAY); |
702 | error = EAGAIN; | | 700 | error = EAGAIN; |
703 | goto out; | | 701 | goto out; |
704 | } | | 702 | } |
705 | | | 703 | |
706 | *resid -= xfersize; | | 704 | *resid -= xfersize; |
707 | boff = 0; | | 705 | boff = 0; |
708 | while (xfersize > 0) { | | 706 | while (xfersize > 0) { |
709 | winsize = xfersize; | | 707 | winsize = xfersize; |
710 | rv = puffs_framebuf_getwindow(pufbuf, METADATASIZE, | | 708 | rv = puffs_framebuf_getwindow(pufbuf, METADATASIZE, |
711 | &win, &winsize); | | 709 | &win, &winsize); |
712 | assert(rv == 0); | | 710 | assert(rv == 0); |
713 | assert(winsize > 0); | | 711 | assert(winsize > 0); |
714 | | | 712 | |
715 | memcpy(buf + boff, win, winsize); | | 713 | memcpy(buf + boff, win, winsize); |
716 | xfersize -= winsize; | | 714 | xfersize -= winsize; |
717 | boff += winsize; | | 715 | boff += winsize; |
718 | } | | 716 | } |
719 | | | 717 | |
720 | out: | | 718 | out: |
721 | puffs_framev_disablefd(pu, portn->fd, PUFFS_FBIO_READ); | | 719 | puffs_framev_disablefd(pu, portn->fd, PUFFS_FBIO_READ); |
722 | puffs_framebuf_destroy(pufbuf); | | 720 | puffs_framebuf_destroy(pufbuf); |
723 | | | 721 | |
724 | /* a trickery, from readdata() */ | | 722 | /* a trickery, from readdata() */ |
725 | if (error == -1) | | 723 | if (error == -1) |
726 | return 0; | | 724 | return 0; |
727 | return error; | | 725 | return error; |
728 | } | | 726 | } |
729 | | | 727 | |
730 | int | | 728 | int |
731 | portal_node_write(struct puffs_usermount *pu, puffs_cookie_t opc, | | 729 | portal_node_write(struct puffs_usermount *pu, puffs_cookie_t opc, |
732 | uint8_t *buf, off_t offset, size_t *resid, | | 730 | uint8_t *buf, off_t offset, size_t *resid, |
733 | const struct puffs_cred *pcr, int ioflag) | | 731 | const struct puffs_cred *pcr, int ioflag) |
734 | { | | 732 | { |
735 | struct puffs_cc *pcc = puffs_cc_getcc(pu); | | 733 | struct puffs_cc *pcc = puffs_cc_getcc(pu); |
736 | struct portal_node *portn = opc; | | 734 | struct portal_node *portn = opc; |
737 | struct puffs_framebuf *pufbuf; | | 735 | struct puffs_framebuf *pufbuf; |
738 | size_t written; | | 736 | size_t written; |
739 | int error, rv, dummy; | | 737 | int error, rv, dummy; |
740 | | | 738 | |
741 | assert(opc != PORTAL_ROOT); | | 739 | assert(opc != PORTAL_ROOT); |
742 | | | 740 | |
743 | pufbuf = puffs_framebuf_make(); | | 741 | pufbuf = puffs_framebuf_make(); |
744 | puffs_framebuf_putdata(pufbuf, buf, *resid); | | 742 | puffs_framebuf_putdata(pufbuf, buf, *resid); |
745 | | | 743 | |
746 | error = 0; | | 744 | error = 0; |
747 | if (ioflag & PUFFS_IO_NDELAY) { | | 745 | if (ioflag & PUFFS_IO_NDELAY) { |
748 | rv = portal_frame_wf(pu, pufbuf, portn->fd, &dummy); | | 746 | rv = portal_frame_wf(pu, pufbuf, portn->fd, &dummy); |
749 | if (rv) { | | 747 | if (rv) { |
750 | error = rv; | | 748 | error = rv; |
751 | goto out; | | 749 | goto out; |
752 | } | | 750 | } |
753 | } else { | | 751 | } else { |
754 | rv = puffs_framev_enqueue_directsend(pcc, portn->fd, pufbuf, 0); | | 752 | rv = puffs_framev_enqueue_directsend(pcc, portn->fd, pufbuf, 0); |
755 | if (rv == -1) { | | 753 | if (rv == -1) { |
756 | error = errno; | | 754 | error = errno; |
757 | goto out; | | 755 | goto out; |
758 | } | | 756 | } |
759 | } | | 757 | } |
760 | | | 758 | |
761 | rv = puffs_framebuf_getdata_atoff(pufbuf, 0, &written, sizeof(size_t)); | | 759 | rv = puffs_framebuf_getdata_atoff(pufbuf, 0, &written, sizeof(size_t)); |
762 | assert(rv == 0); | | 760 | assert(rv == 0); |
763 | assert(written <= *resid); | | 761 | assert(written <= *resid); |
764 | *resid -= written; | | 762 | *resid -= written; |
765 | | | 763 | |
766 | out: | | 764 | out: |
767 | puffs_framebuf_destroy(pufbuf); | | 765 | puffs_framebuf_destroy(pufbuf); |
768 | if (error == -1) | | 766 | if (error == -1) |
769 | error = 0; | | 767 | error = 0; |
770 | return 0; | | 768 | return 0; |
771 | } | | 769 | } |
772 | | | 770 | |
773 | int | | 771 | int |
774 | portal_node_seek(struct puffs_usermount *pu, puffs_cookie_t opc, | | 772 | portal_node_seek(struct puffs_usermount *pu, puffs_cookie_t opc, |
775 | off_t oldoff, off_t newoff, const struct puffs_cred *pcr) | | 773 | off_t oldoff, off_t newoff, const struct puffs_cred *pcr) |
776 | { | | 774 | { |
777 | struct portal_node *portn = opc; | | 775 | struct portal_node *portn = opc; |
778 | | | 776 | |
779 | if (opc == PORTAL_ROOT || portn->fd == -1) | | 777 | if (opc == PORTAL_ROOT || portn->fd == -1) |
780 | return EOPNOTSUPP; | | 778 | return EOPNOTSUPP; |
781 | | | 779 | |
782 | if (lseek(portn->fd, newoff, SEEK_SET) == -1) | | 780 | if (lseek(portn->fd, newoff, SEEK_SET) == -1) |
783 | return errno; | | 781 | return errno; |
784 | return 0; | | 782 | return 0; |
785 | } | | 783 | } |
786 | | | 784 | |
787 | int | | 785 | int |
788 | portal_node_poll(struct puffs_usermount *pu, puffs_cookie_t opc, int *events) | | 786 | portal_node_poll(struct puffs_usermount *pu, puffs_cookie_t opc, int *events) |
789 | { | | 787 | { |
790 | struct puffs_cc *pcc = puffs_cc_getcc(pu); | | 788 | struct puffs_cc *pcc = puffs_cc_getcc(pu); |
791 | struct portal_node *portn = opc; | | 789 | struct portal_node *portn = opc; |
792 | int what; | | 790 | int what; |
793 | | | 791 | |
794 | what = 0; | | 792 | what = 0; |
795 | if (*events & POLLIN) | | 793 | if (*events & POLLIN) |
796 | what |= PUFFS_FBIO_READ; | | 794 | what |= PUFFS_FBIO_READ; |
797 | if (*events & POLLOUT) | | 795 | if (*events & POLLOUT) |
798 | what |= PUFFS_FBIO_WRITE; | | 796 | what |= PUFFS_FBIO_WRITE; |
799 | if (*events & POLLERR) | | 797 | if (*events & POLLERR) |
800 | what |= PUFFS_FBIO_ERROR; | | 798 | what |= PUFFS_FBIO_ERROR; |
801 | | | 799 | |
802 | if (puffs_framev_enqueue_waitevent(pcc, portn->fd, &what) == -1) { | | 800 | if (puffs_framev_enqueue_waitevent(pcc, portn->fd, &what) == -1) { |
803 | *events = POLLERR; | | 801 | *events = POLLERR; |
804 | return errno; | | 802 | return errno; |
805 | } | | 803 | } |
806 | | | 804 | |
807 | *events = 0; | | 805 | *events = 0; |
808 | if (what & PUFFS_FBIO_READ) | | 806 | if (what & PUFFS_FBIO_READ) |
809 | *events |= POLLIN; | | 807 | *events |= POLLIN; |
810 | if (what & PUFFS_FBIO_WRITE) | | 808 | if (what & PUFFS_FBIO_WRITE) |
811 | *events |= POLLOUT; | | 809 | *events |= POLLOUT; |
812 | if (what & PUFFS_FBIO_ERROR) | | 810 | if (what & PUFFS_FBIO_ERROR) |
813 | *events |= POLLERR; | | 811 | *events |= POLLERR; |
814 | | | 812 | |
815 | return 0; | | 813 | return 0; |
816 | } | | 814 | } |
817 | | | 815 | |
818 | int | | 816 | int |
819 | portal_node_inactive(struct puffs_usermount *pu, puffs_cookie_t opc) | | 817 | portal_node_inactive(struct puffs_usermount *pu, puffs_cookie_t opc) |
820 | { | | 818 | { |
821 | | | 819 | |
822 | if (opc == PORTAL_ROOT) | | 820 | if (opc == PORTAL_ROOT) |
823 | return 0; | | 821 | return 0; |
824 | | | 822 | |
825 | puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1); | | 823 | puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1); |
826 | return 0; | | 824 | return 0; |
827 | } | | 825 | } |
828 | | | 826 | |
829 | int | | 827 | int |
830 | portal_node_reclaim(struct puffs_usermount *pu, puffs_cookie_t opc) | | 828 | portal_node_reclaim(struct puffs_usermount *pu, puffs_cookie_t opc) |
831 | { | | 829 | { |
832 | struct portal_node *portn = opc; | | 830 | struct portal_node *portn = opc; |
833 | | | 831 | |
834 | if (portn->fd != -1) { | | 832 | if (portn->fd != -1) { |
835 | puffs_framev_removefd(pu, portn->fd, 0); | | 833 | puffs_framev_removefd(pu, portn->fd, 0); |
836 | close(portn->fd); | | 834 | close(portn->fd); |
837 | } | | 835 | } |
838 | free(portn->path); | | 836 | free(portn->path); |
839 | free(portn); | | 837 | free(portn); |
840 | | | 838 | |
841 | return 0; | | 839 | return 0; |
842 | } | | 840 | } |