1 /*      $NetBSD: shmif_user.c,v 1.1 2014/03/13 01:42:59 pooka Exp $	*/
2 
3 /*-
4  * Copyright (c) 2009, 2010 Antti Kantee.  All Rights Reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 #ifndef _KERNEL
28 #include <sys/types.h>
29 #include <sys/mman.h>
30 
31 #include <errno.h>
32 
33 #include <rump/rumpuser_component.h>
34 
35 #include "shmif_user.h"
36 
37 #define seterr(_v_) if ((_v_) == -1) *error = errno; else *error = 0;
38 
39 /*
40  * On BSD we use kqueue, on Linux we use inotify.  The underlying
41  * interface requirements aren't quite the same, but we have a very
42  * good chance of doing the fd->path mapping on Linux thanks to dcache,
43  * so just keep the existing interfaces for now.
44  */
45 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) \
46     || defined(__OpenBSD__)
47 #include <sys/event.h>
48 
49 #include <stdlib.h>
50 
51 #include <unistd.h>
52 
53 int
rumpcomp_shmif_watchsetup(int * kqp,int fd)54 rumpcomp_shmif_watchsetup(int *kqp, int fd)
55 {
56 	struct kevent kev;
57 	int rv, kq;
58 
59 	kq = *kqp;
60 	if (kq == -1) {
61 		kq = kqueue();
62 		if (kq == -1) {
63 			rv = errno;
64 			goto out;
65 		}
66 	}
67 
68 	EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD|EV_ENABLE|EV_CLEAR,
69 	    NOTE_WRITE, 0, 0);
70 	if (kevent(kq, &kev, 1, NULL, 0, NULL) == -1) {
71 		rv = errno;
72 	} else {
73 		rv = 0;
74 		*kqp = kq;
75 	}
76 
77  out:
78 	return rumpuser_component_errtrans(rv);
79 }
80 
81 int
rumpcomp_shmif_watchwait(int kq)82 rumpcomp_shmif_watchwait(int kq)
83 {
84 	void *cookie;
85 	struct kevent kev;
86 	int rv;
87 
88 	cookie = rumpuser_component_unschedule();
89 	do {
90 		rv = kevent(kq, NULL, 0, &kev, 1, NULL);
91 	} while (rv == -1 && errno == EINTR);
92 	if (rv == -1) {
93 		rv = errno;
94 	} else {
95 		rv = 0;
96 	}
97 	rumpuser_component_schedule(cookie);
98 
99 	return rumpuser_component_errtrans(rv);
100 }
101 
102 #elif defined(__linux__)
103 #include <sys/inotify.h>
104 
105 #include <limits.h>
106 #include <stdio.h>
107 
108 int
rumpcomp_shmif_watchsetup(int * inotifyp,int fd)109 rumpcomp_shmif_watchsetup(int *inotifyp, int fd)
110 {
111 	char procbuf[PATH_MAX], linkbuf[PATH_MAX];
112 	ssize_t nn;
113 	int inotify, rv;
114 
115 	inotify = *inotifyp;
116 	if (inotify == -1) {
117 		inotify = inotify_init();
118 		if (inotify == -1) {
119 			rv = errno;
120 			goto out;
121 		}
122 	}
123 
124 	/* ok, need to map fd into path for inotify */
125 	snprintf(procbuf, sizeof(procbuf), "/proc/self/fd/%d", fd);
126 	nn = readlink(procbuf, linkbuf, sizeof(linkbuf)-1);
127 	if (nn >= (ssize_t)sizeof(linkbuf)-1) {
128 		nn = -1;
129 		errno = E2BIG; /* pick something */
130 	}
131 	if (nn == -1) {
132 		rv = errno;
133 		close(inotify);
134 		goto out;
135 	}
136 
137 	linkbuf[nn] = '\0';
138 	if (inotify_add_watch(inotify, linkbuf, IN_MODIFY) == -1) {
139 		rv = errno;
140 		close(inotify);
141 		goto out;
142 	}
143 	rv = 0;
144 	*inotifyp = inotify;
145 
146  out:
147 	return rumpuser_component_errtrans(rv);
148 }
149 
150 int
rumpcomp_shmif_watchwait(int kq)151 rumpcomp_shmif_watchwait(int kq)
152 {
153 	struct inotify_event iev;
154 	void *cookie;
155 	ssize_t nn;
156 	int rv;
157 
158 	cookie = rumpuser_component_unschedule();
159 	do {
160 		nn = read(kq, &iev, sizeof(iev));
161 	} while (nn == -1 && errno == EINTR);
162 	if (nn == -1) {
163 		rv = errno;
164 	} else {
165 		rv = 0;
166 	}
167 
168 	rumpuser_component_schedule(cookie);
169 
170 	return rumpuser_component_errtrans(rv);
171 }
172 
173 #else
174 #include <stdio.h>
175 
176 /* a polling default implementation */
177 int
rumpcomp_shmif_watchsetup(int * nono,int fd)178 rumpcomp_shmif_watchsetup(int *nono, int fd)
179 {
180 	static int warned = 0;
181 
182 	if (!warned) {
183 		fprintf(stderr, "WARNING: rumpuser writewatchfile routines are "
184 		    "polling-only on this platform\n");
185 		warned = 1;
186 	}
187 
188 	return 0;
189 }
190 
191 int
rumpcomp_shmif_watchwait(int kq)192 rumpcomp_shmif_watchwait(int kq)
193 {
194 	void *cookie;
195 
196 	cookie = rumpuser_component_unschedule();
197 	usleep(10000);
198 	rumpuser_component_schedule(cookie);
199 
200 	return 0;
201 }
202 #endif
203 
204 int
rumpcomp_shmif_mmap(int fd,size_t len,void ** memp)205 rumpcomp_shmif_mmap(int fd, size_t len, void **memp)
206 {
207 	void *mem;
208 	int rv;
209 
210 	if (ftruncate(fd, len) == -1) {
211 		rv = errno;
212 		goto out;
213 	}
214 
215 #if defined(__sun__) && !defined(MAP_FILE)
216 #define MAP_FILE 0
217 #endif
218 
219 	mem = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, 0);
220 	if (mem == MAP_FAILED) {
221 		rv = errno;
222 	} else {
223 		rv = 0;
224 		*memp = mem;
225 	}
226 
227  out:
228 	return rumpuser_component_errtrans(rv);
229 }
230 #endif
231