Improve the process for GNU tools
[minix3.git] / minix / commands / arp / arp.c
blob1a4d9f660d1715babafaebba5484eeb3c7341075
1 /*
2 arp.c
4 Created: Jan 2001 by Philip Homburg <philip@f-mnx.phicoh.com>
6 Manipulate ARP table
7 */
9 #define _POSIX_C_SOURCE 2
10 #define _NETBSD_SOURCE 1
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <stdarg.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
20 #include <sys/ioctl.h>
22 #include <net/netlib.h>
23 #include <net/gen/ether.h>
24 #include <net/gen/if_ether.h>
25 #include <net/gen/in.h>
26 #include <net/gen/inet.h>
27 #include <net/gen/ip_io.h>
28 #include <netdb.h>
29 #include <net/gen/socket.h>
31 #include <net/gen/arp_io.h>
33 #include <arpa/inet.h>
35 char *progname;
36 static int ipfd= -1;
37 static int do_setuid= 0;
39 static void do_open(char *devname);
40 static void show_one(char *hostname, int do_num);
41 static void show_all(int do_num);
42 static void print_one(ipaddr_t ipaddr, nwio_arp_t *arpp, int do_num);
43 static void delete_all(void);
44 static void delete(char *hostname);
45 static void do_set(char *hostname, char *ethername, int temp, int pub,
46 int optdelete);
47 static ipaddr_t nametoipaddr(char *hostname);
48 static void fatal(const char *fmt, ...);
49 static void usage(void);
51 int main(int argc, char *argv[])
53 int c;
54 char *hostname, *ethername;
55 int do_temp, do_pub;
56 int a_flag, d_flag, n_flag, s_flag, S_flag;
57 char *I_arg;
59 (progname=strrchr(argv[0],'/')) ? progname++ : (progname=argv[0]);
61 a_flag= d_flag= n_flag= s_flag= S_flag= 0;
62 I_arg= NULL;
63 while(c= getopt(argc, argv, "adnsS?I:"), c != -1)
65 switch(c)
67 case '?': usage();
68 case 'a': a_flag= 1; break;
69 case 'd': d_flag= 1; break;
70 case 'n': n_flag= 1; break;
71 case 's': s_flag= 1; break;
72 case 'S': S_flag= 1; break;
73 case 'I': I_arg= optarg; break;
74 default: fatal("getopt failed: '%c'", c);
78 hostname= NULL; /* lint */
79 ethername= NULL; /* lint */
80 do_temp= do_pub= 0; /* lint */
82 if (n_flag + d_flag + s_flag + S_flag > 1)
83 usage();
84 if (s_flag || S_flag)
86 if (optind >= argc) usage();
87 hostname= argv[optind++];
89 if (optind >= argc) usage();
90 ethername= argv[optind++];
92 do_temp= do_pub= 0;
93 while (optind < argc)
95 if (strcasecmp(argv[optind], "temp") == 0)
97 do_temp= 1;
98 optind++;
99 continue;
101 if (strcasecmp(argv[optind], "pub") == 0)
103 do_pub= 1;
104 optind++;
105 continue;
107 usage();
110 else if (d_flag)
112 if (!a_flag)
114 if (optind >= argc)
115 usage();
116 hostname= argv[optind++];
117 if (optind != argc)
118 usage();
121 else if (a_flag)
123 if (optind != argc)
124 usage();
125 do_setuid= 1;
127 else
129 if (optind >= argc)
130 usage();
131 hostname= argv[optind++];
132 if (optind != argc)
133 usage();
134 do_setuid= 1;
137 do_open(I_arg);
138 if (d_flag)
140 if (a_flag)
141 delete_all();
142 else
143 delete(hostname);
145 else if (s_flag || S_flag)
146 do_set(hostname, ethername, do_temp, do_pub, S_flag);
147 else if (a_flag)
148 show_all(n_flag);
149 else
150 show_one(hostname, n_flag);
151 exit(0);
154 static void do_open(char *devname)
156 size_t l;
157 char *check;
159 if (do_setuid && devname)
161 /* Only strings that consist of IP_DEVICE optionally
162 * followed by a number are allowed.
164 l= strlen(IP_DEVICE);
165 if (strncmp(devname, IP_DEVICE, l) != 0)
166 do_setuid= 0;
167 else if (strlen(devname) == l)
168 ; /* OK */
169 else
171 strtoul(devname+l, &check, 10);
172 if (check[0] != '\0')
173 do_setuid= 0;
176 if (!devname)
177 devname= IP_DEVICE;
178 if (!do_setuid)
180 setuid(getuid());
181 setgid(getgid());
183 ipfd= open(devname, O_RDWR);
184 if (ipfd == -1)
185 fatal("unable to open '%s': %s", devname, strerror(errno));
188 static void show_one(char *hostname, int do_num)
190 int r;
191 ipaddr_t ipaddr;
192 nwio_arp_t arp;
194 ipaddr= nametoipaddr(hostname);
196 arp.nwa_ipaddr= ipaddr;
197 r= ioctl(ipfd, NWIOARPGIP, &arp);
198 if (r == -1 && errno == ENOENT)
200 print_one(ipaddr, NULL, do_num);
201 exit(1);
203 if (r == -1)
204 fatal("NWIOARPGIP failed: %s", strerror(errno));
205 print_one(ipaddr, &arp, do_num);
208 static void show_all(int do_num)
210 int ind, max, i, r;
211 nwio_arp_t *arptab;
212 nwio_arp_t arp;
214 /* First get all entries */
215 max= 10;
216 ind= 0;
217 arptab= malloc(max * sizeof(*arptab));
218 if (arptab == NULL)
220 fatal("out of memory, can't get %d bytes",
221 max*sizeof(*arptab));
223 arp.nwa_entno= 0;
224 for (;;)
226 if (ind == max)
228 max *= 2;
229 arptab= realloc(arptab, max * sizeof(*arptab));
230 if (!arptab)
232 fatal("out of memory, can't get %d bytes",
233 max*sizeof(*arptab));
236 r= ioctl(ipfd, NWIOARPGNEXT, &arp);
237 if (r == -1 && errno == ENOENT)
238 break;
239 if (r == -1)
240 fatal("NWIOARPGNEXT failed: %s", strerror(errno));
241 arptab[ind]= arp;
242 ind++;
245 for (i= 0; i<ind; i++)
246 print_one(0, &arptab[i], do_num);
249 static void print_one(ipaddr_t ipaddr, nwio_arp_t *arpp, int do_num)
251 u32_t flags;
252 struct hostent *he;
254 if (arpp)
255 ipaddr= arpp->nwa_ipaddr;
256 if (!do_num)
257 he= gethostbyaddr((char *)&ipaddr, sizeof(ipaddr), AF_INET);
258 else
259 he= NULL;
260 if (he)
261 printf("%s (%s)", he->h_name,
262 inet_ntoa(*(struct in_addr *)&ipaddr));
263 else
264 printf("%s", inet_ntoa(*(struct in_addr *)&ipaddr));
265 if (!arpp)
267 printf(" -- no entry\n");
268 return;
270 flags= arpp->nwa_flags;
271 if (flags & NWAF_INCOMPLETE)
272 printf(" is incomplete");
273 else if (flags & NWAF_DEAD)
274 printf(" is dead");
275 else
277 printf(" is at %s", ether_ntoa(&arpp->nwa_ethaddr));
278 if (flags & NWAF_PERM)
279 printf(" permanent");
280 if (flags & NWAF_PUB)
281 printf(" published");
283 printf("\n");
286 static void delete_all(void)
288 int ind, max, i, r;
289 nwio_arp_t *arptab;
290 nwio_arp_t arp;
292 /* First get all entries */
293 max= 10;
294 ind= 0;
295 arptab= malloc(max * sizeof(*arptab));
296 if (arptab == NULL)
298 fatal("out of memory, can't get %d bytes",
299 max*sizeof(*arptab));
301 arp.nwa_entno= 0;
302 for (;;)
304 if (ind == max)
306 max *= 2;
307 arptab= realloc(arptab, max * sizeof(*arptab));
308 if (arptab == NULL)
310 fatal("out of memory, can't get %d bytes",
311 max*sizeof(*arptab));
314 r= ioctl(ipfd, NWIOARPGNEXT, &arp);
315 if (r == -1 && errno == ENOENT)
316 break;
317 if (r == -1)
318 fatal("NWIOARPGNEXT failed: %s", strerror(errno));
319 arptab[ind]= arp;
320 ind++;
323 for (i= 0; i<ind; i++)
325 r= ioctl(ipfd, NWIOARPDIP, &arptab[i]);
326 if (r == 0)
327 continue;
328 if (errno == EINVAL || errno == ENOENT)
330 /* Entry is incomplete of entry is already deleted */
331 continue;
333 fatal("unable to delete host %s: %s",
334 inet_ntoa(*(struct in_addr *)&arptab[i].nwa_ipaddr),
335 strerror(errno));
339 static void delete(char *hostname)
341 int r;
342 ipaddr_t ipaddr;
343 nwio_arp_t arp;
345 ipaddr= nametoipaddr(hostname);
346 arp.nwa_ipaddr= ipaddr;
347 r= ioctl(ipfd, NWIOARPDIP, &arp);
348 if (r == 0)
349 return;
350 if (errno == ENOENT)
352 print_one(ipaddr, NULL, 0);
353 exit(1);
355 fatal("unable to delete host %s: %s",
356 inet_ntoa(*(struct in_addr *)&ipaddr),
357 errno == EINVAL ? "entry is incomplete" : strerror(errno));
360 static void do_set(char *hostname, char *ethername, int temp, int pub,
361 int optdelete)
363 int r;
364 ipaddr_t ipaddr;
365 ether_addr_t *eap;
366 ether_addr_t ethaddr;
367 nwio_arp_t arp;
368 nwio_ipconf_t ipconf;
370 ipaddr= nametoipaddr(hostname);
371 if (pub && strcasecmp(ethername, "auto") == 0)
373 r= ioctl(ipfd, NWIOGIPCONF, &ipconf);
374 if (r == -1)
375 fatal("NWIOGIPCONF failed: %s", strerror(errno));
376 arp.nwa_ipaddr= ipconf.nwic_ipaddr;
377 r= ioctl(ipfd, NWIOARPGIP, &arp);
378 if (r == -1)
379 fatal("NWIOARPGIP failed: %s", strerror(errno));
380 ethaddr= arp.nwa_ethaddr;
382 else if (eap= ether_aton(ethername), eap != NULL)
383 ethaddr= *eap;
384 else if (ether_hostton(ethername, &ethaddr) != 0)
386 fatal("unable to parse ethernet address '%s'",
387 ethername);
390 if (optdelete)
392 arp.nwa_ipaddr= ipaddr;
393 r= ioctl(ipfd, NWIOARPDIP, &arp);
394 if (r == -1 && errno != ENOENT)
396 fatal("unable to delete entry for host %s: %s",
397 inet_ntoa(*(struct in_addr *)&ipaddr),
398 errno == EINVAL ? "incomplete entry" :
399 strerror(errno));
403 arp.nwa_ipaddr= ipaddr;
404 arp.nwa_ethaddr= ethaddr;
405 arp.nwa_flags= 0;
406 if (pub)
407 arp.nwa_flags |= NWAF_PUB;
408 if (!temp)
409 arp.nwa_flags |= NWAF_PERM;
410 r= ioctl(ipfd, NWIOARPSIP, &arp);
411 if (r == -1)
413 fatal("unable to set arp entry: %s",
414 errno == EEXIST ? "entry exists" : strerror(errno));
418 static ipaddr_t nametoipaddr(char *hostname)
420 ipaddr_t ipaddr;
421 struct hostent *he;
423 if (inet_aton(hostname, (struct in_addr *)&ipaddr) == 0)
425 he= gethostbyname(hostname);
426 if (!he)
427 fatal("unknown hostname '%s'", hostname);
428 if (he->h_addrtype != AF_INET ||
429 he->h_length != sizeof(ipaddr))
431 fatal("strange host '%s': addrtype %d, length %d",
432 he->h_addrtype, he->h_length);
434 memcpy(&ipaddr, he->h_addr, sizeof(ipaddr));
436 return ipaddr;
439 #if 0
440 static char *ether_ntoa(struct ether_addr *eap)
442 static char buf[]= "xx:xx:xx:xx:xx:xx";
444 sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
445 eap->ea_addr[0], eap->ea_addr[1],
446 eap->ea_addr[2], eap->ea_addr[3],
447 eap->ea_addr[4], eap->ea_addr[5]);
448 return buf;
450 #endif
452 static void fatal(const char *fmt, ...)
454 va_list ap;
456 va_start(ap, fmt);
457 fprintf(stderr, "%s: ", progname);
458 vfprintf(stderr, fmt, ap);
459 fprintf(stderr, "\n");
460 va_end(ap);
462 exit(1);
465 static void usage(void)
467 fprintf(stderr, "Usage:\tarp [-I ip-dev] [-n] hostname\n"
468 "\tarp [-I ip-dev] [-n] -a\n"
469 "\tarp [-I ip-dev] -d hostname\n"
470 "\tarp [-I ip-dev] -d -a\n"
471 "\tarp [-I ip-dev] -s hostname ether-addr [temp] [pub]\n"
472 "\tarp [-I ip-dev] -S hostname ether-addr [temp] [pub]\n");
473 exit(1);
477 * $PchId: arp.c,v 1.3 2005/01/31 22:31:45 philip Exp $