From owner-svn-src-all@freebsd.org Thu Jun 4 14:44:45 2020 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id AEAF02F64CC; Thu, 4 Jun 2020 14:44:45 +0000 (UTC) (envelope-from eugen@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 49d7pj49NWz40qn; Thu, 4 Jun 2020 14:44:45 +0000 (UTC) (envelope-from eugen@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 8A3C221122; Thu, 4 Jun 2020 14:44:45 +0000 (UTC) (envelope-from eugen@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 054Eij7o047938; Thu, 4 Jun 2020 14:44:45 GMT (envelope-from eugen@FreeBSD.org) Received: (from eugen@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 054EijxB047937; Thu, 4 Jun 2020 14:44:45 GMT (envelope-from eugen@FreeBSD.org) Message-Id: <202006041444.054EijxB047937@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: eugen set sender to eugen@FreeBSD.org using -f From: Eugene Grosbein Date: Thu, 4 Jun 2020 14:44:45 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r361790 - head/sbin/ifconfig X-SVN-Group: head X-SVN-Commit-Author: eugen X-SVN-Commit-Paths: head/sbin/ifconfig X-SVN-Commit-Revision: 361790 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.33 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 04 Jun 2020 14:44:45 -0000 Author: eugen Date: Thu Jun 4 14:44:44 2020 New Revision: 361790 URL: https://svnweb.freebsd.org/changeset/base/361790 Log: ifconfig(8): make it possible to filter output by interface group. Now options -g/-G allow to select/unselect interfaces by groups in the "ifconfig -a" output just like already existing -d/-u. Examples: to exclude loopback from the list: ifconfig -a -G lo to show vlan interfaces only: ifconfig -a -g vlan to show tap interfaces that are up: ifconfig -aug tap Arguments to -g/-G may be shell patterns and both may be specified. Later options -g/-G override previous ones. MFC after: 2 weeks Relnotes: yes Differential Revision: https://reviews.freebsd.org/D25029 Modified: head/sbin/ifconfig/ifconfig.8 head/sbin/ifconfig/ifconfig.c Modified: head/sbin/ifconfig/ifconfig.8 ============================================================================== --- head/sbin/ifconfig/ifconfig.8 Thu Jun 4 14:15:39 2020 (r361789) +++ head/sbin/ifconfig/ifconfig.8 Thu Jun 4 14:44:44 2020 (r361790) @@ -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 Modified: head/sbin/ifconfig/ifconfig.c ============================================================================== --- head/sbin/ifconfig/ifconfig.c Thu Jun 4 14:15:39 2020 (r361789) +++ head/sbin/ifconfig/ifconfig.c Thu Jun 4 14:44:44 2020 (r361790) @@ -63,6 +63,7 @@ static const char rcsid[] = #include #include +#include #include #include #include @@ -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? */ @@ -668,6 +687,73 @@ main(int argc, char *argv[]) done: freeformat(); 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;