minor fix to return E_USAGE on -V instead of exit(0);
[oss-qm-packages.git] / rarp.c
blobaab05b3f97e4232f2fb40cdcce3156ab72a23916
1 /*
2 * rarp This file contains an implementation of the command
3 * that maintains the kernel's RARP cache. It is derived
4 * from Fred N. van Kempen's arp command.
6 * Version: $Id: rarp.c,v 1.6 2001/04/08 17:05:05 pb Exp $
8 * Usage: rarp -d hostname Delete entry
9 * rarp -s hostname ethernet_address Add entry
10 * rarp -a Print entries
11 * rarp -f Add frop /etc/ethers
13 * Rewritten: Phil Blundell <Philip.Blundell@pobox.com> 1997-08-03
14 * gettext instead of catgets: Arnaldo Carvalho de Melo <acme@conectiva.com.br> 1998-06-29
15 * 1998-01-01 Bernd Eckenfels reorganised usage()
16 * 2001-04-04 Arnaldo Carvalho de Melo - use setlocale
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <sys/ioctl.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
25 #include <net/if.h>
26 #include <net/if_arp.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <netdb.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <getopt.h>
36 #define DFLT_HW "ether"
38 #include "config.h"
39 #include "intl.h"
40 #include "net-support.h"
41 #include "version.h"
42 #include "pathnames.h"
44 static char no_rarp_message[] = N_("This kernel does not support RARP.\n");
46 static char version_string[] = RELEASE "\nrarp 1.03 (2001-04-04)\n";
48 static struct hwtype *hardware = NULL;
50 /* Delete an entry from the RARP cache. */
51 static int rarp_delete(int fd, struct hostent *hp)
53 struct arpreq req;
54 struct sockaddr_in *si;
55 unsigned int found = 0;
56 char **addr;
58 /* The host can have more than one address, so we loop on them. */
59 for (addr = hp->h_addr_list; *addr != NULL; addr++) {
60 memset((char *) &req, 0, sizeof(req));
61 si = (struct sockaddr_in *) &req.arp_pa;
62 si->sin_family = hp->h_addrtype;
63 memcpy((char *) &si->sin_addr, *addr, hp->h_length);
65 /* Call the kernel. */
66 if (ioctl(fd, SIOCDRARP, &req) == 0) {
67 found++;
68 } else {
69 switch (errno) {
70 case ENXIO:
71 break;
72 case ENODEV:
73 fputs(_(no_rarp_message), stderr);
74 return 1;
75 default:
76 perror("SIOCDRARP");
77 return 1;
82 if (found == 0)
83 printf(_("no RARP entry for %s.\n"), hp->h_name);
84 return 0;
88 /* Set an entry in the RARP cache. */
89 static int rarp_set(int fd, struct hostent *hp, char *hw_addr)
91 struct arpreq req;
92 struct sockaddr_in *si;
93 struct sockaddr sap;
95 if (hardware->input(hw_addr, &sap)) {
96 fprintf(stderr, _("%s: bad hardware address\n"), hw_addr);
97 return 1;
99 /* Clear and fill in the request block. */
100 memset((char *) &req, 0, sizeof(req));
101 si = (struct sockaddr_in *) &req.arp_pa;
102 si->sin_family = hp->h_addrtype;
103 memcpy((char *) &si->sin_addr, hp->h_addr_list[0], hp->h_length);
104 req.arp_ha.sa_family = hardware->type;
105 memcpy(req.arp_ha.sa_data, sap.sa_data, hardware->alen);
107 /* Call the kernel. */
108 if (ioctl(fd, SIOCSRARP, &req) < 0) {
109 if (errno == ENODEV)
110 fputs(_(no_rarp_message), stderr);
111 else
112 perror("SIOCSRARP");
113 return 1;
115 return 0;
118 /* Process an EtherFile */
119 static int rarp_file(int fd, const char *name)
121 char buff[1024];
122 char *host, *addr;
123 int linenr;
124 FILE *fp;
125 struct hostent *hp;
127 if ((fp = fopen(name, "r")) == NULL) {
128 fprintf(stderr, _("rarp: cannot open file %s:%s.\n"), name, strerror(errno));
129 return -1;
131 /* Read the lines in the file. */
132 linenr = 0;
133 while (fgets(buff, sizeof(buff), fp)) {
134 ++linenr;
135 if (buff[0] == '#' || buff[0] == '\0')
136 continue;
137 if ((addr = strtok(buff, "\n \t")) == NULL)
138 continue;
139 if ((host = strtok(NULL, "\n \t")) == NULL) {
140 fprintf(stderr, _("rarp: format error at %s:%u\n"), name, linenr);
141 continue;
143 if ((hp = gethostbyname(host)) == NULL) {
144 fprintf(stderr, _("rarp: %s: unknown host\n"), host);
146 if (rarp_set(fd, hp, addr) != 0) {
147 fprintf(stderr, _("rarp: cannot set entry from %s:%u\n"), name, linenr);
151 (void) fclose(fp);
152 return 0;
155 static int display_cache(void)
157 FILE *fd = fopen(_PATH_PROCNET_RARP, "r");
158 char buffer[256];
159 if (fd == NULL) {
160 if (errno == ENOENT)
161 fputs(_(no_rarp_message), stderr);
162 else
163 perror(_PATH_PROCNET_RARP);
164 return 1;
166 while (feof(fd) == 0) {
167 if (fgets(buffer, 255, fd))
168 fputs(buffer, stdout);
170 fclose(fd);
171 return 0;
174 static void usage(void)
176 fprintf(stderr, _("Usage: rarp -a list entries in cache.\n"));
177 fprintf(stderr, _(" rarp -d <hostname> delete entry from cache.\n"));
178 fprintf(stderr, _(" rarp [<HW>] -s <hostname> <hwaddr> add entry to cache.\n"));
179 fprintf(stderr, _(" rarp -f add entries from /etc/ethers.\n"));
180 fprintf(stderr, _(" rarp -V display program version.\n\n"));
182 fprintf(stderr, _(" <HW>=Use '-H <hw>' to specify hardware address type. Default: %s\n"), DFLT_HW);
183 fprintf(stderr, _(" List of possible hardware types (which support ARP):\n"));
184 print_hwlist(1); /* 1 = ARPable */
185 exit(E_USAGE);
188 #define MODE_DISPLAY 1
189 #define MODE_DELETE 2
190 #define MODE_SET 3
191 #define MODE_ETHERS 4
193 static struct option longopts[] =
195 {"version", 0, NULL, 'V'},
196 {"verbose", 0, NULL, 'v'},
197 {"list", 0, NULL, 'a'},
198 {"set", 0, NULL, 's'},
199 {"delete", 0, NULL, 'd'},
200 {"help", 0, NULL, 'h'},
201 {NULL, 0, NULL, 0}
204 int main(int argc, char **argv)
206 int result = 0, mode = 0, c, nargs = 0, verbose = 0;
207 char *args[3];
208 struct hostent *hp;
209 int fd;
211 #if I18N
212 setlocale (LC_ALL, "");
213 bindtextdomain("net-tools", "/usr/share/locale");
214 textdomain("net-tools");
215 #endif
217 /* Get a default hardware type. */
218 hardware = get_hwtype(DFLT_HW);
220 do {
221 c = getopt_long(argc, argv, "-ht:aHdsVvf", longopts, NULL);
222 switch (c) {
223 case EOF:
224 break;
225 case 'h':
226 usage();
227 case 'V':
228 fprintf(stderr, version_string);
229 exit(E_VERSION);
230 break;
231 case 'v':
232 verbose++;
233 break;
234 case 'a':
235 case 's':
236 case 'd':
237 if (mode) {
238 fprintf(stderr, _("%s: illegal option mix.\n"), argv[0]);
239 usage();
240 } else {
241 mode = (c == 'a' ? MODE_DISPLAY : (c == 'd' ? MODE_DELETE : MODE_SET));
243 break;
244 case 'f':
245 mode = MODE_ETHERS;
246 break;
247 case 'H':
248 case 't':
249 if (optarg) {
250 hardware = get_hwtype(optarg);
251 } else {
252 usage();
254 break;
255 case 1:
256 if (nargs == 2) {
257 usage();
258 exit(1);
259 } else {
260 args[nargs++] = optarg;
262 break;
263 default:
264 usage();
266 } while (c != EOF);
268 if (hardware == NULL) {
269 fprintf(stderr, _("rarp: %s: unknown hardware type.\n"), optarg);
270 exit(1);
272 switch (mode) {
273 case 0:
274 usage();
276 case MODE_DISPLAY:
277 if (nargs != (mode - 1)) {
278 usage();
280 result = display_cache();
281 break;
283 case MODE_DELETE:
284 case MODE_SET:
285 if (nargs != (mode - 1)) {
286 usage();
288 if ((hp = gethostbyname(args[0])) == NULL) {
289 fprintf(stderr, _("rarp: %s: unknown host\n"), args[0]);
290 exit(1);
292 if (fd = socket(PF_INET, SOCK_DGRAM, 0), fd < 0) {
293 perror("socket");
294 exit(1);
296 result = (mode == MODE_DELETE) ? rarp_delete(fd, hp) : rarp_set(fd, hp, args[1]);
297 close(fd);
298 break;
300 case MODE_ETHERS:
301 if (nargs != 0 && nargs != 1)
302 usage();
303 if (fd = socket(PF_INET, SOCK_DGRAM, 0), fd < 0) {
304 perror("socket");
305 exit(1);
307 result = rarp_file(fd, nargs ? args[0] : _PATH_ETHERS);
308 close(fd);
311 exit(result);