t40c term[] count fix
[minix.git] / commands / arp / arp.c
blob7304f15ca24a6c9c05a70e832ba8de34eadc66bc
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 _MINIX_SOURCE
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 <net/gen/netdb.h>
29 #include <net/gen/socket.h>
31 #include <net/gen/arp_io.h>
33 char *progname;
34 static int ipfd= -1;
35 static int do_setuid= 0;
37 static void do_open(char *devname);
38 static void show_one(char *hostname, int do_num);
39 static void show_all(int do_num);
40 static void print_one(ipaddr_t ipaddr, nwio_arp_t *arpp, int do_num);
41 static void delete_all(void);
42 static void delete(char *hostname);
43 static void do_set(char *hostname, char *ethername, int temp, int pub,
44 int optdelete);
45 static ipaddr_t nametoipaddr(char *hostname);
46 static void fatal(const char *fmt, ...);
47 static void usage(void);
49 int main(int argc, char *argv[])
51 int c;
52 char *hostname, *ethername;
53 int do_temp, do_pub;
54 int a_flag, d_flag, n_flag, s_flag, S_flag;
55 char *I_arg;
57 (progname=strrchr(argv[0],'/')) ? progname++ : (progname=argv[0]);
59 a_flag= d_flag= n_flag= s_flag= S_flag= 0;
60 I_arg= NULL;
61 while(c= getopt(argc, argv, "adnsS?I:"), c != -1)
63 switch(c)
65 case '?': usage();
66 case 'a': a_flag= 1; break;
67 case 'd': d_flag= 1; break;
68 case 'n': n_flag= 1; break;
69 case 's': s_flag= 1; break;
70 case 'S': S_flag= 1; break;
71 case 'I': I_arg= optarg; break;
72 default: fatal("getopt failed: '%c'", c);
76 hostname= NULL; /* lint */
77 ethername= NULL; /* lint */
78 do_temp= do_pub= 0; /* lint */
80 if (n_flag + d_flag + s_flag + S_flag > 1)
81 usage();
82 if (s_flag || S_flag)
84 if (optind >= argc) usage();
85 hostname= argv[optind++];
87 if (optind >= argc) usage();
88 ethername= argv[optind++];
90 do_temp= do_pub= 0;
91 while (optind < argc)
93 if (strcasecmp(argv[optind], "temp") == 0)
95 do_temp= 1;
96 optind++;
97 continue;
99 if (strcasecmp(argv[optind], "pub") == 0)
101 do_pub= 1;
102 optind++;
103 continue;
105 usage();
108 else if (d_flag)
110 if (!a_flag)
112 if (optind >= argc)
113 usage();
114 hostname= argv[optind++];
115 if (optind != argc)
116 usage();
119 else if (a_flag)
121 if (optind != argc)
122 usage();
123 do_setuid= 1;
125 else
127 if (optind >= argc)
128 usage();
129 hostname= argv[optind++];
130 if (optind != argc)
131 usage();
132 do_setuid= 1;
135 do_open(I_arg);
136 if (d_flag)
138 if (a_flag)
139 delete_all();
140 else
141 delete(hostname);
143 else if (s_flag || S_flag)
144 do_set(hostname, ethername, do_temp, do_pub, S_flag);
145 else if (a_flag)
146 show_all(n_flag);
147 else
148 show_one(hostname, n_flag);
149 exit(0);
152 static void do_open(char *devname)
154 size_t l;
155 char *check;
157 if (do_setuid && devname)
159 /* Only strings that consist of IP_DEVICE optionally
160 * followed by a number are allowed.
162 l= strlen(IP_DEVICE);
163 if (strncmp(devname, IP_DEVICE, l) != 0)
164 do_setuid= 0;
165 else if (strlen(devname) == l)
166 ; /* OK */
167 else
169 strtoul(devname+l, &check, 10);
170 if (check[0] != '\0')
171 do_setuid= 0;
174 if (!devname)
175 devname= IP_DEVICE;
176 if (!do_setuid)
178 setuid(getuid());
179 setgid(getgid());
181 ipfd= open(devname, O_RDWR);
182 if (ipfd == -1)
183 fatal("unable to open '%s': %s", devname, strerror(errno));
186 static void show_one(char *hostname, int do_num)
188 int r;
189 ipaddr_t ipaddr;
190 nwio_arp_t arp;
192 ipaddr= nametoipaddr(hostname);
194 arp.nwa_ipaddr= ipaddr;
195 r= ioctl(ipfd, NWIOARPGIP, &arp);
196 if (r == -1 && errno == ENOENT)
198 print_one(ipaddr, NULL, do_num);
199 exit(1);
201 if (r == -1)
202 fatal("NWIOARPGIP failed: %s", strerror(errno));
203 print_one(ipaddr, &arp, do_num);
206 static void show_all(int do_num)
208 int ind, max, i, r;
209 nwio_arp_t *arptab;
210 nwio_arp_t arp;
212 /* First get all entries */
213 max= 10;
214 ind= 0;
215 arptab= malloc(max * sizeof(*arptab));
216 if (arptab == NULL)
218 fatal("out of memory, can't get %d bytes",
219 max*sizeof(*arptab));
221 arp.nwa_entno= 0;
222 for (;;)
224 if (ind == max)
226 max *= 2;
227 arptab= realloc(arptab, max * sizeof(*arptab));
228 if (!arptab)
230 fatal("out of memory, can't get %d bytes",
231 max*sizeof(*arptab));
234 r= ioctl(ipfd, NWIOARPGNEXT, &arp);
235 if (r == -1 && errno == ENOENT)
236 break;
237 if (r == -1)
238 fatal("NWIOARPGNEXT failed: %s", strerror(errno));
239 arptab[ind]= arp;
240 ind++;
243 for (i= 0; i<ind; i++)
244 print_one(0, &arptab[i], do_num);
247 static void print_one(ipaddr_t ipaddr, nwio_arp_t *arpp, int do_num)
249 u32_t flags;
250 struct hostent *he;
252 if (arpp)
253 ipaddr= arpp->nwa_ipaddr;
254 if (!do_num)
255 he= gethostbyaddr((char *)&ipaddr, sizeof(ipaddr), AF_INET);
256 else
257 he= NULL;
258 if (he)
259 printf("%s (%s)", he->h_name, inet_ntoa(ipaddr));
260 else
261 printf("%s", inet_ntoa(ipaddr));
262 if (!arpp)
264 printf(" -- no entry\n");
265 return;
267 flags= arpp->nwa_flags;
268 if (flags & NWAF_INCOMPLETE)
269 printf(" is incomplete");
270 else if (flags & NWAF_DEAD)
271 printf(" is dead");
272 else
274 printf(" is at %s", ether_ntoa(&arpp->nwa_ethaddr));
275 if (flags & NWAF_PERM)
276 printf(" permanent");
277 if (flags & NWAF_PUB)
278 printf(" published");
280 printf("\n");
283 static void delete_all(void)
285 int ind, max, i, r;
286 nwio_arp_t *arptab;
287 nwio_arp_t arp;
289 /* First get all entries */
290 max= 10;
291 ind= 0;
292 arptab= malloc(max * sizeof(*arptab));
293 if (arptab == NULL)
295 fatal("out of memory, can't get %d bytes",
296 max*sizeof(*arptab));
298 arp.nwa_entno= 0;
299 for (;;)
301 if (ind == max)
303 max *= 2;
304 arptab= realloc(arptab, max * sizeof(*arptab));
305 if (arptab == NULL)
307 fatal("out of memory, can't get %d bytes",
308 max*sizeof(*arptab));
311 r= ioctl(ipfd, NWIOARPGNEXT, &arp);
312 if (r == -1 && errno == ENOENT)
313 break;
314 if (r == -1)
315 fatal("NWIOARPGNEXT failed: %s", strerror(errno));
316 arptab[ind]= arp;
317 ind++;
320 for (i= 0; i<ind; i++)
322 r= ioctl(ipfd, NWIOARPDIP, &arptab[i]);
323 if (r == 0)
324 continue;
325 if (errno == EINVAL || errno == ENOENT)
327 /* Entry is incomplete of entry is already deleted */
328 continue;
330 fatal("unable to delete host %s: %s",
331 inet_ntoa(arptab[i].nwa_ipaddr), strerror(errno));
335 static void delete(char *hostname)
337 int r;
338 ipaddr_t ipaddr;
339 nwio_arp_t arp;
341 ipaddr= nametoipaddr(hostname);
342 arp.nwa_ipaddr= ipaddr;
343 r= ioctl(ipfd, NWIOARPDIP, &arp);
344 if (r == 0)
345 return;
346 if (errno == ENOENT)
348 print_one(ipaddr, NULL, 0);
349 exit(1);
351 fatal("unable to delete host %s: %s", inet_ntoa(ipaddr),
352 errno == EINVAL ? "entry is incomplete" : strerror(errno));
355 static void do_set(char *hostname, char *ethername, int temp, int pub,
356 int optdelete)
358 int r;
359 ipaddr_t ipaddr;
360 ether_addr_t *eap;
361 ether_addr_t ethaddr;
362 nwio_arp_t arp;
363 nwio_ipconf_t ipconf;
365 ipaddr= nametoipaddr(hostname);
366 if (pub && strcasecmp(ethername, "auto") == 0)
368 r= ioctl(ipfd, NWIOGIPCONF, &ipconf);
369 if (r == -1)
370 fatal("NWIOGIPCONF failed: %s", strerror(errno));
371 arp.nwa_ipaddr= ipconf.nwic_ipaddr;
372 r= ioctl(ipfd, NWIOARPGIP, &arp);
373 if (r == -1)
374 fatal("NWIOARPGIP failed: %s", strerror(errno));
375 ethaddr= arp.nwa_ethaddr;
377 else if (eap= ether_aton(ethername), eap != NULL)
378 ethaddr= *eap;
379 else if (ether_hostton(ethername, &ethaddr) != 0)
381 fatal("unable to parse ethernet address '%s'",
382 ethername);
385 if (optdelete)
387 arp.nwa_ipaddr= ipaddr;
388 r= ioctl(ipfd, NWIOARPDIP, &arp);
389 if (r == -1 && errno != ENOENT)
391 fatal("unable to delete entry for host %s: %s",
392 inet_ntoa(ipaddr),
393 errno == EINVAL ? "incomplete entry" :
394 strerror(errno));
398 arp.nwa_ipaddr= ipaddr;
399 arp.nwa_ethaddr= ethaddr;
400 arp.nwa_flags= 0;
401 if (pub)
402 arp.nwa_flags |= NWAF_PUB;
403 if (!temp)
404 arp.nwa_flags |= NWAF_PERM;
405 r= ioctl(ipfd, NWIOARPSIP, &arp);
406 if (r == -1)
408 fatal("unable to set arp entry: %s",
409 errno == EEXIST ? "entry exists" : strerror(errno));
413 static ipaddr_t nametoipaddr(char *hostname)
415 ipaddr_t ipaddr;
416 struct hostent *he;
418 if (inet_aton(hostname, &ipaddr) == 0)
420 he= gethostbyname(hostname);
421 if (!he)
422 fatal("unknown hostname '%s'", hostname);
423 if (he->h_addrtype != AF_INET ||
424 he->h_length != sizeof(ipaddr))
426 fatal("strange host '%s': addrtype %d, length %d",
427 he->h_addrtype, he->h_length);
429 memcpy(&ipaddr, he->h_addr, sizeof(ipaddr));
431 return ipaddr;
434 #if 0
435 static char *ether_ntoa(struct ether_addr *eap)
437 static char buf[]= "xx:xx:xx:xx:xx:xx";
439 sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
440 eap->ea_addr[0], eap->ea_addr[1],
441 eap->ea_addr[2], eap->ea_addr[3],
442 eap->ea_addr[4], eap->ea_addr[5]);
443 return buf;
445 #endif
447 static void fatal(const char *fmt, ...)
449 va_list ap;
451 va_start(ap, fmt);
452 fprintf(stderr, "%s: ", progname);
453 vfprintf(stderr, fmt, ap);
454 fprintf(stderr, "\n");
455 va_end(ap);
457 exit(1);
460 static void usage(void)
462 fprintf(stderr, "Usage:\tarp [-I ip-dev] [-n] hostname\n"
463 "\tarp [-I ip-dev] [-n] -a\n"
464 "\tarp [-I ip-dev] -d hostname\n"
465 "\tarp [-I ip-dev] -d -a\n"
466 "\tarp [-I ip-dev] -s hostname ether-addr [temp] [pub]\n"
467 "\tarp [-I ip-dev] -S hostname ether-addr [temp] [pub]\n");
468 exit(1);
472 * $PchId: arp.c,v 1.3 2005/01/31 22:31:45 philip Exp $