GC a manpage backup that was created by passing -b when installing it.
[dragonfly.git] / sbin / syslink / syslink.c
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:
10  * 
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.
20  * 
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.
33  * 
34  * $DragonFly: src/sbin/syslink/syslink.c,v 1.1 2007/04/16 17:36:04 dillon Exp $
35  */
36
37 #include "syslink.h"
38
39 enum cmd { CMD_NONE, CMD_LIST, CMD_ADD, CMD_DEL, CMD_MOD };
40
41 static int parse_add(const char *base);
42 static int run_cmd(enum cmd commandopt);
43 static void usage(const char *av0);
44
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;
56
57 int
58 main(int ac, char **av)
59 {
60         const char *pidfile = NULL;
61         const char *av0 = av[0];
62         char *ptr;
63         enum cmd commandopt;
64         int ch;
65         int i;
66
67         commandopt = CMD_NONE;
68
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);
89                 }
90         }
91         ac -= optind;
92         av += optind;
93
94         /*
95          * -l with no arguments dumps all syslink routers.  This is the
96          * only command that does not require further arguments.
97          */
98         if (commandopt == CMD_LIST && ac == 0)
99                 exit(run_cmd(commandopt));
100         if (ac == 0)
101                 usage(av0);
102
103         /*
104          * Parse sysid[:linkid]
105          */
106         ptr = strdup(av[0]);
107         SysId = ptr;
108         if ((ptr = strchr(ptr, ':')) != NULL) {
109                 *ptr++ = 0;
110                 LinkId = ptr;
111         }
112         --ac;
113         ++av;
114
115         /*
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.
118          */
119         if (commandopt != CMD_NONE) {
120                 if (ac)
121                         usage(av0);
122                 exit(run_cmd(commandopt));
123         }
124
125         /*
126          * Parse keyword commands, set commandopt as an earmark.
127          */
128         if (ac == 0) {
129                 fprintf(stderr, "Missing command directive\n");
130                 usage(av0);
131         }
132         --ac;
133         ++av;
134
135         if (strcmp(av[-1], "add") == 0) {
136                 /*
137                  * add [protocol:]target[/bits]
138                  */
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);
157         }
158
159         /*
160          * Parse supplementary info
161          */
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);
172                         }
173                         ++i;
174                 } else {
175                         fprintf(stderr, "Unknown directive: %s\n", av[i]);
176                         usage(av0);
177                 }
178         }
179         if (i > ac) {
180                 fprintf(stderr, "Expected argument for last directive\n");
181                 usage(av0);
182         }
183
184         exit(run_cmd(commandopt));
185 }
186
187 /*
188  * Parse [protocol:]target[/bits]
189  */
190 static
191 int
192 parse_add(const char *base)
193 {
194         char *prot_str;
195         char *targ_str;
196         char *bits_str;
197         char *ptr;
198         struct hostent *he;
199
200         /*
201          * Split out the protocol from the protocol:target/subnet string,
202          * leave target/subnet in targ_str.
203          */
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);
211         }
212
213         /*
214          * Parse the /subnet out of the target string, if present.
215          */
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);
222                 }
223                 if (NumBits < 2 || NumBits > 24) {
224                         fprintf(stderr, "Subnet must be 2-24 bits\n");
225                         return(-1);
226                 }
227         }
228
229         /*
230          * Figure out the protocol
231          */
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);
252         }
253
254         /*
255          * Process the host, file, or descriptor specification
256          */
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);
270                 }
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);
278                 }
279                 break;
280         case PROTO_FIFO:
281                 TargetPath = targ_str;
282                 break;
283         }
284         return(0);
285 }
286
287 static
288 int
289 run_cmd(enum cmd commandopt)
290 {
291         int exitcode = 0;
292
293         /*
294          * Run the command
295          */
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;
311         }
312         return(exitcode);
313 }
314
315 static
316 void
317 usage(const char *av0)
318 {
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"
326         );
327         exit(1);
328 }
329