netbsd32_socket.c revision 1.39 1 1.39 joerg /* $NetBSD: netbsd32_socket.c,v 1.39 2012/01/20 14:08:07 joerg Exp $ */
2 1.1 mrg
3 1.1 mrg /*
4 1.1 mrg * Copyright (c) 1998, 2001 Matthew R. Green
5 1.1 mrg * All rights reserved.
6 1.1 mrg *
7 1.1 mrg * Redistribution and use in source and binary forms, with or without
8 1.1 mrg * modification, are permitted provided that the following conditions
9 1.1 mrg * are met:
10 1.1 mrg * 1. Redistributions of source code must retain the above copyright
11 1.1 mrg * notice, this list of conditions and the following disclaimer.
12 1.1 mrg * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 mrg * notice, this list of conditions and the following disclaimer in the
14 1.1 mrg * documentation and/or other materials provided with the distribution.
15 1.1 mrg *
16 1.1 mrg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 1.1 mrg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 1.1 mrg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 1.1 mrg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 1.1 mrg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 1.1 mrg * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 1.1 mrg * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 1.1 mrg * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 1.1 mrg * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 1.1 mrg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 1.1 mrg * SUCH DAMAGE.
27 1.1 mrg */
28 1.6 lukem
29 1.6 lukem #include <sys/cdefs.h>
30 1.39 joerg __KERNEL_RCSID(0, "$NetBSD: netbsd32_socket.c,v 1.39 2012/01/20 14:08:07 joerg Exp $");
31 1.1 mrg
32 1.1 mrg #include <sys/param.h>
33 1.1 mrg #include <sys/systm.h>
34 1.1 mrg #define msg __msg /* Don't ask me! */
35 1.1 mrg #include <sys/mount.h>
36 1.1 mrg #include <sys/socket.h>
37 1.1 mrg #include <sys/sockio.h>
38 1.1 mrg #include <sys/socketvar.h>
39 1.1 mrg #include <sys/mbuf.h>
40 1.1 mrg #include <sys/ktrace.h>
41 1.1 mrg #include <sys/file.h>
42 1.1 mrg #include <sys/filedesc.h>
43 1.1 mrg #include <sys/syscallargs.h>
44 1.1 mrg #include <sys/proc.h>
45 1.15 christos #include <sys/dirent.h>
46 1.1 mrg
47 1.1 mrg #include <compat/netbsd32/netbsd32.h>
48 1.1 mrg #include <compat/netbsd32/netbsd32_syscallargs.h>
49 1.1 mrg #include <compat/netbsd32/netbsd32_conv.h>
50 1.1 mrg
51 1.37 rmind /*
52 1.39 joerg * XXX Assumes that struct sockaddr is compatible.
53 1.37 rmind */
54 1.39 joerg
55 1.39 joerg #define CMSG32_ALIGN(n) (((n) + ALIGNBYTES32) & ~ALIGNBYTES32)
56 1.39 joerg #define CMSG32_DATA(cmsg) \
57 1.39 joerg ((u_char *)(void *)(cmsg) + CMSG32_ALIGN(sizeof(struct cmsghdr)))
58 1.39 joerg
59 1.39 joerg #define CMSG32_NXTHDR(mhdr, cmsg) \
60 1.39 joerg (((char *)(cmsg) + CMSG32_ALIGN((cmsg)->cmsg_len) + \
61 1.39 joerg CMSG32_ALIGN(sizeof(struct cmsghdr)) > \
62 1.39 joerg (((char *)(mhdr)->msg_control) + (mhdr)->msg_controllen)) ? \
63 1.39 joerg (struct cmsghdr *)0 : \
64 1.39 joerg (struct cmsghdr *)((char *)(cmsg) + \
65 1.39 joerg CMSG32_ALIGN((cmsg)->cmsg_len)))
66 1.39 joerg #define CMSG32_FIRSTHDR(mhdr) \
67 1.39 joerg ((mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \
68 1.39 joerg (struct cmsghdr *)(mhdr)->msg_control : \
69 1.39 joerg (struct cmsghdr *)0)
70 1.39 joerg
71 1.39 joerg #define CMSG32_SPACE(l) (CMSG32_ALIGN(sizeof(struct cmsghdr)) + CMSG32_ALIGN(l))
72 1.39 joerg #define CMSG32_LEN(l) (CMSG32_ALIGN(sizeof(struct cmsghdr)) + (l))
73 1.39 joerg
74 1.39 joerg static int
75 1.39 joerg copyout32_msg_control_mbuf(struct lwp *l, struct msghdr *mp, int *len, struct mbuf *m, char **q, bool *truncated)
76 1.39 joerg {
77 1.39 joerg struct cmsghdr *cmsg, cmsg32;
78 1.39 joerg int i, j, error;
79 1.39 joerg
80 1.39 joerg *truncated = false;
81 1.39 joerg cmsg = mtod(m, struct cmsghdr *);
82 1.39 joerg do {
83 1.39 joerg if ((char *)cmsg == mtod(m, char *) + m->m_len)
84 1.39 joerg break;
85 1.39 joerg if ((char *)cmsg > mtod(m, char *) + m->m_len - sizeof(*cmsg))
86 1.39 joerg return EINVAL;
87 1.39 joerg cmsg32 = *cmsg;
88 1.39 joerg j = cmsg->cmsg_len - CMSG_LEN(0);
89 1.39 joerg i = cmsg32.cmsg_len = CMSG32_LEN(j);
90 1.39 joerg if (i > *len) {
91 1.39 joerg mp->msg_flags |= MSG_CTRUNC;
92 1.39 joerg if (cmsg->cmsg_level == SOL_SOCKET
93 1.39 joerg && cmsg->cmsg_type == SCM_RIGHTS) {
94 1.39 joerg *truncated = true;
95 1.39 joerg return 0;
96 1.39 joerg }
97 1.39 joerg j -= i - *len;
98 1.39 joerg i = *len;
99 1.39 joerg }
100 1.39 joerg
101 1.39 joerg ktrkuser("msgcontrol", cmsg, cmsg->cmsg_len);
102 1.39 joerg error = copyout(&cmsg32, *q, MAX(i, sizeof(cmsg32)));
103 1.39 joerg if (error)
104 1.39 joerg return (error);
105 1.39 joerg if (i > CMSG32_LEN(0)) {
106 1.39 joerg error = copyout(CMSG_DATA(cmsg), *q + CMSG32_LEN(0), i - CMSG32_LEN(0));
107 1.39 joerg if (error)
108 1.39 joerg return (error);
109 1.39 joerg }
110 1.39 joerg j = CMSG32_SPACE(cmsg->cmsg_len - CMSG_LEN(0));
111 1.39 joerg if (*len >= j) {
112 1.39 joerg *len -= j;
113 1.39 joerg *q += j;
114 1.39 joerg } else {
115 1.39 joerg *q += i;
116 1.39 joerg *len = 0;
117 1.39 joerg }
118 1.39 joerg cmsg = (void *)((char *)cmsg + CMSG_ALIGN(cmsg->cmsg_len));
119 1.39 joerg } while (*len > 0);
120 1.39 joerg
121 1.39 joerg return 0;
122 1.39 joerg }
123 1.39 joerg
124 1.39 joerg static int
125 1.39 joerg copyout32_msg_control(struct lwp *l, struct msghdr *mp, struct mbuf *control)
126 1.39 joerg {
127 1.39 joerg int len, error = 0;
128 1.39 joerg struct mbuf *m;
129 1.39 joerg char *q;
130 1.39 joerg bool truncated;
131 1.39 joerg
132 1.39 joerg len = mp->msg_controllen;
133 1.39 joerg if (len <= 0 || control == 0) {
134 1.39 joerg mp->msg_controllen = 0;
135 1.39 joerg free_control_mbuf(l, control, control);
136 1.39 joerg return 0;
137 1.39 joerg }
138 1.39 joerg
139 1.39 joerg q = (char *)mp->msg_control;
140 1.39 joerg
141 1.39 joerg for (m = control; m != NULL; m = m->m_next) {
142 1.39 joerg error = copyout32_msg_control_mbuf(l, mp, &len, m, &q, &truncated);
143 1.39 joerg if (truncated) {
144 1.39 joerg m = control;
145 1.39 joerg break;
146 1.39 joerg }
147 1.39 joerg if (error)
148 1.39 joerg break;
149 1.39 joerg if (len <= 0)
150 1.39 joerg break;
151 1.39 joerg }
152 1.39 joerg
153 1.39 joerg free_control_mbuf(l, control, m);
154 1.39 joerg
155 1.39 joerg mp->msg_controllen = q - (char *)mp->msg_control;
156 1.39 joerg return error;
157 1.39 joerg }
158 1.39 joerg
159 1.1 mrg int
160 1.30 dsl netbsd32_recvmsg(struct lwp *l, const struct netbsd32_recvmsg_args *uap, register_t *retval)
161 1.1 mrg {
162 1.30 dsl /* {
163 1.1 mrg syscallarg(int) s;
164 1.1 mrg syscallarg(netbsd32_msghdrp_t) msg;
165 1.1 mrg syscallarg(int) flags;
166 1.30 dsl } */
167 1.38 joerg struct netbsd32_msghdr msg32;
168 1.35 njoly struct iovec aiov[UIO_SMALLIOV], *iov;
169 1.38 joerg struct msghdr msg;
170 1.38 joerg int error;
171 1.38 joerg struct mbuf *from, *control;
172 1.37 rmind size_t iovsz;
173 1.1 mrg
174 1.38 joerg error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32));
175 1.1 mrg if (error)
176 1.1 mrg return (error);
177 1.38 joerg
178 1.38 joerg iovsz = msg32.msg_iovlen * sizeof(struct iovec);
179 1.38 joerg if (msg32.msg_iovlen > UIO_SMALLIOV) {
180 1.38 joerg if (msg32.msg_iovlen > IOV_MAX)
181 1.1 mrg return (EMSGSIZE);
182 1.37 rmind iov = kmem_alloc(iovsz, KM_SLEEP);
183 1.25 christos } else
184 1.1 mrg iov = aiov;
185 1.38 joerg error = netbsd32_to_iovecin(NETBSD32PTR64(msg32.msg_iov), iov,
186 1.38 joerg msg32.msg_iovlen);
187 1.1 mrg if (error)
188 1.1 mrg goto done;
189 1.1 mrg
190 1.38 joerg msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS;
191 1.38 joerg msg.msg_name = NETBSD32PTR64(msg32.msg_name);
192 1.38 joerg msg.msg_namelen = msg32.msg_namelen;
193 1.38 joerg msg.msg_control = NETBSD32PTR64(msg32.msg_control);
194 1.38 joerg msg.msg_controllen = msg32.msg_controllen;
195 1.38 joerg msg.msg_iov = iov;
196 1.38 joerg msg.msg_iovlen = msg32.msg_iovlen;
197 1.13 perry
198 1.38 joerg error = do_sys_recvmsg(l, SCARG(uap, s), &msg, &from,
199 1.38 joerg msg.msg_control != NULL ? &control : NULL, retval);
200 1.38 joerg if (error != 0)
201 1.38 joerg goto done;
202 1.1 mrg
203 1.38 joerg if (msg.msg_control != NULL)
204 1.39 joerg error = copyout32_msg_control(l, &msg, control);
205 1.27 ad
206 1.38 joerg if (error == 0)
207 1.38 joerg error = copyout_sockname(msg.msg_name, &msg.msg_namelen, 0,
208 1.38 joerg from);
209 1.38 joerg if (from != NULL)
210 1.38 joerg m_free(from);
211 1.38 joerg if (error == 0) {
212 1.38 joerg ktrkuser("msghdr", &msg, sizeof msg);
213 1.38 joerg msg32.msg_namelen = msg.msg_namelen;
214 1.38 joerg msg32.msg_controllen = msg.msg_controllen;
215 1.38 joerg msg32.msg_flags = msg.msg_flags;
216 1.38 joerg error = copyout(&msg32, SCARG_P32(uap, msg), sizeof(msg32));
217 1.1 mrg }
218 1.27 ad
219 1.38 joerg done:
220 1.38 joerg if (iov != aiov)
221 1.38 joerg kmem_free(iov, iovsz);
222 1.1 mrg return (error);
223 1.1 mrg }
224 1.1 mrg
225 1.39 joerg static int
226 1.39 joerg copyin32_msg_control(struct lwp *l, struct msghdr *mp)
227 1.39 joerg {
228 1.39 joerg /*
229 1.39 joerg * Handle cmsg if there is any.
230 1.39 joerg */
231 1.39 joerg struct cmsghdr *cmsg, cmsg32, *cc;
232 1.39 joerg struct mbuf *ctl_mbuf;
233 1.39 joerg ssize_t resid = mp->msg_controllen;
234 1.39 joerg size_t clen, cidx = 0, cspace;
235 1.39 joerg u_int8_t *control;
236 1.39 joerg int error;
237 1.39 joerg
238 1.39 joerg ctl_mbuf = m_get(M_WAIT, MT_CONTROL);
239 1.39 joerg clen = MLEN;
240 1.39 joerg control = mtod(ctl_mbuf, void *);
241 1.39 joerg memset(control, 0, clen);
242 1.39 joerg
243 1.39 joerg cc = CMSG32_FIRSTHDR(mp);
244 1.39 joerg do {
245 1.39 joerg error = copyin(cc, &cmsg32, sizeof(cmsg32));
246 1.39 joerg if (error)
247 1.39 joerg goto failure;
248 1.39 joerg
249 1.39 joerg /*
250 1.39 joerg * Sanity check the control message length.
251 1.39 joerg */
252 1.39 joerg if (cmsg32.cmsg_len > resid ||
253 1.39 joerg cmsg32.cmsg_len < sizeof(cmsg32)) {
254 1.39 joerg error = EINVAL;
255 1.39 joerg goto failure;
256 1.39 joerg }
257 1.39 joerg
258 1.39 joerg cspace = CMSG_SPACE(cmsg32.cmsg_len - CMSG32_LEN(0));
259 1.39 joerg
260 1.39 joerg /* Check the buffer is big enough */
261 1.39 joerg if (__predict_false(cidx + cspace > clen)) {
262 1.39 joerg u_int8_t *nc;
263 1.39 joerg size_t nclen;
264 1.39 joerg
265 1.39 joerg nclen = cidx + cspace;
266 1.39 joerg if (nclen >= PAGE_SIZE) {
267 1.39 joerg error = EINVAL;
268 1.39 joerg goto failure;
269 1.39 joerg }
270 1.39 joerg nc = realloc(clen <= MLEN ? NULL : control,
271 1.39 joerg nclen, M_TEMP, M_WAITOK);
272 1.39 joerg if (!nc) {
273 1.39 joerg error = ENOMEM;
274 1.39 joerg goto failure;
275 1.39 joerg }
276 1.39 joerg if (cidx <= MLEN) {
277 1.39 joerg /* Old buffer was in mbuf... */
278 1.39 joerg memcpy(nc, control, cidx);
279 1.39 joerg memset(nc + cidx, 0, nclen - cidx);
280 1.39 joerg } else {
281 1.39 joerg memset(nc + nclen, 0, nclen - clen);
282 1.39 joerg }
283 1.39 joerg control = nc;
284 1.39 joerg clen = nclen;
285 1.39 joerg }
286 1.39 joerg
287 1.39 joerg /* Copy header */
288 1.39 joerg cmsg = (void *)&control[cidx];
289 1.39 joerg cmsg->cmsg_len = CMSG_LEN(cmsg32.cmsg_len - CMSG32_LEN(0));
290 1.39 joerg cmsg->cmsg_level = cmsg32.cmsg_level;
291 1.39 joerg cmsg->cmsg_type = cmsg32.cmsg_type;
292 1.39 joerg
293 1.39 joerg /* Copyin the data */
294 1.39 joerg error = copyin(CMSG32_DATA(cc), CMSG_DATA(cmsg),
295 1.39 joerg cmsg32.cmsg_len - CMSG32_LEN(0));
296 1.39 joerg if (error)
297 1.39 joerg goto failure;
298 1.39 joerg
299 1.39 joerg resid -= CMSG32_ALIGN(cmsg32.cmsg_len);
300 1.39 joerg cidx += cmsg->cmsg_len;
301 1.39 joerg } while ((cc = CMSG32_NXTHDR(mp, cc)) && resid > 0);
302 1.39 joerg
303 1.39 joerg /* If we allocated a buffer, attach to mbuf */
304 1.39 joerg if (cidx > MLEN) {
305 1.39 joerg MEXTADD(ctl_mbuf, control, clen, M_MBUF, NULL, NULL);
306 1.39 joerg ctl_mbuf->m_flags |= M_EXT_RW;
307 1.39 joerg }
308 1.39 joerg control = NULL;
309 1.39 joerg mp->msg_controllen = ctl_mbuf->m_len = CMSG_ALIGN(cidx);
310 1.39 joerg
311 1.39 joerg mp->msg_control = ctl_mbuf;
312 1.39 joerg mp->msg_flags |= MSG_CONTROLMBUF;
313 1.39 joerg
314 1.39 joerg ktrkuser("msgcontrol", mtod(ctl_mbuf, void *),
315 1.39 joerg mp->msg_controllen);
316 1.39 joerg
317 1.39 joerg return 0;
318 1.39 joerg
319 1.39 joerg failure:
320 1.39 joerg if (control != mtod(ctl_mbuf, void *))
321 1.39 joerg free(control, M_MBUF);
322 1.39 joerg m_free(ctl_mbuf);
323 1.39 joerg return error;
324 1.39 joerg }
325 1.39 joerg
326 1.1 mrg int
327 1.30 dsl netbsd32_sendmsg(struct lwp *l, const struct netbsd32_sendmsg_args *uap, register_t *retval)
328 1.1 mrg {
329 1.30 dsl /* {
330 1.1 mrg syscallarg(int) s;
331 1.1 mrg syscallarg(const netbsd32_msghdrp_t) msg;
332 1.1 mrg syscallarg(int) flags;
333 1.30 dsl } */
334 1.1 mrg struct msghdr msg;
335 1.1 mrg struct netbsd32_msghdr msg32;
336 1.1 mrg struct iovec aiov[UIO_SMALLIOV], *iov;
337 1.35 njoly struct netbsd32_iovec *iov32;
338 1.37 rmind size_t iovsz;
339 1.1 mrg int error;
340 1.1 mrg
341 1.24 dsl error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32));
342 1.1 mrg if (error)
343 1.1 mrg return (error);
344 1.1 mrg netbsd32_to_msghdr(&msg32, &msg);
345 1.39 joerg msg.msg_flags = 0;
346 1.39 joerg
347 1.39 joerg if (CMSG32_FIRSTHDR(&msg)) {
348 1.39 joerg error = copyin32_msg_control(l, &msg);
349 1.39 joerg if (error)
350 1.39 joerg return (error);
351 1.39 joerg } else {
352 1.39 joerg msg.msg_control = NULL;
353 1.39 joerg msg.msg_controllen = 0;
354 1.39 joerg }
355 1.26 dsl
356 1.37 rmind iovsz = msg.msg_iovlen * sizeof(struct iovec);
357 1.1 mrg if ((u_int)msg.msg_iovlen > UIO_SMALLIOV) {
358 1.1 mrg if ((u_int)msg.msg_iovlen > IOV_MAX)
359 1.1 mrg return (EMSGSIZE);
360 1.37 rmind iov = kmem_alloc(iovsz, KM_SLEEP);
361 1.36 njoly } else
362 1.1 mrg iov = aiov;
363 1.26 dsl
364 1.35 njoly iov32 = NETBSD32PTR64(msg32.msg_iov);
365 1.35 njoly error = netbsd32_to_iovecin(iov32, iov, msg.msg_iovlen);
366 1.1 mrg if (error)
367 1.1 mrg goto done;
368 1.1 mrg msg.msg_iov = iov;
369 1.26 dsl
370 1.26 dsl error = do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags), retval);
371 1.1 mrg done:
372 1.1 mrg if (iov != aiov)
373 1.37 rmind kmem_free(iov, iovsz);
374 1.1 mrg return (error);
375 1.1 mrg }
376 1.1 mrg
377 1.1 mrg int
378 1.30 dsl netbsd32_recvfrom(struct lwp *l, const struct netbsd32_recvfrom_args *uap, register_t *retval)
379 1.1 mrg {
380 1.30 dsl /* {
381 1.1 mrg syscallarg(int) s;
382 1.1 mrg syscallarg(netbsd32_voidp) buf;
383 1.1 mrg syscallarg(netbsd32_size_t) len;
384 1.1 mrg syscallarg(int) flags;
385 1.1 mrg syscallarg(netbsd32_sockaddrp_t) from;
386 1.1 mrg syscallarg(netbsd32_intp) fromlenaddr;
387 1.30 dsl } */
388 1.38 joerg struct msghdr msg;
389 1.38 joerg struct iovec aiov;
390 1.38 joerg int error;
391 1.38 joerg struct mbuf *from;
392 1.1 mrg
393 1.38 joerg msg.msg_name = NULL;
394 1.38 joerg msg.msg_iov = &aiov;
395 1.1 mrg msg.msg_iovlen = 1;
396 1.24 dsl aiov.iov_base = SCARG_P32(uap, buf);
397 1.38 joerg aiov.iov_len = SCARG(uap, len);
398 1.38 joerg msg.msg_control = NULL;
399 1.38 joerg msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS;
400 1.38 joerg
401 1.38 joerg error = do_sys_recvmsg(l, SCARG(uap, s), &msg, &from, NULL, retval);
402 1.38 joerg if (error != 0)
403 1.38 joerg return error;
404 1.38 joerg
405 1.38 joerg error = copyout_sockname(SCARG_P32(uap, from), SCARG_P32(uap, fromlenaddr),
406 1.38 joerg MSG_LENUSRSPACE, from);
407 1.38 joerg if (from != NULL)
408 1.38 joerg m_free(from);
409 1.38 joerg return error;
410 1.1 mrg }
411 1.1 mrg
412 1.1 mrg int
413 1.30 dsl netbsd32_sendto(struct lwp *l, const struct netbsd32_sendto_args *uap, register_t *retval)
414 1.1 mrg {
415 1.30 dsl /* {
416 1.1 mrg syscallarg(int) s;
417 1.1 mrg syscallarg(const netbsd32_voidp) buf;
418 1.1 mrg syscallarg(netbsd32_size_t) len;
419 1.1 mrg syscallarg(int) flags;
420 1.1 mrg syscallarg(const netbsd32_sockaddrp_t) to;
421 1.1 mrg syscallarg(int) tolen;
422 1.30 dsl } */
423 1.1 mrg struct msghdr msg;
424 1.1 mrg struct iovec aiov;
425 1.1 mrg
426 1.24 dsl msg.msg_name = SCARG_P32(uap, to); /* XXX kills const */
427 1.1 mrg msg.msg_namelen = SCARG(uap, tolen);
428 1.1 mrg msg.msg_iov = &aiov;
429 1.1 mrg msg.msg_iovlen = 1;
430 1.1 mrg msg.msg_control = 0;
431 1.24 dsl aiov.iov_base = SCARG_P32(uap, buf); /* XXX kills const */
432 1.1 mrg aiov.iov_len = SCARG(uap, len);
433 1.26 dsl msg.msg_flags = 0;
434 1.26 dsl return do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags), retval);
435 1.1 mrg }
436