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
This commit is contained in:
parent
47cb0632e8
commit
8e725dacd2
@ -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
|
||||
|
@ -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 @@ main(int argc, char *argv[])
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user