xref: /dflybsd-src/lib/libc/sysvipc/sockets.c (revision ff86f40163b90743b832c47e55fc6ca83aa45121)
182657471SMarkus Pfeiffer /**
282657471SMarkus Pfeiffer  * Copyright (c) 2013 Larisa Grigore.  All rights reserved.
382657471SMarkus Pfeiffer  *
482657471SMarkus Pfeiffer  * Redistribution and use in source and binary forms, with or without
582657471SMarkus Pfeiffer  * modification, are permitted provided that the following conditions
682657471SMarkus Pfeiffer  * are met:
782657471SMarkus Pfeiffer  * 1. Redistributions of source code must retain the above copyright
882657471SMarkus Pfeiffer  *    notice, this list of conditions and the following disclaimer.
982657471SMarkus Pfeiffer  * 2. Redistributions in binary form must reproduce the above copyright
1082657471SMarkus Pfeiffer  *    notice, this list of conditions and the following disclaimer in the
1182657471SMarkus Pfeiffer  *    documentation and/or other materials provided with the distribution.
1282657471SMarkus Pfeiffer  * 3. The name of the author may not be used to endorse or promote products
1382657471SMarkus Pfeiffer  *    derived from this software without specific prior written permission.
1482657471SMarkus Pfeiffer  *
1582657471SMarkus Pfeiffer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1682657471SMarkus Pfeiffer  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1782657471SMarkus Pfeiffer  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1882657471SMarkus Pfeiffer  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1982657471SMarkus Pfeiffer  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2082657471SMarkus Pfeiffer  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2182657471SMarkus Pfeiffer  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2282657471SMarkus Pfeiffer  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2382657471SMarkus Pfeiffer  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2482657471SMarkus Pfeiffer  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2582657471SMarkus Pfeiffer  */
2682657471SMarkus Pfeiffer 
2782657471SMarkus Pfeiffer #include <sys/param.h>
2882657471SMarkus Pfeiffer #include <sys/un.h>
2982657471SMarkus Pfeiffer #include <sys/uio.h>
3082657471SMarkus Pfeiffer #include <sys/types.h>
3182657471SMarkus Pfeiffer #include <sys/stat.h>
3282657471SMarkus Pfeiffer #include <err.h>
3382657471SMarkus Pfeiffer #include <errno.h>
3482657471SMarkus Pfeiffer #include <fcntl.h>
3582657471SMarkus Pfeiffer #include <signal.h>
3682657471SMarkus Pfeiffer #include <stdio.h>
3782657471SMarkus Pfeiffer #include <stdlib.h>
3882657471SMarkus Pfeiffer #include <string.h>
3982657471SMarkus Pfeiffer #include <unistd.h>
4082657471SMarkus Pfeiffer 
4182657471SMarkus Pfeiffer #include "sysvipc_utils.h"
4282657471SMarkus Pfeiffer #include "sysvipc_sockets.h"
4382657471SMarkus Pfeiffer 
4482657471SMarkus Pfeiffer #define MAX_CONN	10
4582657471SMarkus Pfeiffer 
4682657471SMarkus Pfeiffer int
init_socket(const char * sockfile)4782657471SMarkus Pfeiffer init_socket(const char *sockfile)
4882657471SMarkus Pfeiffer {
4982657471SMarkus Pfeiffer 	struct sockaddr_un un_addr;
5082657471SMarkus Pfeiffer 	int sock;
5182657471SMarkus Pfeiffer 
5282657471SMarkus Pfeiffer 	/* create server socket */
5382657471SMarkus Pfeiffer 	if ( (sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
5482657471SMarkus Pfeiffer 		sysv_print_err("init socket");
5582657471SMarkus Pfeiffer 		return (-1);
5682657471SMarkus Pfeiffer 	}
5782657471SMarkus Pfeiffer 
5882657471SMarkus Pfeiffer 	/* bind it */
5982657471SMarkus Pfeiffer 	memset(&un_addr, 0, sizeof(un_addr));
6082657471SMarkus Pfeiffer 	un_addr.sun_len = sizeof(un_addr);
6182657471SMarkus Pfeiffer 	un_addr.sun_family = AF_UNIX;
6282657471SMarkus Pfeiffer 	strcpy(un_addr.sun_path, sockfile);
6382657471SMarkus Pfeiffer 
6482657471SMarkus Pfeiffer 	unlink(un_addr.sun_path);
6582657471SMarkus Pfeiffer 
6682657471SMarkus Pfeiffer 	if (bind(sock, (struct sockaddr *)&un_addr, sizeof(un_addr)) < 0) {
6782657471SMarkus Pfeiffer 		close(sock);
6882657471SMarkus Pfeiffer 		sysv_print_err("bind");
6982657471SMarkus Pfeiffer 		return (-1);
7082657471SMarkus Pfeiffer 	}
7182657471SMarkus Pfeiffer 
7282657471SMarkus Pfeiffer 	if (listen(sock, MAX_CONN) < 0) {
7382657471SMarkus Pfeiffer 		close(sock);
7482657471SMarkus Pfeiffer 		sysv_print_err("listen");
7582657471SMarkus Pfeiffer 		return (-1);
7682657471SMarkus Pfeiffer 	}
7782657471SMarkus Pfeiffer 
7882657471SMarkus Pfeiffer 	/* turn on credentials passing */
7982657471SMarkus Pfeiffer 	return (sock);
8082657471SMarkus Pfeiffer }
8182657471SMarkus Pfeiffer 
8282657471SMarkus Pfeiffer int
handle_new_connection(int sock)8382657471SMarkus Pfeiffer handle_new_connection(int sock)
8482657471SMarkus Pfeiffer {
8582657471SMarkus Pfeiffer 	int fd, flags;
8682657471SMarkus Pfeiffer 
8782657471SMarkus Pfeiffer 	do {
8882657471SMarkus Pfeiffer 		fd = accept(sock, NULL, NULL);
8982657471SMarkus Pfeiffer 	} while (fd < 0 && errno == EINTR);
9082657471SMarkus Pfeiffer 
9182657471SMarkus Pfeiffer 	if (fd < 0) {
9282657471SMarkus Pfeiffer 		sysv_print_err("accept");
9382657471SMarkus Pfeiffer 		return (-1);
9482657471SMarkus Pfeiffer 	}
9582657471SMarkus Pfeiffer 
9682657471SMarkus Pfeiffer 	flags = fcntl(fd, F_GETFL, 0);
9782657471SMarkus Pfeiffer 	fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
9882657471SMarkus Pfeiffer 
9982657471SMarkus Pfeiffer 	return (fd);
10082657471SMarkus Pfeiffer }
10182657471SMarkus Pfeiffer 
10282657471SMarkus Pfeiffer int
connect_to_daemon(const char * sockfile)10382657471SMarkus Pfeiffer connect_to_daemon(const char *sockfile)
10482657471SMarkus Pfeiffer {
10582657471SMarkus Pfeiffer 	int sock, flags;
10682657471SMarkus Pfeiffer 	struct sockaddr_un serv_addr;
10782657471SMarkus Pfeiffer 
10882657471SMarkus Pfeiffer 	if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
10982657471SMarkus Pfeiffer 		sysv_print_err("socket(%d)\n", sock);
11082657471SMarkus Pfeiffer 		return (-1);
11182657471SMarkus Pfeiffer 	}
11282657471SMarkus Pfeiffer 
11382657471SMarkus Pfeiffer 	flags = fcntl(sock, F_GETFL, 0);
11482657471SMarkus Pfeiffer 	fcntl(sock, F_SETFL, flags & ~O_NONBLOCK);
11582657471SMarkus Pfeiffer 
11682657471SMarkus Pfeiffer 	memset(&serv_addr, 0, sizeof(serv_addr));
11782657471SMarkus Pfeiffer 	serv_addr.sun_family = AF_UNIX;
11882657471SMarkus Pfeiffer 	strcpy(serv_addr.sun_path, sockfile);
11982657471SMarkus Pfeiffer 
12082657471SMarkus Pfeiffer 	if (connect(sock, (struct sockaddr *)&serv_addr,
12182657471SMarkus Pfeiffer 				sizeof(serv_addr)) < 0) {
12282657471SMarkus Pfeiffer 		close(sock);
12382657471SMarkus Pfeiffer 		sysv_print_err("connect(%d)\n", sock);
12482657471SMarkus Pfeiffer 		return (-1);
12582657471SMarkus Pfeiffer 	}
12682657471SMarkus Pfeiffer 
12782657471SMarkus Pfeiffer 	return (sock);
12882657471SMarkus Pfeiffer }
12982657471SMarkus Pfeiffer 
13082657471SMarkus Pfeiffer int
send_fd(int sock,int fd)13182657471SMarkus Pfeiffer send_fd(int sock, int fd)
13282657471SMarkus Pfeiffer {
13382657471SMarkus Pfeiffer 	struct msghdr msg;
13482657471SMarkus Pfeiffer 	struct iovec vec;
13582657471SMarkus Pfeiffer #ifndef HAVE_ACCRIGHTS_IN_MSGHDR
13682657471SMarkus Pfeiffer 	union {
13782657471SMarkus Pfeiffer 		struct cmsghdr hdr;
13882657471SMarkus Pfeiffer 		char buf[CMSG_SPACE(sizeof(int))];
13982657471SMarkus Pfeiffer 	} cmsgbuf;
14082657471SMarkus Pfeiffer 	struct cmsghdr *cmsg;
14182657471SMarkus Pfeiffer #endif
14282657471SMarkus Pfeiffer 	int result = 0;
14382657471SMarkus Pfeiffer 	ssize_t n;
14482657471SMarkus Pfeiffer 
14582657471SMarkus Pfeiffer 	memset(&msg, 0, sizeof(msg));
14682657471SMarkus Pfeiffer 
14782657471SMarkus Pfeiffer 	if (fd < 0)
14882657471SMarkus Pfeiffer 		result = errno;
14982657471SMarkus Pfeiffer 	else {
15082657471SMarkus Pfeiffer #ifdef HAVE_ACCRIGHTS_IN_MSGHDR
15182657471SMarkus Pfeiffer 		msg.msg_accrights = (caddr_t)&fd;
15282657471SMarkus Pfeiffer 		msg.msg_accrightslen = sizeof(fd);
15382657471SMarkus Pfeiffer #else
15482657471SMarkus Pfeiffer 		msg.msg_control = (caddr_t)cmsgbuf.buf;
15582657471SMarkus Pfeiffer 		msg.msg_controllen = sizeof(cmsgbuf.buf);
15682657471SMarkus Pfeiffer 		cmsg = CMSG_FIRSTHDR(&msg);
15782657471SMarkus Pfeiffer 		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
15882657471SMarkus Pfeiffer 		cmsg->cmsg_level = SOL_SOCKET;
15982657471SMarkus Pfeiffer 		cmsg->cmsg_type = SCM_RIGHTS;
16082657471SMarkus Pfeiffer 		*(int *)CMSG_DATA(cmsg) = fd;
16182657471SMarkus Pfeiffer #endif
16282657471SMarkus Pfeiffer 	}
16382657471SMarkus Pfeiffer 
16482657471SMarkus Pfeiffer 	vec.iov_base = (caddr_t)&result;
16582657471SMarkus Pfeiffer 	vec.iov_len = sizeof(int);
16682657471SMarkus Pfeiffer 	msg.msg_iov = &vec;
16782657471SMarkus Pfeiffer 	msg.msg_iovlen = 1;
16882657471SMarkus Pfeiffer 
16982657471SMarkus Pfeiffer 	if ((n = sendmsg(sock, &msg, 0)) == -1) {
17040d436c0SSascha Wildner 		sysv_print_err("sendmsg(%d)\n", sock);
17182657471SMarkus Pfeiffer 		return (-1);
17282657471SMarkus Pfeiffer 	}
17382657471SMarkus Pfeiffer 	if (n != sizeof(int)) {
17482657471SMarkus Pfeiffer 		sysv_print_err("sendmsg: expected sent 1 got %ld\n",
17582657471SMarkus Pfeiffer 				(long)n);
17682657471SMarkus Pfeiffer 		return (-1);
17782657471SMarkus Pfeiffer 	}
17882657471SMarkus Pfeiffer 
17982657471SMarkus Pfeiffer 	return (0);
18082657471SMarkus Pfeiffer }
18182657471SMarkus Pfeiffer 
18282657471SMarkus Pfeiffer /**/
18382657471SMarkus Pfeiffer int
receive_fd(int sock)18482657471SMarkus Pfeiffer receive_fd(int sock)
18582657471SMarkus Pfeiffer {
18682657471SMarkus Pfeiffer 	struct msghdr msg;
18782657471SMarkus Pfeiffer 	struct iovec vec;
18882657471SMarkus Pfeiffer #ifndef HAVE_ACCRIGHTS_IN_MSGHDR
18982657471SMarkus Pfeiffer 	union {
19082657471SMarkus Pfeiffer 		struct cmsghdr hdr;
19182657471SMarkus Pfeiffer 		char buf[CMSG_SPACE(sizeof(int))];
19282657471SMarkus Pfeiffer 	} cmsgbuf;
19382657471SMarkus Pfeiffer 	struct cmsghdr *cmsg;
19482657471SMarkus Pfeiffer #endif
19582657471SMarkus Pfeiffer 	ssize_t n;
19682657471SMarkus Pfeiffer 	int result;
19782657471SMarkus Pfeiffer 	int fd;
19882657471SMarkus Pfeiffer 
19982657471SMarkus Pfeiffer 	memset(&msg, 0, sizeof(msg));
20082657471SMarkus Pfeiffer 	vec.iov_base = (caddr_t)&result;
20182657471SMarkus Pfeiffer 	vec.iov_len = sizeof(int);
20282657471SMarkus Pfeiffer 	msg.msg_iov = &vec;
20382657471SMarkus Pfeiffer 	msg.msg_iovlen = 1;
20482657471SMarkus Pfeiffer 
20582657471SMarkus Pfeiffer #ifdef HAVE_ACCRIGHTS_IN_MSGHDR
20682657471SMarkus Pfeiffer 	msg.msg_accrights = (caddr_t)&fd;
20782657471SMarkus Pfeiffer 	msg.msg_accrightslen = sizeof(fd);
20882657471SMarkus Pfeiffer #else
20982657471SMarkus Pfeiffer 	msg.msg_control = &cmsgbuf.buf;
21082657471SMarkus Pfeiffer 	msg.msg_controllen = sizeof(cmsgbuf.buf);
21182657471SMarkus Pfeiffer #endif
21282657471SMarkus Pfeiffer 
21382657471SMarkus Pfeiffer 	if ((n = recvmsg(sock, &msg, 0)) == -1)
21482657471SMarkus Pfeiffer 		sysv_print_err("recvmsg\n");
21582657471SMarkus Pfeiffer 	if (n != sizeof(int)) {
21682657471SMarkus Pfeiffer 		sysv_print_err("recvmsg: expected received 1 got %ld\n",
21782657471SMarkus Pfeiffer 				(long)n);
21882657471SMarkus Pfeiffer 	}
21982657471SMarkus Pfeiffer 	if (result == 0) {
22082657471SMarkus Pfeiffer 		cmsg = CMSG_FIRSTHDR(&msg);
22182657471SMarkus Pfeiffer 		if (cmsg == NULL) {
22282657471SMarkus Pfeiffer 			sysv_print_err("no message header\n");
22382657471SMarkus Pfeiffer 			return (-1);
22482657471SMarkus Pfeiffer 		}
22582657471SMarkus Pfeiffer 		if (cmsg->cmsg_type != SCM_RIGHTS)
22682657471SMarkus Pfeiffer 			sysv_print_err("expected type %d got %d\n",
22782657471SMarkus Pfeiffer 					SCM_RIGHTS, cmsg->cmsg_type);
22882657471SMarkus Pfeiffer 
22982657471SMarkus Pfeiffer 		fd = (*(int *)CMSG_DATA(cmsg));
23082657471SMarkus Pfeiffer 		return (fd);
23182657471SMarkus Pfeiffer 	} else {
23282657471SMarkus Pfeiffer 		errno = result;
23382657471SMarkus Pfeiffer 		return (-1);
23482657471SMarkus Pfeiffer 	}
23582657471SMarkus Pfeiffer }
23682657471SMarkus Pfeiffer 
23782657471SMarkus Pfeiffer static void
close_fds(int * fds,int num_fds)238*ff86f401SSascha Wildner close_fds(int *fds, int num_fds)
239*ff86f401SSascha Wildner {
24082657471SMarkus Pfeiffer 	int i;
24182657471SMarkus Pfeiffer 
24282657471SMarkus Pfeiffer 	for (i=0; i < num_fds; i++)
24382657471SMarkus Pfeiffer 		close(fds[i]);
24482657471SMarkus Pfeiffer }
24582657471SMarkus Pfeiffer 
24682657471SMarkus Pfeiffer /* Send with the message, credentials too. */
24782657471SMarkus Pfeiffer int
send_msg_with_cred(int sock,char * buffer,size_t size)248*ff86f401SSascha Wildner send_msg_with_cred(int sock, char *buffer, size_t size)
249*ff86f401SSascha Wildner {
25082657471SMarkus Pfeiffer 	struct msghdr msg;
25182657471SMarkus Pfeiffer 	struct iovec vec;
25282657471SMarkus Pfeiffer 	ssize_t n;
25382657471SMarkus Pfeiffer 
25482657471SMarkus Pfeiffer 	struct {
25582657471SMarkus Pfeiffer 		struct cmsghdr hdr;
25682657471SMarkus Pfeiffer 		char cred[CMSG_SPACE(sizeof(struct cmsgcred))];
25782657471SMarkus Pfeiffer 	} cmsg;
25882657471SMarkus Pfeiffer 
25982657471SMarkus Pfeiffer 	memset(&cmsg, 0, sizeof(cmsg));
26082657471SMarkus Pfeiffer 	cmsg.hdr.cmsg_len =  CMSG_LEN(sizeof(struct cmsgcred));
26182657471SMarkus Pfeiffer 	cmsg.hdr.cmsg_level = SOL_SOCKET;
26282657471SMarkus Pfeiffer 	cmsg.hdr.cmsg_type = SCM_CREDS;
26382657471SMarkus Pfeiffer 
26482657471SMarkus Pfeiffer 	memset(&msg, 0, sizeof(struct msghdr));
26582657471SMarkus Pfeiffer 	msg.msg_iov = &vec;
26682657471SMarkus Pfeiffer 	msg.msg_iovlen = 1;
26782657471SMarkus Pfeiffer 	msg.msg_control = (caddr_t)&cmsg;
26882657471SMarkus Pfeiffer 	msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
26982657471SMarkus Pfeiffer 
27082657471SMarkus Pfeiffer 	vec.iov_base = buffer;
27182657471SMarkus Pfeiffer 	vec.iov_len = size;
27282657471SMarkus Pfeiffer 
27382657471SMarkus Pfeiffer 	if ((n = sendmsg(sock, &msg, 0)) == -1) {
27482657471SMarkus Pfeiffer 		sysv_print_err("sendmsg on fd %d\n", sock);
27582657471SMarkus Pfeiffer 		return (-1);
27682657471SMarkus Pfeiffer 	}
27782657471SMarkus Pfeiffer 
27882657471SMarkus Pfeiffer 	return (0);
27982657471SMarkus Pfeiffer }
28082657471SMarkus Pfeiffer 
28182657471SMarkus Pfeiffer /* Receive a message and the credentials of the sender. */
28282657471SMarkus Pfeiffer int
receive_msg_with_cred(int sock,char * buffer,size_t size,struct cmsgcred * cred)28382657471SMarkus Pfeiffer receive_msg_with_cred(int sock, char *buffer, size_t size,
284*ff86f401SSascha Wildner     struct cmsgcred *cred)
285*ff86f401SSascha Wildner {
286381fa6daSSascha Wildner 	struct msghdr msg = { .msg_name = NULL };
28782657471SMarkus Pfeiffer 	struct iovec vec;
28882657471SMarkus Pfeiffer 	ssize_t n;
28982657471SMarkus Pfeiffer 	int result;
29082657471SMarkus Pfeiffer 	struct cmsghdr *cmp;
29182657471SMarkus Pfeiffer 	struct {
29282657471SMarkus Pfeiffer 		struct cmsghdr hdr;
29382657471SMarkus Pfeiffer 		char cred[CMSG_SPACE(sizeof(struct cmsgcred))];
29482657471SMarkus Pfeiffer 	} cmsg;
29582657471SMarkus Pfeiffer 
29682657471SMarkus Pfeiffer 	memset(&msg, 0, sizeof(msg));
29782657471SMarkus Pfeiffer 	vec.iov_base = buffer;
29882657471SMarkus Pfeiffer 	vec.iov_len = size;
29982657471SMarkus Pfeiffer 	msg.msg_iov = &vec;
30082657471SMarkus Pfeiffer 	msg.msg_iovlen = 1;
30182657471SMarkus Pfeiffer 
30282657471SMarkus Pfeiffer 	msg.msg_control = &cmsg;
30382657471SMarkus Pfeiffer 	msg.msg_controllen = sizeof(cmsg);
30482657471SMarkus Pfeiffer 
30582657471SMarkus Pfeiffer 	do {
30682657471SMarkus Pfeiffer 		n = recvmsg(sock, &msg, 0);
30782657471SMarkus Pfeiffer 	} while (n < 0 && errno == EINTR);
30882657471SMarkus Pfeiffer 
30982657471SMarkus Pfeiffer 	if (n < 0) {
31082657471SMarkus Pfeiffer 		sysv_print_err("recvmsg on fd %d\n", sock);
31182657471SMarkus Pfeiffer 		return (-1);
31282657471SMarkus Pfeiffer 	}
31382657471SMarkus Pfeiffer 
31482657471SMarkus Pfeiffer 	if (n == 0) {
31582657471SMarkus Pfeiffer 		return (-1);
31682657471SMarkus Pfeiffer 	}
31782657471SMarkus Pfeiffer 
31882657471SMarkus Pfeiffer 	result = -1;
31982657471SMarkus Pfeiffer 	cmp = CMSG_FIRSTHDR(&msg);
32082657471SMarkus Pfeiffer 
32182657471SMarkus Pfeiffer 	while(cmp != NULL) {
32282657471SMarkus Pfeiffer 		if (cmp->cmsg_level == SOL_SOCKET
32382657471SMarkus Pfeiffer 				&& cmp->cmsg_type  == SCM_CREDS) {
32482657471SMarkus Pfeiffer 			if (cred)
32582657471SMarkus Pfeiffer 				memcpy(cred, CMSG_DATA(cmp), sizeof(*cred));
32682657471SMarkus Pfeiffer 			result = n;
32782657471SMarkus Pfeiffer 		} else if (cmp->cmsg_level == SOL_SOCKET
32882657471SMarkus Pfeiffer 				&& cmp->cmsg_type  == SCM_RIGHTS) {
32982657471SMarkus Pfeiffer 			close_fds((int *) CMSG_DATA(cmp),
33082657471SMarkus Pfeiffer 					(cmp->cmsg_len - CMSG_LEN(0))
33182657471SMarkus Pfeiffer 					/ sizeof(int));
33282657471SMarkus Pfeiffer 		}
33382657471SMarkus Pfeiffer 		cmp = CMSG_NXTHDR(&msg, cmp);
33482657471SMarkus Pfeiffer 	}
33582657471SMarkus Pfeiffer 
33682657471SMarkus Pfeiffer 	return (result);
33782657471SMarkus Pfeiffer }
338