Resync patch with contrib.
[dragonfly.git] / sbin / syslink / syslink.c
bloba8de2bdc6abbda1ffa4b12b767220f1b384d32fe
1 /*
2 * Copyright (c) 2007 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
34 * $DragonFly: src/sbin/syslink/syslink.c,v 1.1 2007/04/16 17:36:04 dillon Exp $
37 #include "syslink.h"
39 enum cmd { CMD_NONE, CMD_LIST, CMD_ADD, CMD_DEL, CMD_MOD };
41 static int parse_add(const char *base);
42 static int run_cmd(enum cmd commandopt);
43 static void usage(const char *av0);
45 int ForceOpt;
46 int NumericOpt;
47 int VerboseOpt;
48 const char *SysId;
49 const char *LinkId;
50 const char *LabelStr;
51 enum proto Protocol; /* filled in by parse_add() */
52 int NumBits;
53 int TargetFd = -1;
54 const char *TargetPath;
55 struct sockaddr_in TargetSin;
57 int
58 main(int ac, char **av)
60 const char *pidfile = NULL;
61 const char *av0 = av[0];
62 char *ptr;
63 enum cmd commandopt;
64 int ch;
65 int i;
67 commandopt = CMD_NONE;
69 while ((ch = getopt(ac, av, "fnlvp:")) != -1) {
70 switch(ch) {
71 case 'f':
72 ++ForceOpt;
73 break;
74 case 'n':
75 ++NumericOpt;
76 break;
77 case 'l':
78 commandopt = CMD_LIST;
79 break;
80 case 'v':
81 ++VerboseOpt;
82 break;
83 case 'p':
84 pidfile = optarg;
85 break;
86 default:
87 fprintf(stderr, "unknown option: -%c\n", optopt);
88 usage(av0);
91 ac -= optind;
92 av += optind;
95 * -l with no arguments dumps all syslink routers. This is the
96 * only command that does not require further arguments.
98 if (commandopt == CMD_LIST && ac == 0)
99 exit(run_cmd(commandopt));
100 if (ac == 0)
101 usage(av0);
104 * Parse sysid[:linkid]
106 ptr = strdup(av[0]);
107 SysId = ptr;
108 if ((ptr = strchr(ptr, ':')) != NULL) {
109 *ptr++ = 0;
110 LinkId = ptr;
112 --ac;
113 ++av;
116 * Handle options that are actually commands (-l only at the moment).
117 * There should be no more arguments if we have a command-as-option.
119 if (commandopt != CMD_NONE) {
120 if (ac)
121 usage(av0);
122 exit(run_cmd(commandopt));
126 * Parse keyword commands, set commandopt as an earmark.
128 if (ac == 0) {
129 fprintf(stderr, "Missing command directive\n");
130 usage(av0);
132 --ac;
133 ++av;
135 if (strcmp(av[-1], "add") == 0) {
137 * add [protocol:]target[/bits]
139 commandopt = CMD_ADD;
140 if (ac == 0)
141 usage(av0);
142 if (parse_add(av[0]))
143 usage(av0);
144 --ac;
145 ++av;
146 } else if (strcmp(av[-1], "del") == 0) {
147 commandopt = CMD_DEL;
148 } else if (strcmp(av[-1], "delete") == 0) {
149 commandopt = CMD_DEL;
150 } else if (strcmp(av[-1], "mod") == 0) {
151 commandopt = CMD_MOD;
152 } else if (strcmp(av[-1], "modify") == 0) {
153 commandopt = CMD_MOD;
154 } else {
155 fprintf(stderr, "Unknown command directive: %s\n", av[-1]);
156 usage(av0);
160 * Parse supplementary info
162 for (i = 0; i < ac; ++i) {
163 if (strcmp(av[i], "label") == 0) {
164 LabelStr = av[i+1];
165 ++i;
166 } else if (strcmp(av[i], "port") == 0) {
167 ptr = av[i+1];
168 TargetSin.sin_port = htons(strtol(ptr, &ptr, 0));
169 if (*ptr) {
170 fprintf(stderr, "Non-numeric port specified\n");
171 usage(av0);
173 ++i;
174 } else {
175 fprintf(stderr, "Unknown directive: %s\n", av[i]);
176 usage(av0);
179 if (i > ac) {
180 fprintf(stderr, "Expected argument for last directive\n");
181 usage(av0);
184 exit(run_cmd(commandopt));
188 * Parse [protocol:]target[/bits]
190 static
192 parse_add(const char *base)
194 char *prot_str;
195 char *targ_str;
196 char *bits_str;
197 char *ptr;
198 struct hostent *he;
201 * Split out the protocol from the protocol:target/subnet string,
202 * leave target/subnet in targ_str.
204 if (strchr(base, ':')) {
205 prot_str = strdup(base);
206 targ_str = strchr(prot_str, ':');
207 *targ_str++ = 0;
208 } else {
209 prot_str = NULL;
210 targ_str = strdup(base);
214 * Parse the /subnet out of the target string, if present.
216 if ((bits_str = strchr(targ_str, '/')) != NULL) {
217 *bits_str++ = 0;
218 NumBits = strtol(bits_str, &ptr, NULL);
219 if (*ptr) {
220 fprintf(stderr, "Malformed /subnet\n");
221 return(-1);
223 if (NumBits < 2 || NumBits > 24) {
224 fprintf(stderr, "Subnet must be 2-24 bits\n");
225 return(-1);
230 * Figure out the protocol
232 if (prot_str == NULL) {
233 if (bits_str)
234 Protocol = PROTO_TCP;
235 else
236 Protocol = PROTO_UDP;
237 } else if (strcmp(prot_str, "tcp") == 0) {
238 Protocol = PROTO_TCP;
239 } else if (strcmp(prot_str, "udp") == 0) {
240 Protocol = PROTO_UDP;
241 } else if (strcmp(prot_str, "udp_ptp") == 0) {
242 Protocol = PROTO_UDP_PTP;
243 } else if (strcmp(prot_str, "pipe") == 0) {
244 Protocol = PROTO_PIPE;
245 } else if (strcmp(prot_str, "fifo") == 0) {
246 Protocol = PROTO_FIFO;
247 } else if (strcmp(prot_str, "listen") == 0) {
248 Protocol = PROTO_LISTEN;
249 } else {
250 fprintf(stderr, "Unknown protocol: %s\n", prot_str);
251 return(-1);
255 * Process the host, file, or descriptor specification
257 switch(Protocol) {
258 case PROTO_TCP:
259 case PROTO_UDP:
260 case PROTO_UDP_PTP:
261 case PROTO_LISTEN:
262 TargetSin.sin_len = sizeof(TargetSin);
263 TargetSin.sin_family = AF_INET;
264 if (inet_aton(targ_str, &TargetSin.sin_addr) != 0) {
265 } else if ((he = gethostbyname2(targ_str, AF_INET)) != NULL) {
266 bcopy(he->h_addr, &TargetSin.sin_addr, he->h_length);
267 } else {
268 fprintf(stderr, "Cannot resolve target %s\n", targ_str);
269 return(-1);
271 break;
272 case PROTO_PIPE:
273 TargetFd = strtol(targ_str, &ptr, 0);
274 if (*ptr) {
275 fprintf(stderr, "non-numeric file descriptor "
276 "number in target\n");
277 return(-1);
279 break;
280 case PROTO_FIFO:
281 TargetPath = targ_str;
282 break;
284 return(0);
287 static
289 run_cmd(enum cmd commandopt)
291 int exitcode = 0;
294 * Run the command
296 switch(commandopt) {
297 case CMD_NONE:
298 break;
299 case CMD_LIST:
300 printf("list\n");
301 break;
302 case CMD_ADD:
303 printf("add\n");
304 break;
305 case CMD_DEL:
306 printf("del\n");
307 break;
308 case CMD_MOD:
309 printf("mod\n");
310 break;
312 return(exitcode);
315 static
316 void
317 usage(const char *av0)
319 fprintf(stderr,
320 "syslink -l [-nv] [sysid[:linkid]]\n"
321 "syslink [-fnv] [-p pidfile] sysid add [protocol:]target[/bits]\n"
322 " [label name] [port num]\n"
323 "syslink [-fnv] sysid[:linkid] delete\n"
324 "syslink [-fnv] sysid[:linkid] modify\n"
325 " [label name] [port num]\n"
327 exit(1);