aboutsummaryrefslogtreecommitdiff
path: root/sbin/ifconfig
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/ifconfig')
-rw-r--r--sbin/ifconfig/ifconfig.825
-rw-r--r--sbin/ifconfig/ifconfig.c90
2 files changed, 111 insertions, 4 deletions
diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8
index 0fde75a2f654..a31bd9c81615 100644
--- a/sbin/ifconfig/ifconfig.8
+++ b/sbin/ifconfig/ifconfig.8
@@ -56,6 +56,7 @@
.Fl a
.Op Fl L
.Op Fl d
+.Op Fl [gG] Ar groupname
.Op Fl m
.Op Fl u
.Op Fl v
@@ -2910,9 +2911,26 @@ This flag instructs
to display information about all interfaces in the system.
The
.Fl d
-flag limits this to interfaces that are down, and
+flag limits this to interfaces that are down,
.Fl u
-limits this to interfaces that are up.
+limits this to interfaces that are up,
+limits this to interfaces that are up,
+.Fl g
+limits this to members of the specified group of interfaces, and
+.Fl G
+excludes members of the specified group from the list.
+Both
+.Fl g
+and
+.Fl G
+flags may be specified to apply both conditions.
+Only one option
+.Fl g
+should be specified as later override previous ones
+(same for
+.Fl G ) .
+.Sy groupname
+may contain shell patterns in which case it should be quoted.
When no arguments are given,
.Fl a
is implied.
@@ -3036,6 +3054,9 @@ Display available wireless networks using
.Pp
Display inet and inet6 address subnet masks in CIDR notation
.Dl # ifconfig -f inet:cidr,inet6:cidr
+.Pp
+Display interfaces that are up with the exception of loopback
+.Dl # ifconfig -a -u -G lo
.Sh DIAGNOSTICS
Messages indicating the specified interface does not exist, the
requested address is unknown, or the user is not privileged and
diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c
index 78fc6a7e1e1e..0aa73b095a57 100644
--- a/sbin/ifconfig/ifconfig.c
+++ b/sbin/ifconfig/ifconfig.c
@@ -63,6 +63,7 @@ static const char rcsid[] =
#include <arpa/inet.h>
#include <netdb.h>
+#include <fnmatch.h>
#include <ifaddrs.h>
#include <ctype.h>
#include <err.h>
@@ -105,6 +106,8 @@ int exit_code = 0;
/* Formatter Strings */
char *f_inet, *f_inet6, *f_ether, *f_addr;
+static bool group_member(const char *ifname, const char *match,
+ const char *nomatch);
static int ifconfig(int argc, char *const *argv, int iscreate,
const struct afswtch *afp);
static void status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
@@ -402,13 +405,14 @@ main(int argc, char *argv[])
char options[1024], *cp, *envformat, *namecp = NULL;
struct ifa_queue q = TAILQ_HEAD_INITIALIZER(q);
struct ifa_order_elt *cur, *tmp;
- const char *ifname;
+ const char *ifname, *matchgroup, *nogroup;
struct option *p;
size_t iflen;
int flags;
all = downonly = uponly = namesonly = noload = verbose = 0;
f_inet = f_inet6 = f_ether = f_addr = NULL;
+ matchgroup = nogroup = NULL;
envformat = getenv("IFCONFIG_FORMAT");
if (envformat != NULL)
@@ -421,7 +425,7 @@ main(int argc, char *argv[])
atexit(printifnamemaybe);
/* Parse leading line options */
- strlcpy(options, "f:adklmnuv", sizeof(options));
+ strlcpy(options, "G:adf:klmnuv", sizeof(options));
for (p = opts; p != NULL; p = p->next)
strlcat(options, p->opt, sizeof(options));
while ((c = getopt(argc, argv, options)) != -1) {
@@ -437,6 +441,11 @@ main(int argc, char *argv[])
usage();
setformat(optarg);
break;
+ case 'G':
+ if (optarg == NULL || all == 0)
+ usage();
+ nogroup = optarg;
+ break;
case 'k':
printkeys++;
break;
@@ -455,6 +464,14 @@ main(int argc, char *argv[])
case 'v':
verbose++;
break;
+ case 'g':
+ if (all) {
+ if (optarg == NULL)
+ usage();
+ matchgroup = optarg;
+ break;
+ }
+ /* FALLTHROUGH */
default:
for (p = opts; p != NULL; p = p->next)
if (p->opt[0] == c) {
@@ -626,6 +643,8 @@ main(int argc, char *argv[])
continue;
if (uponly && (ifa->ifa_flags & IFF_UP) == 0)
continue;
+ if (!group_member(ifa->ifa_name, matchgroup, nogroup))
+ continue;
/*
* Are we just listing the interfaces?
*/
@@ -670,6 +689,73 @@ done:
exit(exit_code);
}
+/*
+ * Returns true if an interface should be listed because any its groups
+ * matches shell pattern "match" and none of groups matches pattern "nomatch".
+ * If any pattern is NULL, corresponding condition is skipped.
+ */
+static bool
+group_member(const char *ifname, const char *match, const char *nomatch)
+{
+ static int sock = -1;
+
+ struct ifgroupreq ifgr;
+ struct ifg_req *ifg;
+ int len;
+ bool matched, nomatched;
+
+ /* Sanity checks. */
+ if (match == NULL && nomatch == NULL)
+ return (true);
+ if (ifname == NULL)
+ return (false);
+
+ memset(&ifgr, 0, sizeof(ifgr));
+ strlcpy(ifgr.ifgr_name, ifname, IFNAMSIZ);
+
+ /* The socket is opened once. Let _exit() close it. */
+ if (sock == -1) {
+ sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
+ if (sock == -1)
+ errx(1, "%s: socket(AF_LOCAL,SOCK_DGRAM)", __func__);
+ }
+
+ /* Determine amount of memory for the list of groups. */
+ if (ioctl(sock, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) {
+ if (errno == EINVAL || errno == ENOTTY)
+ return (false);
+ else
+ errx(1, "%s: SIOCGIFGROUP", __func__);
+ }
+
+ /* Obtain the list of groups. */
+ len = ifgr.ifgr_len;
+ ifgr.ifgr_groups =
+ (struct ifg_req *)calloc(len / sizeof(*ifg), sizeof(*ifg));
+
+ if (ifgr.ifgr_groups == NULL)
+ errx(1, "%s: no memory", __func__);
+ if (ioctl(sock, SIOCGIFGROUP, (caddr_t)&ifgr) == -1)
+ errx(1, "%s: SIOCGIFGROUP", __func__);
+
+ /* Perform matching. */
+ matched = false;
+ nomatched = true;
+ for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(*ifg); ifg++) {
+ len -= sizeof(struct ifg_req);
+ if (match)
+ matched |= !fnmatch(match, ifg->ifgrq_group, 0);
+ if (nomatch)
+ nomatched &= fnmatch(nomatch, ifg->ifgrq_group, 0);
+ }
+
+ if (match && !nomatch)
+ return (matched);
+ if (!match && nomatch)
+ return (nomatched);
+ return (matched && nomatched);
+}
+
static struct afswtch *afs = NULL;
void