0
0
mirror of https://github.com/ecki/net-tools.git synced 2024-09-22 04:10:55 +00:00
net-tools/rarp.c
Mike Frysinger aebd88ef8d standardize --help/usage handling
When displaying usage output in response to the user requesting it
(e.g. using -h/--help), make sure we write the output to stdout and
we exit(0).  When displaying output in response to an error (e.g.
an invalid option or argument), make sure we write the output to
stdout and exit non-zero.  This brings us in line with standard
utilities out there.

URL: https://bugs.gentoo.org/655942
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
2018-06-26 03:30:13 -04:00

316 lines
7.6 KiB
C

/*
* rarp This file contains an implementation of the command
* that maintains the kernel's RARP cache. It is derived
* from Fred N. van Kempen's arp command.
*
* Version: $Id: rarp.c,v 1.9 2007/12/02 02:19:52 ecki Exp $
*
* Usage: rarp -d hostname Delete entry
* rarp -s hostname ethernet_address Add entry
* rarp -a Print entries
* rarp -f Add frop /etc/ethers
*
* Rewritten: Phil Blundell <Philip.Blundell@pobox.com> 1997-08-03
* gettext instead of catgets: Arnaldo Carvalho de Melo <acme@conectiva.com.br> 1998-06-29
* 1998-01-01 Bernd Eckenfels reorganised usage()
* 2001-04-04 Arnaldo Carvalho de Melo - use setlocale
*
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#define DFLT_HW "ether"
#include "config.h"
#include "intl.h"
#include "net-support.h"
#include "version.h"
#include "pathnames.h"
#include "proc.h"
static char no_rarp_message[] = N_("This kernel does not support RARP.\n");
static char *Release = RELEASE;
static const struct hwtype *hardware = NULL;
/* Delete an entry from the RARP cache. */
static int rarp_delete(int fd, struct hostent *hp)
{
struct arpreq req;
struct sockaddr_in *si;
unsigned int found = 0;
char **addr;
/* The host can have more than one address, so we loop on them. */
for (addr = hp->h_addr_list; *addr != NULL; addr++) {
memset((char *) &req, 0, sizeof(req));
si = (struct sockaddr_in *) &req.arp_pa;
si->sin_family = hp->h_addrtype;
memcpy((char *) &si->sin_addr, *addr, hp->h_length);
/* Call the kernel. */
if (ioctl(fd, SIOCDRARP, &req) == 0) {
found++;
} else {
switch (errno) {
case ENXIO:
break;
case ENODEV:
fputs(_(no_rarp_message), stderr);
return 1;
default:
perror("SIOCDRARP");
return 1;
}
}
}
if (found == 0)
printf(_("no RARP entry for %s.\n"), hp->h_name);
return 0;
}
/* Set an entry in the RARP cache. */
static int rarp_set(int fd, struct hostent *hp, char *hw_addr)
{
struct arpreq req;
struct sockaddr_in *si;
struct sockaddr_storage sas;
struct sockaddr *sap = (struct sockaddr *)&sas;
if (hardware->input(hw_addr, &sas)) {
fprintf(stderr, _("%s: bad hardware address\n"), hw_addr);
return 1;
}
/* Clear and fill in the request block. */
memset((char *) &req, 0, sizeof(req));
si = (struct sockaddr_in *) &req.arp_pa;
si->sin_family = hp->h_addrtype;
memcpy((char *) &si->sin_addr, hp->h_addr_list[0], hp->h_length);
req.arp_ha.sa_family = hardware->type;
memcpy(req.arp_ha.sa_data, sap->sa_data, hardware->alen);
/* Call the kernel. */
if (ioctl(fd, SIOCSRARP, &req) < 0) {
if (errno == ENODEV)
fputs(_(no_rarp_message), stderr);
else
perror("SIOCSRARP");
return 1;
}
return 0;
}
/* Process an EtherFile */
static int rarp_file(int fd, const char *name)
{
char buff[1024];
char *host, *addr;
int linenr;
FILE *fp;
struct hostent *hp;
if ((fp = fopen(name, "r")) == NULL) {
fprintf(stderr, _("rarp: cannot open file %s:%s.\n"), name, strerror(errno));
return -1;
}
/* Read the lines in the file. */
linenr = 0;
while (fgets(buff, sizeof(buff), fp)) {
++linenr;
if (buff[0] == '#' || buff[0] == '\0')
continue;
if ((addr = strtok(buff, "\n \t")) == NULL)
continue;
if ((host = strtok(NULL, "\n \t")) == NULL) {
fprintf(stderr, _("rarp: format error at %s:%u\n"), name, linenr);
continue;
}
if ((hp = gethostbyname(host)) == NULL) {
fprintf(stderr, _("rarp: %s: unknown host\n"), host);
}
if (rarp_set(fd, hp, addr) != 0) {
fprintf(stderr, _("rarp: cannot set entry from %s:%u\n"), name, linenr);
}
}
(void) fclose(fp);
return 0;
}
static int display_cache(void)
{
FILE *fd = proc_fopen(_PATH_PROCNET_RARP);
char buffer[256];
if (fd == NULL) {
if (errno == ENOENT)
fputs(_(no_rarp_message), stderr);
else
perror(_PATH_PROCNET_RARP);
return 1;
}
while (feof(fd) == 0) {
if (fgets(buffer, 255, fd))
fputs(buffer, stdout);
}
fclose(fd);
return 0;
}
static void usage(int rc)
{
FILE *fp = rc ? stderr : stdout;
fprintf(fp, _("Usage: rarp -a list entries in cache.\n"));
fprintf(fp, _(" rarp -d <hostname> delete entry from cache.\n"));
fprintf(fp, _(" rarp [<HW>] -s <hostname> <hwaddr> add entry to cache.\n"));
fprintf(fp, _(" rarp -f add entries from /etc/ethers.\n"));
fprintf(fp, _(" rarp -V display program version.\n\n"));
fprintf(fp, _(" <HW>=Use '-H <hw>' to specify hardware address type. Default: %s\n"), DFLT_HW);
fprintf(fp, _(" List of possible hardware types (which support ARP):\n"));
print_hwlist(1); /* 1 = ARPable */
exit(rc);
}
#define MODE_DISPLAY 1
#define MODE_DELETE 2
#define MODE_SET 3
#define MODE_ETHERS 4
static struct option longopts[] =
{
{"version", 0, NULL, 'V'},
{"verbose", 0, NULL, 'v'},
{"list", 0, NULL, 'a'},
{"set", 0, NULL, 's'},
{"delete", 0, NULL, 'd'},
{"help", 0, NULL, 'h'},
{NULL, 0, NULL, 0}
};
int main(int argc, char **argv)
{
int result = 0, mode = 0, c, nargs = 0, verbose = 0;
char *args[3];
struct hostent *hp;
int fd;
#if I18N
setlocale (LC_ALL, "");
bindtextdomain("net-tools", "/usr/share/locale");
textdomain("net-tools");
#endif
/* Get a default hardware type. */
hardware = get_hwtype(DFLT_HW);
do {
c = getopt_long(argc, argv, "-ht:aHdsVvf", longopts, NULL);
switch (c) {
case EOF:
break;
case 'h':
usage(E_USAGE);
case 'V':
printf("%s\n", Release);
exit(E_VERSION);
break;
case 'v':
verbose++;
break;
case 'a':
case 's':
case 'd':
if (mode) {
fprintf(stderr, _("%s: illegal option mix.\n"), argv[0]);
usage(E_OPTERR);
} else {
mode = (c == 'a' ? MODE_DISPLAY : (c == 'd' ? MODE_DELETE : MODE_SET));
}
break;
case 'f':
mode = MODE_ETHERS;
break;
case 'H':
case 't':
if (optarg) {
hardware = get_hwtype(optarg);
} else {
usage(E_OPTERR);
}
break;
case 1:
if (nargs == 2) {
usage(E_OPTERR);
exit(1);
} else {
args[nargs++] = optarg;
}
break;
default:
usage(E_OPTERR);
}
} while (c != EOF);
if (hardware == NULL) {
fprintf(stderr, _("rarp: %s: unknown hardware type.\n"), optarg);
exit(1);
}
switch (mode) {
case 0:
usage(E_OPTERR);
case MODE_DISPLAY:
if (nargs != (mode - 1)) {
usage(E_OPTERR);
}
result = display_cache();
break;
case MODE_DELETE:
case MODE_SET:
if (nargs != (mode - 1)) {
usage(E_OPTERR);
}
if ((hp = gethostbyname(args[0])) == NULL) {
fprintf(stderr, _("rarp: %s: unknown host\n"), args[0]);
exit(1);
}
if (fd = socket(PF_INET, SOCK_DGRAM, 0), fd < 0) {
perror("socket");
exit(1);
}
result = (mode == MODE_DELETE) ? rarp_delete(fd, hp) : rarp_set(fd, hp, args[1]);
close(fd);
break;
case MODE_ETHERS:
if (nargs != 0 && nargs != 1)
usage(E_OPTERR);
if (fd = socket(PF_INET, SOCK_DGRAM, 0), fd < 0) {
perror("socket");
exit(1);
}
result = rarp_file(fd, nargs ? args[0] : _PATH_ETHERS);
close(fd);
}
exit(result);
}