From 9a90d9b9119906df23cb2db1503cb0f099942dd9 Mon Sep 17 00:00:00 2001
From: Mats Erik Andersson <gnu@gisladisker.se>
Date: Sat, 18 Jul 2015 01:12:41 +0200
Subject: [PATCH 02/60] ifconfig: Improve the support for GNU/Hurd.

Use system specific code instead of generic code.
This provides abilities similar to other systems.
---
 ChangeLog                   |  17 +++
 ifconfig/system.c           |  10 +-
 ifconfig/system.h           |   2 +
 ifconfig/system/Makefile.am |   4 +-
 ifconfig/system/generic.c   |  14 +-
 ifconfig/system/hurd.c      | 292 ++++++++++++++++++++++++++++++++++++
 ifconfig/system/hurd.h      |  50 ++++++
 7 files changed, 381 insertions(+), 8 deletions(-)
 create mode 100644 ifconfig/system/hurd.c
 create mode 100644 ifconfig/system/hurd.h

diff --git a/ChangeLog b/ChangeLog
index 7f799daa..18a584ba 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2015-07-18  Mats Erik Andersson  <gnu@gisladisker.se>
+
+	ifconfig: Improve the support for GNU/Hurd.
+	Add system specific abilities, including parsing of command
+	line and hardware addresses.
+
+	* ifconfig/system.h [__GNU__]: Include "system/hurd.h".
+	* ifconfig/system.c [__GNU__]: Include "system/hurd.c".
+	* ifconfig/system/Makefile.am (noinst_HEADERS): Add the
+	files `hurd.h' and `hurd.c'.
+	* ifconfig/system/hurd.h, ifconfig/system/hurd.c: New files.
+
+	* ifconfig/system/generic.c: Include <unused-parameter.h>.
+	(system_parse_opt, system_parse_opt_rest, system_configure):
+	Apply _GL_UNUSED_PARAMETER to all arguments, as these functions
+	are placeholders and no-ops.
+
 2015-07-17  Mats Erik Andersson  <gnu@gisladisker.se>
 
 	ifconfig: Sporadically appearing regression.
diff --git a/ifconfig/system.c b/ifconfig/system.c
index 30677e41..e108dc2e 100644
--- a/ifconfig/system.c
+++ b/ifconfig/system.c
@@ -25,10 +25,12 @@
 # include "system/solaris.c"
 #elif defined __QNX__
 # include "system/qnx.c"
-# elif defined __DragonFly__ || defined __FreeBSD__ || \
-       defined __FreeBSD_kernel__ || \
-       defined __NetBSD__ || defined __OpenBSD__
-#  include "system/bsd.c"
+#elif defined __DragonFly__ || defined __FreeBSD__ || \
+      defined __FreeBSD_kernel__ || \
+      defined __NetBSD__ || defined __OpenBSD__
+# include "system/bsd.c"
+#elif defined __GNU__
+# include "system/hurd.c"
 #else
 # include "system/generic.c"
 #endif
diff --git a/ifconfig/system.h b/ifconfig/system.h
index 8521ad95..66878d3a 100644
--- a/ifconfig/system.h
+++ b/ifconfig/system.h
@@ -97,6 +97,8 @@ extern struct if_nameindex* (*system_if_nameindex) (void);
        defined __FreeBSD_kernel__ || \
        defined __NetBSD__ || defined __OpenBSD__
 #  include "system/bsd.h"
+# elif defined __GNU__
+#  include "system/hurd.h"
 # else
 #  include "system/generic.h"
 # endif
diff --git a/ifconfig/system/Makefile.am b/ifconfig/system/Makefile.am
index 954c6774..62a9f1c4 100644
--- a/ifconfig/system/Makefile.am
+++ b/ifconfig/system/Makefile.am
@@ -26,8 +26,10 @@ noinst_HEADERS = \
 	linux.h \
 	solaris.h \
 	qnx.h \
+	hurd.h \
 	bsd.c \
 	generic.c \
 	linux.c \
 	solaris.c \
-	qnx.c
+	qnx.c \
+	hurd.c
diff --git a/ifconfig/system/generic.c b/ifconfig/system/generic.c
index 9a2bda55..20a78bde 100644
--- a/ifconfig/system/generic.c
+++ b/ifconfig/system/generic.c
@@ -22,6 +22,8 @@
 #include <config.h>
 
 #include "../ifconfig.h"
+
+#include <unused-parameter.h>
 
 
 /* Output format stuff.  */
@@ -36,19 +38,25 @@ const char *system_help;
 struct argp_child system_argp_child;
 
 int
-system_parse_opt (struct ifconfig **ifp, char option, char *optarg)
+system_parse_opt (struct ifconfig **ifp _GL_UNUSED_PARAMETER,
+		  char option _GL_UNUSED_PARAMETER,
+		  char *optarg _GL_UNUSED_PARAMETER)
 {
   return 0;
 }
 
 int
-system_parse_opt_rest (struct ifconfig **ifp, int argc, char *argv[])
+system_parse_opt_rest (struct ifconfig **ifp _GL_UNUSED_PARAMETER,
+		       int argc _GL_UNUSED_PARAMETER,
+		       char *argv[] _GL_UNUSED_PARAMETER)
 {
   return 0;
 }
 
 int
-system_configure (int sfd, struct ifreq *ifr, struct system_ifconfig *ifs)
+system_configure (int sfd _GL_UNUSED_PARAMETER,
+		  struct ifreq *ifr _GL_UNUSED_PARAMETER,
+		  struct system_ifconfig *ifs _GL_UNUSED_PARAMETER)
 {
   return 0;
 }
diff --git a/ifconfig/system/hurd.c b/ifconfig/system/hurd.c
new file mode 100644
index 00000000..3bd19775
--- /dev/null
+++ b/ifconfig/system/hurd.c
@@ -0,0 +1,292 @@
+/* hurd.c -- Code for ifconfig specific to GNU/Hurd.
+  Copyright (C) 2015 Free Software Foundation, Inc.
+
+  This file is part of GNU Inetutils.
+
+  GNU Inetutils is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or (at
+  your option) any later version.
+
+  GNU Inetutils is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see `http://www.gnu.org/licenses/'. */
+
+/* Mostly written by Marcus Brinkmann.
+   Adaptions to GNU/Hurd by Mats Erik Andersson.  */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <net/if_arp.h>
+#include "../ifconfig.h"
+
+#include <unused-parameter.h>
+
+
+/* Output format stuff.  */
+
+const char *system_default_format = "gnu";
+
+
+/* Argument parsing stuff.  */
+
+const char *system_help = "NAME [ADDR]\
+ [broadcast BRDADDR] [netmask MASK]\
+ [mtu N] [up|down] [FLAGS]";
+
+struct argp_child system_argp_child;
+
+int
+system_parse_opt (struct ifconfig **ifp _GL_UNUSED_PARAMETER,
+		  char option _GL_UNUSED_PARAMETER,
+		  char *optarg _GL_UNUSED_PARAMETER)
+{
+  return 0;
+}
+
+int
+system_parse_opt_rest (struct ifconfig **ifp, int argc, char *argv[])
+{
+  int i = 0, mask, rev;
+  enum {
+    EXPECT_NOTHING,
+    EXPECT_AF,
+    EXPECT_BROADCAST,
+    EXPECT_NETMASK,
+    EXPECT_METRIC,
+    EXPECT_MTU
+  } expect = EXPECT_AF;
+
+  *ifp = parse_opt_new_ifs (argv[0]);
+
+  while (++i < argc)
+    {
+      switch (expect)
+	{
+	case EXPECT_BROADCAST:
+	  parse_opt_set_brdaddr (*ifp, argv[i]);
+	  break;
+
+	case EXPECT_NETMASK:
+	  parse_opt_set_netmask (*ifp, argv[i]);
+	  break;
+
+	case EXPECT_MTU:
+	  parse_opt_set_mtu (*ifp, argv[i]);
+	  break;
+
+	/* XXX: 2015-07-18, GNU/Hurd does not yet support
+		ioctl(SIOCSIFMETRIC), but we let the code
+		handle this standard ability anyway!
+	 */
+	case EXPECT_METRIC:
+	  parse_opt_set_metric (*ifp, argv[i]);
+	  break;
+
+	case EXPECT_AF:
+	  expect = EXPECT_NOTHING;
+	  if (!strcmp (argv[i], "inet"))
+	    continue;
+	  else if (!strcmp (argv[i], "inet6"))
+	    {
+	      error (0, 0, "%s is not a supported address family", argv[i]);
+	      return 0;
+	    }
+	  break;
+
+	case EXPECT_NOTHING:
+	  break;
+	}
+
+      if (expect != EXPECT_NOTHING)
+	expect = EXPECT_NOTHING;
+      else if (!strcmp (argv[i], "broadcast"))
+	expect = EXPECT_BROADCAST;
+      else if (!strcmp (argv[i], "netmask"))
+	expect = EXPECT_NETMASK;
+      else if (!strcmp (argv[i], "metric"))
+	expect = EXPECT_METRIC;
+      else if (!strcmp (argv[i], "mtu"))
+	expect = EXPECT_MTU;
+      else if (!strcmp (argv[i], "up"))
+	parse_opt_set_flag (*ifp, IFF_UP | IFF_RUNNING, 0);
+      else if (!strcmp (argv[i], "down"))
+	parse_opt_set_flag (*ifp, IFF_UP, 1);
+      else if (((mask = if_nameztoflag (argv[i], &rev))
+		& ~IU_IFF_CANTCHANGE) != 0)
+	parse_opt_set_flag (*ifp, mask, rev);
+      else
+	{
+	  if (!((*ifp)->valid & IF_VALID_ADDR))
+	    parse_opt_set_address (*ifp, argv[i]);
+	  else if (!((*ifp)->valid & IF_VALID_DSTADDR))
+	    parse_opt_set_dstaddr (*ifp, argv[i]);
+	}
+    }
+
+  switch (expect)
+    {
+    case EXPECT_BROADCAST:
+      error (0, 0, "option `broadcast' requires an argument");
+      break;
+
+    case EXPECT_NETMASK:
+      error (0, 0, "option `netmask' requires an argument");
+      break;
+
+    case EXPECT_METRIC:
+      error (0, 0, "option `metric' requires an argument");
+      break;
+
+    case EXPECT_MTU:
+      error (0, 0, "option `mtu' requires an argument");
+      break;
+
+    case EXPECT_AF:
+    case EXPECT_NOTHING:
+      return 1;
+    }
+
+  return 0;
+}
+
+int
+system_configure (int sfd _GL_UNUSED_PARAMETER,
+		  struct ifreq *ifr _GL_UNUSED_PARAMETER,
+		  struct system_ifconfig *ifs _GL_UNUSED_PARAMETER)
+{
+  return 0;
+}
+
+struct if_nameindex* (*system_if_nameindex) (void) = if_nameindex;
+
+static void
+print_hwaddr_ether (format_data_t form _GL_UNUSED_PARAMETER,
+		    unsigned char *data)
+{
+  *column += printf ("%02X:%02X:%02X:%02X:%02X:%02X",
+		     data[0], data[1], data[2], data[3], data[4], data[5]);
+  had_output = 1;
+}
+
+struct arphrd_symbol
+{
+  const char *name;
+  const char *title;
+  int value;
+  void (*print_hwaddr) (format_data_t form, unsigned char *data);
+} arphrd_symbols[] =
+  {
+#ifdef ARPHRD_ETHER		/* Ethernet 10/100Mbps.  */
+    { "ETHER", "Ethernet", ARPHRD_ETHER, print_hwaddr_ether},
+#endif
+#ifdef ARPHRD_LOOPBACK		/* Loopback device.  */
+    { "LOOPBACK", "Local Loopback", ARPHRD_LOOPBACK, NULL},
+#endif
+    /* XXX: The image debian-hurd-20150424 returns the value 4
+	    instead of expected ARPHRD_LOOPBACK.  This has been
+	    discussed in the list debian-hurd, where I was asked
+	    to resist the temptation of a work around!
+     */
+    { NULL, NULL, 0, NULL}
+  };
+
+struct arphrd_symbol *
+arphrd_findvalue (int value)
+{
+  struct arphrd_symbol *arp = arphrd_symbols;
+  while (arp->name != NULL)
+    {
+      if (arp->value == value)
+	break;
+      arp++;
+    }
+  if (arp->name)
+    return arp;
+  else
+    return NULL;
+}
+
+void
+system_fh_hwaddr_query (format_data_t form, int argc, char *argv[])
+{
+#ifdef SIOCGIFHWADDR
+  struct arphrd_symbol *arp;
+
+  if (ioctl (form->sfd, SIOCGIFHWADDR, form->ifr) < 0)
+    select_arg (form, argc, argv, 1);
+
+  arp = arphrd_findvalue (form->ifr->ifr_hwaddr.sa_family);
+  select_arg (form, argc, argv, (arp && arp->print_hwaddr) ? 0 : 1);
+#else
+  select_arg (form, argc, argv, 1);
+#endif
+}
+
+void
+system_fh_hwaddr (format_data_t form, int argc _GL_UNUSED_PARAMETER,
+		  char *argv[] _GL_UNUSED_PARAMETER)
+{
+#ifdef SIOCGIFHWADDR
+  if (ioctl (form->sfd, SIOCGIFHWADDR, form->ifr) < 0)
+    error (EXIT_FAILURE, errno,
+	   "SIOCGIFHWADDR failed for interface `%s'",
+	   form->ifr->ifr_name);
+  else
+    {
+      struct arphrd_symbol *arp;
+
+      arp = arphrd_findvalue (form->ifr->ifr_hwaddr.sa_family);
+      if (arp && arp->print_hwaddr)
+	arp->print_hwaddr (form,
+			   (unsigned char *) form->ifr->ifr_hwaddr.sa_data);
+      else
+	put_string (form, "(hwaddr unknown)");
+    }
+#else
+  *column += printf ("(not available)");
+  had_output = 1;
+#endif
+}
+
+void
+system_fh_hwtype_query (format_data_t form, int argc, char *argv[])
+{
+#ifdef SIOCGIFHWADDR
+  if (ioctl (form->sfd, SIOCGIFHWADDR, form->ifr) >= 0)
+    select_arg (form, argc, argv, 0);
+  else
+#endif
+    select_arg (form, argc, argv, 1);
+}
+
+void
+system_fh_hwtype (format_data_t form, int argc _GL_UNUSED_PARAMETER,
+		  char *argv[] _GL_UNUSED_PARAMETER)
+{
+#ifdef SIOCGIFHWADDR
+  if (ioctl (form->sfd, SIOCGIFHWADDR, form->ifr) < 0)
+    error (EXIT_FAILURE, errno,
+	   "SIOCGIFHWADDR failed for interface `%s'",
+	   form->ifr->ifr_name);
+  else
+    {
+      struct arphrd_symbol *arp;
+
+      arp = arphrd_findvalue (form->ifr->ifr_hwaddr.sa_family);
+      if (arp)
+	put_string (form, arp->title);
+      else
+	put_string (form, "(hwtype unknown)");
+    }
+#else
+  *column += printf ("(not available)");
+  had_output = 1;
+#endif
+}
diff --git a/ifconfig/system/hurd.h b/ifconfig/system/hurd.h
new file mode 100644
index 00000000..bab14565
--- /dev/null
+++ b/ifconfig/system/hurd.h
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2015 Free Software Foundation, Inc.
+
+  This file is part of GNU Inetutils.
+
+  GNU Inetutils is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or (at
+  your option) any later version.
+
+  GNU Inetutils is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see `http://www.gnu.org/licenses/'. */
+
+/* Written by Mats Erik Andersson.  */
+
+#ifndef IFCONFIG_SYSTEM_HURD_H
+# define IFCONFIG_SYSTEM_HURD_H
+
+# include "../printif.h"
+# include "../options.h"
+
+
+/* Option support.  */
+
+struct system_ifconfig
+{
+  int valid;
+};
+
+
+/* Output format support.  */
+
+# define SYSTEM_FORMAT_HANDLER \
+  { "hurd", fh_nothing}, \
+  { "hwaddr?", system_fh_hwaddr_query}, \
+  { "hwaddr", system_fh_hwaddr}, \
+  { "hwtype?", system_fh_hwtype_query}, \
+  { "hwtype", system_fh_hwtype},
+
+void system_fh_hwaddr_query (format_data_t form, int argc, char *argv[]);
+void system_fh_hwaddr (format_data_t form, int argc, char *argv[]);
+void system_fh_hwtype_query (format_data_t form, int argc, char *argv[]);
+void system_fh_hwtype (format_data_t form, int argc, char *argv[]);
+
+#endif /* !IFCONFIG_SYSTEM_HURD_H */
-- 
2.26.0.292.g33ef6b2f38

