summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/netinet/ether.h2
-rw-r--r--libc/inet/Makefile.in2
-rwxr-xr-xlibc/inet/ethers.c122
-rwxr-xr-xtest/inet/tst-ethers-line.c45
-rwxr-xr-xtest/inet/tst-ethers.c28
5 files changed, 198 insertions, 1 deletions
diff --git a/include/netinet/ether.h b/include/netinet/ether.h
index ca780e2d0..a16255037 100644
--- a/include/netinet/ether.h
+++ b/include/netinet/ether.h
@@ -25,6 +25,8 @@
/* Get definition of `struct ether_addr'. */
#include <netinet/if_ether.h>
+#define ETHER_FILE_NAME "/etc/ethers"
+
__BEGIN_DECLS
/* Convert 48 bit Ethernet ADDRess to ASCII. */
diff --git a/libc/inet/Makefile.in b/libc/inet/Makefile.in
index 8cb8661c4..b1ea25b26 100644
--- a/libc/inet/Makefile.in
+++ b/libc/inet/Makefile.in
@@ -23,7 +23,7 @@ CSRC += encodeh.c decodeh.c encoded.c decoded.c lengthd.c encodeq.c \
res_query.c gethostbyaddr.c read_etc_hosts_r.c get_hosts_byname_r.c \
get_hosts_byaddr_r.c gethostbyname2.c getnameinfo.c gethostent.c \
gethostbyname_r.c gethostbyname2_r.c gethostbyaddr_r.c \
- res_comp.c ns_name.c
+ res_comp.c ns_name.c ethers.c
# unused ATM
CSRC += encodep.c decodep.c formquery.c
diff --git a/libc/inet/ethers.c b/libc/inet/ethers.c
new file mode 100755
index 000000000..857e5d165
--- /dev/null
+++ b/libc/inet/ethers.c
@@ -0,0 +1,122 @@
+/*
+ * libc/inet/ethers.c
+ *
+ * Programmatic interface for the /etc/ethers file
+ *
+ * Copyright 2007 by Matthew Wilcox <matthew@wil.cx>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <netinet/ether.h>
+
+#define ETHER_LINE_LEN 256
+
+/*
+ * Internal function which returns a pointer to the part of the line
+ * with the start of the hostname, or NULL if we couldn't parse the line.
+ * Note that this line may have a comment symbol on it somewhere; if so
+ * it will return NULL if the # is before or within the ether_addr, and
+ * succeed if the # is before or within the host. It's up to the callers
+ * to be aware of this.
+ *
+ * I would have preferred to write a NUL to the location of the comment
+ * character, but ether_line takes a const argument. See __ether_line_w.
+ */
+static const char *__ether_line(const char *line, struct ether_addr *addr)
+{
+ struct ether_addr *res = ether_aton_r(line, addr);
+ if (!res)
+ return NULL;
+
+ while (*line && (*line != ' ') && (*line != '\t'))
+ line++;
+ while (*line && ((*line == ' ') || (*line == '\t')))
+ line++;
+ return (*line) ? line : NULL;
+}
+
+/*
+ * Strips out the comment before calling __ether_line. We can do this,
+ * since we know the buffer is writable.
+ */
+static const char *__ether_line_w(char *line, struct ether_addr *addr)
+{
+ char *end = strchr(line, '#');
+ if (!end)
+ end = strchr(line, '\n');
+ if (end)
+ *end = '\0';
+ return __ether_line(line, addr);
+}
+
+int ether_line(const char *line, struct ether_addr *addr, char *hostname)
+{
+ const char *name = __ether_line(line, addr);
+ if (!name)
+ return -1;
+
+ while (*name) {
+ if ((*name == '#') || isspace(*name))
+ break;
+ *hostname++ = *name++;
+ }
+ *hostname = '\0';
+
+ return 0;
+}
+
+int ether_ntohost(char *hostname, const struct ether_addr *addr)
+{
+ int res = -1;
+ FILE *fp;
+ char buf[ETHER_LINE_LEN];
+
+ fp = fopen(ETHER_FILE_NAME, "r");
+ if (!fp)
+ return -1;
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ struct ether_addr tmp_addr;
+ const char *cp = __ether_line_w(buf, &tmp_addr);
+ if (!cp)
+ continue;
+ if (memcmp(addr, &tmp_addr, sizeof(tmp_addr)))
+ continue;
+
+ strcpy(hostname, cp);
+ res = 0;
+ break;
+ }
+
+ fclose(fp);
+ return res;
+}
+
+int ether_hostton(const char *hostname, struct ether_addr *addr)
+{
+ int res = -1;
+ FILE *fp;
+ char buf[ETHER_LINE_LEN];
+
+ fp = fopen(ETHER_FILE_NAME, "r");
+ if (!fp)
+ return -1;
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ const char *cp = __ether_line_w(buf, addr);
+ if (!cp)
+ continue;
+ if (strcasecmp(hostname, cp))
+ continue;
+
+ res = 0;
+ break;
+ }
+
+ fclose(fp);
+ return res;
+}
diff --git a/test/inet/tst-ethers-line.c b/test/inet/tst-ethers-line.c
new file mode 100755
index 000000000..d4835b546
--- /dev/null
+++ b/test/inet/tst-ethers-line.c
@@ -0,0 +1,45 @@
+#include <netinet/ether.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#define ETHER_LINE_LEN 256
+
+int main(void)
+{
+ struct ether_addr addr;
+ char hostname[ETHER_LINE_LEN];
+ int fd, i;
+ const char *ethers;
+ struct stat statb;
+
+ if ((fd = open(ETHER_FILE_NAME, O_RDONLY)) == -1) {
+ perror ("Cannot open file");
+ exit(1);
+ }
+
+ if (fstat(fd, &statb)) {
+ perror("Stat failed");
+ exit(1);
+ }
+ ethers = mmap(NULL, statb.st_size, PROT_READ, MAP_SHARED, fd, 0);
+
+ if (ethers == MAP_FAILED) {
+ perror("File mapping failed");
+ exit(1);
+ }
+
+ ether_line(ethers, &addr, hostname);
+
+ for (i = 0; i < 6; i++) {
+ printf("%02x", addr.ether_addr_octet[i]);
+ if (i < 5)
+ printf(":");
+ }
+ printf(" %s\n", hostname);
+
+ return 0;
+}
diff --git a/test/inet/tst-ethers.c b/test/inet/tst-ethers.c
new file mode 100755
index 000000000..eb6280c3f
--- /dev/null
+++ b/test/inet/tst-ethers.c
@@ -0,0 +1,28 @@
+#include <netinet/ether.h>
+#include <stdio.h>
+
+#define ETHER_LINE_LEN 256
+
+int main(void)
+{
+ struct ether_addr addr;
+ char host[ETHER_LINE_LEN];
+ int i;
+ int res = ether_hostton("teeth", &addr);
+
+ if (res)
+ return 1;
+
+ for (i = 0; i < 6; i++) {
+ printf("%02x", addr.ether_addr_octet[i]);
+ if (i < 5)
+ printf(":");
+ }
+
+ res = ether_ntohost(host, &addr);
+ if (res)
+ return 1;
+ printf(" %s\n", host);
+
+ return 0;
+}