xref: /freebsd/sbin/ggate/shared/ggate.c (revision 6ac5fe48541eed98a4b2caef98c617cae193dddd)
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 <arpa/inet.h>
42 #include <signal.h>
43 #include <err.h>
44 #include <errno.h>
45 #include <string.h>
46 #include <strings.h>
47 #include <libgen.h>
48 #include <netdb.h>
49 #include <syslog.h>
50 #include <stdarg.h>
51 #include <libgeom.h>
52 
53 #include <geom/gate/g_gate.h>
54 #include "ggate.h"
55 
56 
57 int g_gate_devfd = -1;
58 int g_gate_verbose = 0;
59 
60 
61 void
62 g_gate_vlog(int priority, const char *message, va_list ap)
63 {
64 
65 	if (g_gate_verbose) {
66 		const char *prefix;
67 
68 		switch (priority) {
69 		case LOG_ERR:
70 			prefix = "error";
71 			break;
72 		case LOG_WARNING:
73 			prefix = "warning";
74 			break;
75 		case LOG_NOTICE:
76 			prefix = "notice";
77 			break;
78 		case LOG_INFO:
79 			prefix = "info";
80 			break;
81 		case LOG_DEBUG:
82 			prefix = "debug";
83 			break;
84 		default:
85 			prefix = "unknown";
86 		}
87 
88 		printf("%s: ", prefix);
89 		vprintf(message, ap);
90 		printf("\n");
91 	} else {
92 		if (priority != LOG_DEBUG)
93 			vsyslog(priority, message, ap);
94 	}
95 }
96 
97 void
98 g_gate_log(int priority, const char *message, ...)
99 {
100 	va_list ap;
101 
102 	va_start(ap, message);
103 	g_gate_vlog(priority, message, ap);
104 	va_end(ap);
105 }
106 
107 void
108 g_gate_xvlog(const char *message, va_list ap)
109 {
110 
111 	g_gate_vlog(LOG_ERR, message, ap);
112 	g_gate_vlog(LOG_ERR, "Exiting.", ap);
113 	exit(EXIT_FAILURE);
114 }
115 
116 void
117 g_gate_xlog(const char *message, ...)
118 {
119 	va_list ap;
120 
121 	va_start(ap, message);
122 	g_gate_xvlog(message, ap);
123 	/* NOTREACHED */
124 	va_end(ap);
125 	exit(EXIT_FAILURE);
126 }
127 
128 off_t
129 g_gate_mediasize(int fd)
130 {
131 	off_t mediasize;
132 	struct stat sb;
133 
134 	if (fstat(fd, &sb) < 0)
135 		g_gate_xlog("fstat(): %s.", strerror(errno));
136 	if (S_ISCHR(sb.st_mode)) {
137 		if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) {
138 			g_gate_xlog("Can't get media size: %s.",
139 			    strerror(errno));
140 		}
141 	} else if (S_ISREG(sb.st_mode)) {
142 		mediasize = sb.st_size;
143 	} else {
144 		g_gate_xlog("Unsupported file system object.");
145 	}
146 	return (mediasize);
147 }
148 
149 size_t
150 g_gate_sectorsize(int fd)
151 {
152 	size_t secsize;
153 	struct stat sb;
154 
155 	if (fstat(fd, &sb) < 0)
156 		g_gate_xlog("fstat(): %s.", strerror(errno));
157 	if (S_ISCHR(sb.st_mode)) {
158 		if (ioctl(fd, DIOCGSECTORSIZE, &secsize) < 0) {
159                         g_gate_xlog("Can't get sector size: %s.",
160 			    strerror(errno));
161 		}
162 	} else if (S_ISREG(sb.st_mode)) {
163 		secsize = 512;
164 	} else {
165 		g_gate_xlog("Unsupported file system object.");
166 	}
167 	return (secsize);
168 }
169 
170 void
171 g_gate_open_device(void)
172 {
173 
174 	g_gate_devfd = open("/dev/" G_GATE_CTL_NAME, O_RDWR, 0);
175 	if (g_gate_devfd < 0)
176 		err(EXIT_FAILURE, "open(/dev/%s)", G_GATE_CTL_NAME);
177 }
178 
179 void
180 g_gate_close_device(void)
181 {
182 
183 	close(g_gate_devfd);
184 }
185 
186 void
187 g_gate_ioctl(unsigned long req, void *data)
188 {
189 
190 	if (ioctl(g_gate_devfd, req, data) < 0) {
191 		g_gate_xlog("%s: ioctl(/dev/%s): %s.", getprogname(),
192 		    G_GATE_CTL_NAME, strerror(errno));
193 	}
194 }
195 
196 void
197 g_gate_destroy(int unit, int force)
198 {
199 	struct g_gate_ctl_destroy ggio;
200 
201 	ggio.gctl_version = G_GATE_VERSION;
202 	ggio.gctl_unit = unit;
203 	ggio.gctl_force = force;
204 	g_gate_ioctl(G_GATE_CMD_DESTROY, &ggio);
205 }
206 
207 int
208 g_gate_openflags(unsigned ggflags)
209 {
210 
211 	if ((ggflags & G_GATE_FLAG_READONLY) != 0)
212 		return (O_RDONLY);
213 	else if ((ggflags & G_GATE_FLAG_WRITEONLY) != 0)
214 		return (O_WRONLY);
215 	return (O_RDWR);
216 }
217 
218 void
219 g_gate_load_module(void)
220 {
221 
222 	if (modfind("g_gate") < 0) {
223 		/* Not present in kernel, try loading it. */
224 		if (kldload("geom_gate") < 0 || modfind("g_gate") < 0) {
225 			if (errno != EEXIST) {
226 				errx(EXIT_FAILURE,
227 				    "geom_gate module not available!");
228 			}
229 		}
230 	}
231 }
232 
233 #ifdef LIBGEOM
234 static struct gclass *
235 find_class(struct gmesh *mesh, const char *name)
236 {
237 	struct gclass *class;
238 
239 	LIST_FOREACH(class, &mesh->lg_class, lg_class) {
240 		if (strcmp(class->lg_name, name) == 0)
241 			return (class);
242 	}
243 	return (NULL);
244 }
245 
246 static const char *
247 get_conf(struct ggeom *gp, const char *name)
248 {
249 	struct gconfig *conf;
250 
251 	LIST_FOREACH(conf, &gp->lg_config, lg_config) {
252 		if (strcmp(conf->lg_name, name) == 0)
253 			return (conf->lg_val);
254 	}
255 	return (NULL);
256 }
257 
258 static void
259 show_config(struct ggeom *gp, int verbose)
260 {
261 	struct gprovider *pp;
262 
263 	pp = LIST_FIRST(&gp->lg_provider);
264 	if (pp == NULL)
265 		return;
266 	if (!verbose) {
267 		printf("%s\n", pp->lg_name);
268 		return;
269 	}
270 	printf("       NAME: %s\n", pp->lg_name);
271 	printf("       info: %s\n", get_conf(gp, "info"));
272 	printf("     access: %s\n", get_conf(gp, "access"));
273 	printf("    timeout: %s\n", get_conf(gp, "timeout"));
274 	printf("queue_count: %s\n", get_conf(gp, "queue_count"));
275 	printf(" queue_size: %s\n", get_conf(gp, "queue_size"));
276 	printf(" references: %s\n", get_conf(gp, "ref"));
277 	printf("  mediasize: %jd\n", pp->lg_mediasize);
278 	printf(" sectorsize: %u\n", pp->lg_sectorsize);
279 	printf("       mode: %s\n", pp->lg_mode);
280 	printf("\n");
281 }
282 
283 void
284 g_gate_list(int unit, int verbose)
285 {
286 	struct gmesh mesh;
287 	struct gclass *class;
288 	struct ggeom *gp;
289 	char name[64];
290 	int error;
291 
292 	error = geom_gettree(&mesh);
293 	if (error != 0)
294 		exit(EXIT_FAILURE);
295 	class = find_class(&mesh, G_GATE_CLASS_NAME);
296 	if (class == NULL) {
297 		geom_deletetree(&mesh);
298 		exit(EXIT_SUCCESS);
299 	}
300 	if (unit >= 0) {
301 		snprintf(name, sizeof(name), "%s%d", G_GATE_PROVIDER_NAME,
302 		    unit);
303 	}
304 	LIST_FOREACH(gp, &class->lg_geom, lg_geom) {
305 		if (unit != -1 && strcmp(gp->lg_name, name) != 0)
306 			continue;
307 		show_config(gp, verbose);
308 	}
309 	geom_deletetree(&mesh);
310 	exit(EXIT_SUCCESS);
311 }
312 #endif	/* LIBGEOM */
313 
314 in_addr_t
315 g_gate_str2ip(const char *str)
316 {
317 	struct hostent *hp;
318 	in_addr_t ip;
319 
320 	ip = inet_addr(str);
321 	if (ip != INADDR_NONE) {
322 		/* It is a valid IP address. */
323 		return (ip);
324 	}
325 	/* Check if it is a valid host name. */
326 	hp = gethostbyname(str);
327 	if (hp == NULL)
328 		return (INADDR_NONE);
329 	return (((struct in_addr *)(hp->h_addr))->s_addr);
330 }
331