xref: /freebsd/sbin/ggate/shared/ggate.c (revision 15c7f46bcf28b55f91da496e1cdd0cc7f7b9e0f6)
1 /*-
2  * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <sys/param.h>
34 #include <sys/disk.h>
35 #include <sys/stat.h>
36 #include <sys/endian.h>
37 #include <sys/socket.h>
38 #include <sys/linker.h>
39 #include <sys/module.h>
40 #include <netinet/in.h>
41 #include <netinet/tcp.h>
42 #include <arpa/inet.h>
43 #include <signal.h>
44 #include <err.h>
45 #include <errno.h>
46 #include <string.h>
47 #include <strings.h>
48 #include <libgen.h>
49 #include <libutil.h>
50 #include <netdb.h>
51 #include <syslog.h>
52 #include <stdarg.h>
53 #include <stdint.h>
54 #include <libgeom.h>
55 
56 #include <geom/gate/g_gate.h>
57 #include "ggate.h"
58 
59 
60 int g_gate_devfd = -1;
61 int g_gate_verbose = 0;
62 
63 
64 void
65 g_gate_vlog(int priority, const char *message, va_list ap)
66 {
67 
68 	if (g_gate_verbose) {
69 		const char *prefix;
70 
71 		switch (priority) {
72 		case LOG_ERR:
73 			prefix = "error";
74 			break;
75 		case LOG_WARNING:
76 			prefix = "warning";
77 			break;
78 		case LOG_NOTICE:
79 			prefix = "notice";
80 			break;
81 		case LOG_INFO:
82 			prefix = "info";
83 			break;
84 		case LOG_DEBUG:
85 			prefix = "debug";
86 			break;
87 		default:
88 			prefix = "unknown";
89 		}
90 
91 		printf("%s: ", prefix);
92 		vprintf(message, ap);
93 		printf("\n");
94 	} else {
95 		if (priority != LOG_DEBUG)
96 			vsyslog(priority, message, ap);
97 	}
98 }
99 
100 void
101 g_gate_log(int priority, const char *message, ...)
102 {
103 	va_list ap;
104 
105 	va_start(ap, message);
106 	g_gate_vlog(priority, message, ap);
107 	va_end(ap);
108 }
109 
110 void
111 g_gate_xvlog(const char *message, va_list ap)
112 {
113 
114 	g_gate_vlog(LOG_ERR, message, ap);
115 	g_gate_vlog(LOG_ERR, "Exiting.", ap);
116 	exit(EXIT_FAILURE);
117 }
118 
119 void
120 g_gate_xlog(const char *message, ...)
121 {
122 	va_list ap;
123 
124 	va_start(ap, message);
125 	g_gate_xvlog(message, ap);
126 	/* NOTREACHED */
127 	va_end(ap);
128 	exit(EXIT_FAILURE);
129 }
130 
131 off_t
132 g_gate_mediasize(int fd)
133 {
134 	off_t mediasize;
135 	struct stat sb;
136 
137 	if (fstat(fd, &sb) == -1)
138 		g_gate_xlog("fstat(): %s.", strerror(errno));
139 	if (S_ISCHR(sb.st_mode)) {
140 		if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) == -1) {
141 			g_gate_xlog("Can't get media size: %s.",
142 			    strerror(errno));
143 		}
144 	} else if (S_ISREG(sb.st_mode)) {
145 		mediasize = sb.st_size;
146 	} else {
147 		g_gate_xlog("Unsupported file system object.");
148 	}
149 	return (mediasize);
150 }
151 
152 unsigned
153 g_gate_sectorsize(int fd)
154 {
155 	unsigned secsize;
156 	struct stat sb;
157 
158 	if (fstat(fd, &sb) == -1)
159 		g_gate_xlog("fstat(): %s.", strerror(errno));
160 	if (S_ISCHR(sb.st_mode)) {
161 		if (ioctl(fd, DIOCGSECTORSIZE, &secsize) == -1) {
162                         g_gate_xlog("Can't get sector size: %s.",
163 			    strerror(errno));
164 		}
165 	} else if (S_ISREG(sb.st_mode)) {
166 		secsize = 512;
167 	} else {
168 		g_gate_xlog("Unsupported file system object.");
169 	}
170 	return (secsize);
171 }
172 
173 void
174 g_gate_open_device(void)
175 {
176 
177 	g_gate_devfd = open("/dev/" G_GATE_CTL_NAME, O_RDWR, 0);
178 	if (g_gate_devfd == -1)
179 		err(EXIT_FAILURE, "open(/dev/%s)", G_GATE_CTL_NAME);
180 }
181 
182 void
183 g_gate_close_device(void)
184 {
185 
186 	close(g_gate_devfd);
187 }
188 
189 void
190 g_gate_ioctl(unsigned long req, void *data)
191 {
192 
193 	if (ioctl(g_gate_devfd, req, data) == -1) {
194 		g_gate_xlog("%s: ioctl(/dev/%s): %s.", getprogname(),
195 		    G_GATE_CTL_NAME, strerror(errno));
196 	}
197 }
198 
199 void
200 g_gate_destroy(int unit, int force)
201 {
202 	struct g_gate_ctl_destroy ggio;
203 
204 	ggio.gctl_version = G_GATE_VERSION;
205 	ggio.gctl_unit = unit;
206 	ggio.gctl_force = force;
207 	g_gate_ioctl(G_GATE_CMD_DESTROY, &ggio);
208 }
209 
210 void
211 g_gate_load_module(void)
212 {
213 
214 	if (modfind("g_gate") == -1) {
215 		/* Not present in kernel, try loading it. */
216 		if (kldload("geom_gate") == -1 || modfind("g_gate") == -1) {
217 			if (errno != EEXIST) {
218 				errx(EXIT_FAILURE,
219 				    "geom_gate module not available!");
220 			}
221 		}
222 	}
223 }
224 
225 ssize_t
226 g_gate_send(int s, const void *buf, size_t len, int flags)
227 {
228 	ssize_t done = 0, done2;
229 	const unsigned char *p = buf;
230 
231 	while (len > 0) {
232 		done2 = send(s, p, len, flags);
233 		if (done2 == 0)
234 			break;
235 		else if (done2 == -1) {
236 			if (errno == EAGAIN) {
237 				printf("%s: EAGAIN\n", __func__);
238 				continue;
239 			}
240 			done = -1;
241 			break;
242 		}
243 		done += done2;
244 		p += done2;
245 		len -= done2;
246 	}
247 	return (done);
248 }
249 
250 ssize_t
251 g_gate_recv(int s, void *buf, size_t len, int flags)
252 {
253 	ssize_t done;
254 
255 	do {
256 		done = recv(s, buf, len, flags);
257 	} while (done == -1 && errno == EAGAIN);
258 	return (done);
259 }
260 
261 int nagle = 1;
262 unsigned rcvbuf = G_GATE_RCVBUF;
263 unsigned sndbuf = G_GATE_SNDBUF;
264 
265 void
266 g_gate_socket_settings(int sfd)
267 {
268 	struct timeval tv;
269 	int bsize, on;
270 
271 	/* Socket settings. */
272 	on = 1;
273 	if (nagle) {
274 		if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &on,
275 		    sizeof(on)) == -1) {
276 			g_gate_xlog("setsockopt() error: %s.", strerror(errno));
277 		}
278 	}
279 	if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
280 		g_gate_xlog("setsockopt(SO_REUSEADDR): %s.", strerror(errno));
281 	bsize = rcvbuf;
282 	if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, &bsize, sizeof(bsize)) == -1)
283 		g_gate_xlog("setsockopt(SO_RCVBUF): %s.", strerror(errno));
284 	bsize = sndbuf;
285 	if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, &bsize, sizeof(bsize)) == -1)
286 		g_gate_xlog("setsockopt(SO_SNDBUF): %s.", strerror(errno));
287 	tv.tv_sec = 8;
288 	tv.tv_usec = 0;
289 	if (setsockopt(sfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1) {
290 		g_gate_log(LOG_ERR, "setsockopt(SO_SNDTIMEO) error: %s.",
291 		    strerror(errno));
292 	}
293 	if (setsockopt(sfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
294 		g_gate_log(LOG_ERR, "setsockopt(SO_RCVTIMEO) error: %s.",
295 		    strerror(errno));
296 	}
297 }
298 
299 #ifdef LIBGEOM
300 static struct gclass *
301 find_class(struct gmesh *mesh, const char *name)
302 {
303 	struct gclass *class;
304 
305 	LIST_FOREACH(class, &mesh->lg_class, lg_class) {
306 		if (strcmp(class->lg_name, name) == 0)
307 			return (class);
308 	}
309 	return (NULL);
310 }
311 
312 static const char *
313 get_conf(struct ggeom *gp, const char *name)
314 {
315 	struct gconfig *conf;
316 
317 	LIST_FOREACH(conf, &gp->lg_config, lg_config) {
318 		if (strcmp(conf->lg_name, name) == 0)
319 			return (conf->lg_val);
320 	}
321 	return (NULL);
322 }
323 
324 static void
325 show_config(struct ggeom *gp, int verbose)
326 {
327 	struct gprovider *pp;
328 	char buf[5];
329 
330 	pp = LIST_FIRST(&gp->lg_provider);
331 	if (pp == NULL)
332 		return;
333 	if (!verbose) {
334 		printf("%s\n", pp->lg_name);
335 		return;
336 	}
337 	printf("       NAME: %s\n", pp->lg_name);
338 	printf("       info: %s\n", get_conf(gp, "info"));
339 	printf("     access: %s\n", get_conf(gp, "access"));
340 	printf("    timeout: %s\n", get_conf(gp, "timeout"));
341 	printf("queue_count: %s\n", get_conf(gp, "queue_count"));
342 	printf(" queue_size: %s\n", get_conf(gp, "queue_size"));
343 	printf(" references: %s\n", get_conf(gp, "ref"));
344 	humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
345 	    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
346 	printf("  mediasize: %jd (%s)\n", (intmax_t)pp->lg_mediasize, buf);
347 	printf(" sectorsize: %u\n", pp->lg_sectorsize);
348 	printf("       mode: %s\n", pp->lg_mode);
349 	printf("\n");
350 }
351 
352 void
353 g_gate_list(int unit, int verbose)
354 {
355 	struct gmesh mesh;
356 	struct gclass *class;
357 	struct ggeom *gp;
358 	char name[64];
359 	int error;
360 
361 	error = geom_gettree(&mesh);
362 	if (error != 0)
363 		exit(EXIT_FAILURE);
364 	class = find_class(&mesh, G_GATE_CLASS_NAME);
365 	if (class == NULL) {
366 		geom_deletetree(&mesh);
367 		exit(EXIT_SUCCESS);
368 	}
369 	if (unit >= 0) {
370 		snprintf(name, sizeof(name), "%s%d", G_GATE_PROVIDER_NAME,
371 		    unit);
372 	}
373 	LIST_FOREACH(gp, &class->lg_geom, lg_geom) {
374 		if (unit != -1 && strcmp(gp->lg_name, name) != 0)
375 			continue;
376 		show_config(gp, verbose);
377 	}
378 	geom_deletetree(&mesh);
379 	exit(EXIT_SUCCESS);
380 }
381 #endif	/* LIBGEOM */
382 
383 in_addr_t
384 g_gate_str2ip(const char *str)
385 {
386 	struct hostent *hp;
387 	in_addr_t ip;
388 
389 	ip = inet_addr(str);
390 	if (ip != INADDR_NONE) {
391 		/* It is a valid IP address. */
392 		return (ip);
393 	}
394 	/* Check if it is a valid host name. */
395 	hp = gethostbyname(str);
396 	if (hp == NULL)
397 		return (INADDR_NONE);
398 	return (((struct in_addr *)(void *)hp->h_addr)->s_addr);
399 }
400