1128765Spjd/*-
2128765Spjd * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3128765Spjd * All rights reserved.
4128765Spjd *
5128765Spjd * Redistribution and use in source and binary forms, with or without
6128765Spjd * modification, are permitted provided that the following conditions
7128765Spjd * are met:
8128765Spjd * 1. Redistributions of source code must retain the above copyright
9128765Spjd *    notice, this list of conditions and the following disclaimer.
10128765Spjd * 2. Redistributions in binary form must reproduce the above copyright
11128765Spjd *    notice, this list of conditions and the following disclaimer in the
12128765Spjd *    documentation and/or other materials provided with the distribution.
13128765Spjd *
14128765Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15128765Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16128765Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17128765Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18128765Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19128765Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20128765Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21128765Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22128765Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23128765Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24128765Spjd * SUCH DAMAGE.
25128765Spjd *
26128765Spjd * $FreeBSD$
27128765Spjd */
28128765Spjd
29128765Spjd#include <stdio.h>
30128765Spjd#include <stdlib.h>
31128765Spjd#include <stdint.h>
32128765Spjd#include <fcntl.h>
33128765Spjd#include <unistd.h>
34128765Spjd#include <string.h>
35128765Spjd#include <ctype.h>
36128765Spjd#include <libgen.h>
37147844Spjd#include <pthread.h>
38147844Spjd#include <signal.h>
39128765Spjd#include <err.h>
40128765Spjd#include <errno.h>
41147844Spjd#include <assert.h>
42147844Spjd
43128765Spjd#include <sys/param.h>
44128765Spjd#include <sys/ioctl.h>
45128765Spjd#include <sys/socket.h>
46128765Spjd#include <sys/sysctl.h>
47128765Spjd#include <sys/syslog.h>
48128765Spjd#include <sys/time.h>
49128765Spjd#include <sys/bio.h>
50128765Spjd#include <netinet/in.h>
51128765Spjd#include <netinet/tcp.h>
52128765Spjd#include <arpa/inet.h>
53128765Spjd
54128765Spjd#include <geom/gate/g_gate.h>
55128765Spjd#include "ggate.h"
56128765Spjd
57128765Spjd
58241720Sedstatic enum { UNSET, CREATE, DESTROY, LIST, RESCUE } action = UNSET;
59128765Spjd
60128765Spjdstatic const char *path = NULL;
61128765Spjdstatic const char *host = NULL;
62204076Spjdstatic int unit = G_GATE_UNIT_AUTO;
63128765Spjdstatic unsigned flags = 0;
64128765Spjdstatic int force = 0;
65128765Spjdstatic unsigned queue_size = G_GATE_QUEUE_SIZE;
66128765Spjdstatic unsigned port = G_GATE_PORT;
67128765Spjdstatic off_t mediasize;
68128765Spjdstatic unsigned sectorsize = 0;
69128765Spjdstatic unsigned timeout = G_GATE_TIMEOUT;
70147844Spjdstatic int sendfd, recvfd;
71147844Spjdstatic uint32_t token;
72147844Spjdstatic pthread_t sendtd, recvtd;
73147844Spjdstatic int reconnect;
74128765Spjd
75128765Spjdstatic void
76128765Spjdusage(void)
77128765Spjd{
78128765Spjd
79128765Spjd	fprintf(stderr, "usage: %s create [-nv] [-o <ro|wo|rw>] [-p port] "
80128765Spjd	    "[-q queue_size] [-R rcvbuf] [-S sndbuf] [-s sectorsize] "
81128765Spjd	    "[-t timeout] [-u unit] <host> <path>\n", getprogname());
82147844Spjd	fprintf(stderr, "       %s rescue [-nv] [-o <ro|wo|rw>] [-p port] "
83128765Spjd	    "[-R rcvbuf] [-S sndbuf] <-u unit> <host> <path>\n", getprogname());
84128765Spjd	fprintf(stderr, "       %s destroy [-f] <-u unit>\n", getprogname());
85128765Spjd	fprintf(stderr, "       %s list [-v] [-u unit]\n", getprogname());
86128765Spjd	exit(EXIT_FAILURE);
87128765Spjd}
88128765Spjd
89147844Spjdstatic void *
90147844Spjdsend_thread(void *arg __unused)
91128765Spjd{
92128765Spjd	struct g_gate_ctl_io ggio;
93147844Spjd	struct g_gate_hdr hdr;
94147844Spjd	char buf[MAXPHYS];
95147844Spjd	ssize_t data;
96147844Spjd	int error;
97128765Spjd
98147844Spjd	g_gate_log(LOG_NOTICE, "%s: started!", __func__);
99128765Spjd
100128765Spjd	ggio.gctl_version = G_GATE_VERSION;
101128765Spjd	ggio.gctl_unit = unit;
102147844Spjd	ggio.gctl_data = buf;
103147844Spjd
104128765Spjd	for (;;) {
105147844Spjd		ggio.gctl_length = sizeof(buf);
106128765Spjd		ggio.gctl_error = 0;
107128765Spjd		g_gate_ioctl(G_GATE_CMD_START, &ggio);
108128765Spjd		error = ggio.gctl_error;
109128765Spjd		switch (error) {
110128765Spjd		case 0:
111128765Spjd			break;
112128765Spjd		case ECANCELED:
113147844Spjd			if (reconnect)
114147844Spjd				break;
115128765Spjd			/* Exit gracefully. */
116128765Spjd			g_gate_close_device();
117128765Spjd			exit(EXIT_SUCCESS);
118147844Spjd#if 0
119128765Spjd		case ENOMEM:
120128765Spjd			/* Buffer too small. */
121128765Spjd			ggio.gctl_data = realloc(ggio.gctl_data,
122128765Spjd			    ggio.gctl_length);
123128765Spjd			if (ggio.gctl_data != NULL) {
124128765Spjd				bsize = ggio.gctl_length;
125128765Spjd				goto once_again;
126128765Spjd			}
127128765Spjd			/* FALLTHROUGH */
128147844Spjd#endif
129128765Spjd		case ENXIO:
130128765Spjd		default:
131128765Spjd			g_gate_xlog("ioctl(/dev/%s): %s.", G_GATE_CTL_NAME,
132128765Spjd			    strerror(error));
133128765Spjd		}
134128765Spjd
135147844Spjd		if (reconnect)
136147844Spjd			break;
137147844Spjd
138147844Spjd		switch (ggio.gctl_cmd) {
139147844Spjd		case BIO_READ:
140147844Spjd			hdr.gh_cmd = GGATE_CMD_READ;
141147844Spjd			break;
142147844Spjd		case BIO_WRITE:
143147844Spjd			hdr.gh_cmd = GGATE_CMD_WRITE;
144147844Spjd			break;
145147844Spjd		}
146147844Spjd		hdr.gh_seq = ggio.gctl_seq;
147128765Spjd		hdr.gh_offset = ggio.gctl_offset;
148128765Spjd		hdr.gh_length = ggio.gctl_length;
149128765Spjd		hdr.gh_error = 0;
150128765Spjd		g_gate_swap2n_hdr(&hdr);
151147844Spjd
152147844Spjd		data = g_gate_send(sendfd, &hdr, sizeof(hdr), MSG_NOSIGNAL);
153128765Spjd		g_gate_log(LOG_DEBUG, "Sent hdr packet.");
154128765Spjd		g_gate_swap2h_hdr(&hdr);
155147844Spjd		if (reconnect)
156147844Spjd			break;
157128765Spjd		if (data != sizeof(hdr)) {
158147844Spjd			g_gate_log(LOG_ERR, "Lost connection 1.");
159147844Spjd			reconnect = 1;
160147844Spjd			pthread_kill(recvtd, SIGUSR1);
161147844Spjd			break;
162128765Spjd		}
163147844Spjd
164147844Spjd		if (hdr.gh_cmd == GGATE_CMD_WRITE) {
165147844Spjd			data = g_gate_send(sendfd, ggio.gctl_data,
166147844Spjd			    ggio.gctl_length, MSG_NOSIGNAL);
167147844Spjd			if (reconnect)
168147844Spjd				break;
169128765Spjd			if (data != ggio.gctl_length) {
170147844Spjd				g_gate_log(LOG_ERR, "Lost connection 2 (%zd != %zd).", data, (ssize_t)ggio.gctl_length);
171147844Spjd				reconnect = 1;
172147844Spjd				pthread_kill(recvtd, SIGUSR1);
173147844Spjd				break;
174128765Spjd			}
175147844Spjd			g_gate_log(LOG_DEBUG, "Sent %zd bytes (offset=%llu, "
176128765Spjd			    "size=%u).", data, hdr.gh_offset, hdr.gh_length);
177128765Spjd		}
178147844Spjd	}
179147844Spjd	g_gate_log(LOG_DEBUG, "%s: Died.", __func__);
180147844Spjd	return (NULL);
181147844Spjd}
182147844Spjd
183147844Spjdstatic void *
184147844Spjdrecv_thread(void *arg __unused)
185147844Spjd{
186147844Spjd	struct g_gate_ctl_io ggio;
187147844Spjd	struct g_gate_hdr hdr;
188147844Spjd	char buf[MAXPHYS];
189147844Spjd	ssize_t data;
190147844Spjd
191147844Spjd	g_gate_log(LOG_NOTICE, "%s: started!", __func__);
192147844Spjd
193147844Spjd	ggio.gctl_version = G_GATE_VERSION;
194147844Spjd	ggio.gctl_unit = unit;
195147844Spjd	ggio.gctl_data = buf;
196147844Spjd
197147844Spjd	for (;;) {
198147844Spjd		data = g_gate_recv(recvfd, &hdr, sizeof(hdr), MSG_WAITALL);
199147844Spjd		if (reconnect)
200147844Spjd			break;
201128765Spjd		g_gate_swap2h_hdr(&hdr);
202128765Spjd		if (data != sizeof(hdr)) {
203147844Spjd			if (data == -1 && errno == EAGAIN)
204147844Spjd				continue;
205147844Spjd			g_gate_log(LOG_ERR, "Lost connection 3.");
206147844Spjd			reconnect = 1;
207147844Spjd			pthread_kill(sendtd, SIGUSR1);
208147844Spjd			break;
209128765Spjd		}
210147844Spjd		g_gate_log(LOG_DEBUG, "Received hdr packet.");
211147844Spjd
212147844Spjd		ggio.gctl_seq = hdr.gh_seq;
213147844Spjd		ggio.gctl_cmd = hdr.gh_cmd;
214147844Spjd		ggio.gctl_offset = hdr.gh_offset;
215147844Spjd		ggio.gctl_length = hdr.gh_length;
216147844Spjd		ggio.gctl_error = hdr.gh_error;
217147844Spjd
218147844Spjd		if (ggio.gctl_error == 0 && ggio.gctl_cmd == GGATE_CMD_READ) {
219147844Spjd			data = g_gate_recv(recvfd, ggio.gctl_data,
220147844Spjd			    ggio.gctl_length, MSG_WAITALL);
221147844Spjd			if (reconnect)
222147844Spjd				break;
223128765Spjd			g_gate_log(LOG_DEBUG, "Received data packet.");
224128765Spjd			if (data != ggio.gctl_length) {
225147844Spjd				g_gate_log(LOG_ERR, "Lost connection 4.");
226147844Spjd				reconnect = 1;
227147844Spjd				pthread_kill(sendtd, SIGUSR1);
228147844Spjd				break;
229128765Spjd			}
230128765Spjd			g_gate_log(LOG_DEBUG, "Received %d bytes (offset=%ju, "
231128765Spjd			    "size=%zu).", data, (uintmax_t)hdr.gh_offset,
232128765Spjd			    (size_t)hdr.gh_length);
233128765Spjd		}
234147844Spjd
235128765Spjd		g_gate_ioctl(G_GATE_CMD_DONE, &ggio);
236128765Spjd	}
237147844Spjd	g_gate_log(LOG_DEBUG, "%s: Died.", __func__);
238147844Spjd	pthread_exit(NULL);
239128765Spjd}
240128765Spjd
241147844Spjdstatic int
242147844Spjdhandshake(int dir)
243128765Spjd{
244147844Spjd	struct g_gate_version ver;
245147844Spjd	struct g_gate_cinit cinit;
246147844Spjd	struct g_gate_sinit sinit;
247147844Spjd	struct sockaddr_in serv;
248147844Spjd	int sfd;
249128765Spjd
250147844Spjd	/*
251147844Spjd	 * Do the network stuff.
252147844Spjd	 */
253147844Spjd	bzero(&serv, sizeof(serv));
254147844Spjd	serv.sin_family = AF_INET;
255147844Spjd	serv.sin_addr.s_addr = g_gate_str2ip(host);
256147844Spjd	if (serv.sin_addr.s_addr == INADDR_NONE) {
257147844Spjd		g_gate_log(LOG_DEBUG, "Invalid IP/host name: %s.", host);
258147844Spjd		return (-1);
259147844Spjd	}
260147844Spjd	serv.sin_port = htons(port);
261147844Spjd	sfd = socket(AF_INET, SOCK_STREAM, 0);
262147844Spjd	if (sfd == -1) {
263147844Spjd		g_gate_log(LOG_DEBUG, "Cannot open socket: %s.",
264147844Spjd		    strerror(errno));
265147844Spjd		return (-1);
266147844Spjd	}
267128765Spjd
268147844Spjd	g_gate_socket_settings(sfd);
269147844Spjd
270147844Spjd	if (connect(sfd, (struct sockaddr *)&serv, sizeof(serv)) == -1) {
271147844Spjd		g_gate_log(LOG_DEBUG, "Cannot connect to server: %s.",
272147844Spjd		    strerror(errno));
273128882Spjd		close(sfd);
274147844Spjd		return (-1);
275128765Spjd	}
276147844Spjd
277147844Spjd	g_gate_log(LOG_INFO, "Connected to the server: %s:%d.", host, port);
278147844Spjd
279147844Spjd	/*
280147844Spjd	 * Create and send version packet.
281147844Spjd	 */
282147844Spjd	g_gate_log(LOG_DEBUG, "Sending version packet.");
283147844Spjd	assert(strlen(GGATE_MAGIC) == sizeof(ver.gv_magic));
284147844Spjd	bcopy(GGATE_MAGIC, ver.gv_magic, sizeof(ver.gv_magic));
285147844Spjd	ver.gv_version = GGATE_VERSION;
286147844Spjd	ver.gv_error = 0;
287147844Spjd	g_gate_swap2n_version(&ver);
288147844Spjd	if (g_gate_send(sfd, &ver, sizeof(ver), MSG_NOSIGNAL) == -1) {
289147844Spjd		g_gate_log(LOG_DEBUG, "Error while sending version packet: %s.",
290147844Spjd		    strerror(errno));
291147844Spjd		close(sfd);
292147844Spjd		return (-1);
293147844Spjd	}
294147844Spjd	bzero(&ver, sizeof(ver));
295147844Spjd	if (g_gate_recv(sfd, &ver, sizeof(ver), MSG_WAITALL) == -1) {
296147844Spjd		g_gate_log(LOG_DEBUG, "Error while receiving data: %s.",
297147844Spjd		    strerror(errno));
298147844Spjd		close(sfd);
299147844Spjd		return (-1);
300147844Spjd	}
301147844Spjd	if (ver.gv_error != 0) {
302147844Spjd		g_gate_log(LOG_DEBUG, "Version verification problem: %s.",
303147844Spjd		    strerror(errno));
304147844Spjd		close(sfd);
305147844Spjd		return (-1);
306147844Spjd	}
307147844Spjd
308147844Spjd	/*
309147844Spjd	 * Create and send initial packet.
310147844Spjd	 */
311147844Spjd	g_gate_log(LOG_DEBUG, "Sending initial packet.");
312147844Spjd	if (strlcpy(cinit.gc_path, path, sizeof(cinit.gc_path)) >=
313147844Spjd	    sizeof(cinit.gc_path)) {
314147844Spjd		g_gate_log(LOG_DEBUG, "Path name too long.");
315147844Spjd		close(sfd);
316147844Spjd		return (-1);
317147844Spjd	}
318147844Spjd	cinit.gc_flags = flags | dir;
319147844Spjd	cinit.gc_token = token;
320147844Spjd	cinit.gc_nconn = 2;
321147844Spjd	g_gate_swap2n_cinit(&cinit);
322147844Spjd	if (g_gate_send(sfd, &cinit, sizeof(cinit), MSG_NOSIGNAL) == -1) {
323147844Spjd	        g_gate_log(LOG_DEBUG, "Error while sending initial packet: %s.",
324147844Spjd		    strerror(errno));
325147844Spjd		close(sfd);
326147844Spjd		return (-1);
327147844Spjd	}
328147844Spjd	g_gate_swap2h_cinit(&cinit);
329147844Spjd
330147844Spjd	/*
331147844Spjd	 * Receiving initial packet from server.
332147844Spjd	 */
333147844Spjd	g_gate_log(LOG_DEBUG, "Receiving initial packet.");
334147844Spjd	if (g_gate_recv(sfd, &sinit, sizeof(sinit), MSG_WAITALL) == -1) {
335147844Spjd		g_gate_log(LOG_DEBUG, "Error while receiving data: %s.",
336147844Spjd		    strerror(errno));
337147844Spjd		close(sfd);
338147844Spjd		return (-1);
339147844Spjd	}
340147844Spjd	g_gate_swap2h_sinit(&sinit);
341147844Spjd	if (sinit.gs_error != 0) {
342147844Spjd	        g_gate_log(LOG_DEBUG, "Error from server: %s.",
343147844Spjd		    strerror(sinit.gs_error));
344147844Spjd		close(sfd);
345147844Spjd		return (-1);
346147844Spjd	}
347147844Spjd	g_gate_log(LOG_DEBUG, "Received initial packet.");
348147844Spjd
349147844Spjd	mediasize = sinit.gs_mediasize;
350147844Spjd	if (sectorsize == 0)
351147844Spjd		sectorsize = sinit.gs_sectorsize;
352147844Spjd
353147844Spjd	return (sfd);
354128765Spjd}
355128765Spjd
356128765Spjdstatic void
357128765Spjdmydaemon(void)
358128765Spjd{
359128765Spjd
360128765Spjd	if (g_gate_verbose > 0)
361128765Spjd		return;
362128765Spjd	if (daemon(0, 0) == 0)
363128765Spjd		return;
364128765Spjd	if (action == CREATE)
365128765Spjd		g_gate_destroy(unit, 1);
366128765Spjd	err(EXIT_FAILURE, "Cannot daemonize");
367128765Spjd}
368128765Spjd
369147844Spjdstatic int
370147844Spjdg_gatec_connect(void)
371147844Spjd{
372147844Spjd
373147844Spjd	token = arc4random();
374147844Spjd	/*
375147844Spjd	 * Our receive descriptor is connected to the send descriptor on the
376147844Spjd	 * server side.
377147844Spjd	 */
378147844Spjd	recvfd = handshake(GGATE_FLAG_SEND);
379147844Spjd	if (recvfd == -1)
380147844Spjd		return (0);
381147844Spjd	/*
382147844Spjd	 * Our send descriptor is connected to the receive descriptor on the
383147844Spjd	 * server side.
384147844Spjd	 */
385147844Spjd	sendfd = handshake(GGATE_FLAG_RECV);
386147844Spjd	if (sendfd == -1)
387147844Spjd		return (0);
388147844Spjd	return (1);
389147844Spjd}
390147844Spjd
391128765Spjdstatic void
392147844Spjdg_gatec_start(void)
393128765Spjd{
394147844Spjd	int error;
395128765Spjd
396147844Spjd	reconnect = 0;
397147844Spjd	error = pthread_create(&recvtd, NULL, recv_thread, NULL);
398147844Spjd	if (error != 0) {
399147844Spjd		g_gate_destroy(unit, 1);
400147844Spjd		g_gate_xlog("pthread_create(recv_thread): %s.",
401147844Spjd		    strerror(error));
402147844Spjd	}
403147844Spjd	sendtd = pthread_self();
404147844Spjd	send_thread(NULL);
405147844Spjd	/* Disconnected. */
406147844Spjd	close(sendfd);
407147844Spjd	close(recvfd);
408128765Spjd}
409128765Spjd
410128765Spjdstatic void
411147844Spjdsignop(int sig __unused)
412147844Spjd{
413147844Spjd
414147844Spjd	/* Do nothing. */
415147844Spjd}
416147844Spjd
417147844Spjdstatic void
418147844Spjdg_gatec_loop(void)
419147844Spjd{
420147844Spjd	struct g_gate_ctl_cancel ggioc;
421147844Spjd
422147844Spjd	signal(SIGUSR1, signop);
423147844Spjd	for (;;) {
424147844Spjd		g_gatec_start();
425147844Spjd		g_gate_log(LOG_NOTICE, "Disconnected [%s %s]. Connecting...",
426147844Spjd		    host, path);
427147844Spjd		while (!g_gatec_connect()) {
428147844Spjd			sleep(2);
429147844Spjd			g_gate_log(LOG_NOTICE, "Connecting [%s %s]...", host,
430147844Spjd			    path);
431147844Spjd		}
432147844Spjd		ggioc.gctl_version = G_GATE_VERSION;
433147844Spjd		ggioc.gctl_unit = unit;
434147844Spjd		ggioc.gctl_seq = 0;
435147844Spjd		g_gate_ioctl(G_GATE_CMD_CANCEL, &ggioc);
436147844Spjd	}
437147844Spjd}
438147844Spjd
439147844Spjdstatic void
440128765Spjdg_gatec_create(void)
441128765Spjd{
442128765Spjd	struct g_gate_ctl_create ggioc;
443128765Spjd
444147844Spjd	if (!g_gatec_connect())
445147844Spjd		g_gate_xlog("Cannot connect: %s.", strerror(errno));
446147844Spjd
447147844Spjd	/*
448147844Spjd	 * Ok, got both sockets, time to create provider.
449147844Spjd	 */
450285748Sbrueffer	memset(&ggioc, 0, sizeof(ggioc));
451128765Spjd	ggioc.gctl_version = G_GATE_VERSION;
452128765Spjd	ggioc.gctl_mediasize = mediasize;
453128765Spjd	ggioc.gctl_sectorsize = sectorsize;
454128765Spjd	ggioc.gctl_flags = flags;
455128765Spjd	ggioc.gctl_maxcount = queue_size;
456128765Spjd	ggioc.gctl_timeout = timeout;
457128765Spjd	ggioc.gctl_unit = unit;
458128765Spjd	snprintf(ggioc.gctl_info, sizeof(ggioc.gctl_info), "%s:%u %s", host,
459128765Spjd	    port, path);
460128765Spjd	g_gate_ioctl(G_GATE_CMD_CREATE, &ggioc);
461156590Spjd	if (unit == -1) {
462128765Spjd		printf("%s%u\n", G_GATE_PROVIDER_NAME, ggioc.gctl_unit);
463156590Spjd		fflush(stdout);
464156590Spjd	}
465128765Spjd	unit = ggioc.gctl_unit;
466147844Spjd
467128765Spjd	mydaemon();
468147844Spjd	g_gatec_loop();
469128765Spjd}
470128765Spjd
471147844Spjdstatic void
472147844Spjdg_gatec_rescue(void)
473147844Spjd{
474147844Spjd	struct g_gate_ctl_cancel ggioc;
475147844Spjd
476147844Spjd	if (!g_gatec_connect())
477147844Spjd		g_gate_xlog("Cannot connect: %s.", strerror(errno));
478147844Spjd
479147844Spjd	ggioc.gctl_version = G_GATE_VERSION;
480147844Spjd	ggioc.gctl_unit = unit;
481147844Spjd	ggioc.gctl_seq = 0;
482147844Spjd	g_gate_ioctl(G_GATE_CMD_CANCEL, &ggioc);
483147844Spjd
484147844Spjd	mydaemon();
485147844Spjd	g_gatec_loop();
486147844Spjd}
487147844Spjd
488128765Spjdint
489128765Spjdmain(int argc, char *argv[])
490128765Spjd{
491128765Spjd
492128765Spjd	if (argc < 2)
493128765Spjd		usage();
494147844Spjd	if (strcasecmp(argv[1], "create") == 0)
495128765Spjd		action = CREATE;
496128765Spjd	else if (strcasecmp(argv[1], "destroy") == 0)
497128765Spjd		action = DESTROY;
498128765Spjd	else if (strcasecmp(argv[1], "list") == 0)
499128765Spjd		action = LIST;
500147844Spjd	else if (strcasecmp(argv[1], "rescue") == 0)
501147844Spjd		action = RESCUE;
502128765Spjd	else
503128765Spjd		usage();
504128765Spjd	argc -= 1;
505128765Spjd	argv += 1;
506128765Spjd	for (;;) {
507128765Spjd		int ch;
508128765Spjd
509128765Spjd		ch = getopt(argc, argv, "fno:p:q:R:S:s:t:u:v");
510128765Spjd		if (ch == -1)
511128765Spjd			break;
512128765Spjd		switch (ch) {
513128765Spjd		case 'f':
514128765Spjd			if (action != DESTROY)
515128765Spjd				usage();
516128765Spjd			force = 1;
517128765Spjd			break;
518128765Spjd		case 'n':
519147844Spjd			if (action != CREATE && action != RESCUE)
520128765Spjd				usage();
521128765Spjd			nagle = 0;
522128765Spjd			break;
523128765Spjd		case 'o':
524147844Spjd			if (action != CREATE && action != RESCUE)
525128765Spjd				usage();
526128765Spjd			if (strcasecmp("ro", optarg) == 0)
527128765Spjd				flags = G_GATE_FLAG_READONLY;
528128765Spjd			else if (strcasecmp("wo", optarg) == 0)
529128765Spjd				flags = G_GATE_FLAG_WRITEONLY;
530128765Spjd			else if (strcasecmp("rw", optarg) == 0)
531128765Spjd				flags = 0;
532128765Spjd			else {
533128765Spjd				errx(EXIT_FAILURE,
534128765Spjd				    "Invalid argument for '-o' option.");
535128765Spjd			}
536128765Spjd			break;
537128765Spjd		case 'p':
538147844Spjd			if (action != CREATE && action != RESCUE)
539128765Spjd				usage();
540128765Spjd			errno = 0;
541128765Spjd			port = strtoul(optarg, NULL, 10);
542128765Spjd			if (port == 0 && errno != 0)
543128765Spjd				errx(EXIT_FAILURE, "Invalid port.");
544128765Spjd			break;
545128765Spjd		case 'q':
546128765Spjd			if (action != CREATE)
547128765Spjd				usage();
548128765Spjd			errno = 0;
549128765Spjd			queue_size = strtoul(optarg, NULL, 10);
550128765Spjd			if (queue_size == 0 && errno != 0)
551128765Spjd				errx(EXIT_FAILURE, "Invalid queue_size.");
552128765Spjd			break;
553128765Spjd		case 'R':
554147844Spjd			if (action != CREATE && action != RESCUE)
555128765Spjd				usage();
556128765Spjd			errno = 0;
557128765Spjd			rcvbuf = strtoul(optarg, NULL, 10);
558128765Spjd			if (rcvbuf == 0 && errno != 0)
559128765Spjd				errx(EXIT_FAILURE, "Invalid rcvbuf.");
560128765Spjd			break;
561128765Spjd		case 'S':
562147844Spjd			if (action != CREATE && action != RESCUE)
563128765Spjd				usage();
564128765Spjd			errno = 0;
565128765Spjd			sndbuf = strtoul(optarg, NULL, 10);
566128765Spjd			if (sndbuf == 0 && errno != 0)
567128765Spjd				errx(EXIT_FAILURE, "Invalid sndbuf.");
568128765Spjd			break;
569128765Spjd		case 's':
570128765Spjd			if (action != CREATE)
571128765Spjd				usage();
572128765Spjd			errno = 0;
573128765Spjd			sectorsize = strtoul(optarg, NULL, 10);
574128765Spjd			if (sectorsize == 0 && errno != 0)
575128765Spjd				errx(EXIT_FAILURE, "Invalid sectorsize.");
576128765Spjd			break;
577128765Spjd		case 't':
578128765Spjd			if (action != CREATE)
579128765Spjd				usage();
580128765Spjd			errno = 0;
581128765Spjd			timeout = strtoul(optarg, NULL, 10);
582128765Spjd			if (timeout == 0 && errno != 0)
583128765Spjd				errx(EXIT_FAILURE, "Invalid timeout.");
584128765Spjd			break;
585128765Spjd		case 'u':
586128765Spjd			errno = 0;
587128765Spjd			unit = strtol(optarg, NULL, 10);
588128765Spjd			if (unit == 0 && errno != 0)
589128765Spjd				errx(EXIT_FAILURE, "Invalid unit number.");
590128765Spjd			break;
591128765Spjd		case 'v':
592128765Spjd			if (action == DESTROY)
593128765Spjd				usage();
594128765Spjd			g_gate_verbose++;
595128765Spjd			break;
596128765Spjd		default:
597128765Spjd			usage();
598128765Spjd		}
599128765Spjd	}
600128765Spjd	argc -= optind;
601128765Spjd	argv += optind;
602128765Spjd
603128765Spjd	switch (action) {
604128765Spjd	case CREATE:
605128765Spjd		if (argc != 2)
606128765Spjd			usage();
607128765Spjd		g_gate_load_module();
608128765Spjd		g_gate_open_device();
609128765Spjd		host = argv[0];
610128765Spjd		path = argv[1];
611128765Spjd		g_gatec_create();
612128765Spjd		break;
613128765Spjd	case DESTROY:
614128765Spjd		if (unit == -1) {
615128765Spjd			fprintf(stderr, "Required unit number.\n");
616128765Spjd			usage();
617128765Spjd		}
618128765Spjd		g_gate_verbose = 1;
619128765Spjd		g_gate_open_device();
620128765Spjd		g_gate_destroy(unit, force);
621128765Spjd		break;
622128765Spjd	case LIST:
623128765Spjd		g_gate_list(unit, g_gate_verbose);
624128765Spjd		break;
625147844Spjd	case RESCUE:
626147844Spjd		if (argc != 2)
627147844Spjd			usage();
628147844Spjd		if (unit == -1) {
629147844Spjd			fprintf(stderr, "Required unit number.\n");
630147844Spjd			usage();
631147844Spjd		}
632147844Spjd		g_gate_open_device();
633147844Spjd		host = argv[0];
634147844Spjd		path = argv[1];
635147844Spjd		g_gatec_rescue();
636147844Spjd		break;
637128765Spjd	case UNSET:
638128765Spjd	default:
639128765Spjd		usage();
640128765Spjd	}
641128765Spjd	g_gate_close_device();
642128765Spjd	exit(EXIT_SUCCESS);
643128765Spjd}
644