/* getif.c
 * program to display inet interace configuration
 * Copyright (C) 2002 Felix Müri
 *
 * This program is free software  you can redistribute it and/or modify
 * it under the terms of the GNU Felix Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
             
 * This program 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 Felix Public License for more details.
                             
 * You should have received a copy of the GNU Felix Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 * Version 1.0: 6. Oktober 2002
 */

#include <stdio.h>
#include <sys/ioctl.h>

/* Definition von ifreq (interface request structure) */
#include <net/if.h>
/* für getopt */
#include <unistd.h>
/* für socket */
#include <sys/types.h>
#include <sys/socket.h>

#include <arpa/inet.h>

int skfd;
char** args;
short int g_flags;
char g_addr[16], g_net[16], g_brd[16], g_hw[18];

/*****************************************************************************
 * allgemeine Funktionen
 *****************************************************************************/
void
version()
{
  printf("%s V1.0 (c) Felix Müri\n", args[0]);
}

void
usage()
{
  fprintf(stderr, "Usage:\n  %s [-v] [-a] [interface] ...\n",
		  args[0]);
}

/*****************************************************************************
 * do_one
 *****************************************************************************/
void
do_one(char* ifname)
{
  struct ifreq ifr;
  char *ptr;

  strncpy(ifr.ifr_name, ifname, IF_NAMESIZE);
  if(ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
    perror("SIOCGIFFLAGS");
    return;
  }
  g_flags = ifr.ifr_flags;

  /* hardware address */
  strncpy(ifr.ifr_name, ifname, IF_NAMESIZE);
  if(ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) {
	perror("SIOCGIFHWADDR");
	return;
  }
  ptr = (char *)&ifr.ifr_addr.sa_data;
  sprintf(g_hw, "%02X:%02X:%02X:%02X:%02X:%02X",
		  (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
		  (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377));

  if(g_flags & IFF_UP) {
    /* interface address */
    strncpy(ifr.ifr_name, ifname, IF_NAMESIZE);
    if(ioctl(skfd, SIOCGIFADDR, &ifr) < 0) {
      perror("SIOCGIFDADDR");
      return;
    }
    strcpy(g_addr, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
		
    /* netmask */
    strncpy(ifr.ifr_name, ifname, IF_NAMESIZE);
    if(ioctl(skfd, SIOCGIFNETMASK, &ifr) < 0) {
      perror("SIOCGIFNETMASK");
      return;
    }
	strcpy(g_net, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
		
    /* broadcast address */
    strncpy(ifr.ifr_name, ifname, IF_NAMESIZE);
    if(ioctl(skfd, SIOCGIFBRDADDR, &ifr) < 0) {
      perror("SIOCGIFBRDADDR");
      return;
    }
	strcpy(g_brd, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
  }
}

/*****************************************************************************
 * do_all
 *****************************************************************************/
void
do_all()
{
  struct ifconf ifc;
  char buf[BUFSIZ];

  struct ifreq *pifr;
  int n;

  ifc.ifc_len = sizeof(buf);
  ifc.ifc_buf = buf;

  if(ioctl(skfd, SIOCGIFCONF, (char *) &ifc) < 0) {
    perror("SIOCGIFCONF");
    return;
  }

  pifr = ifc.ifc_req;
  for(n = ifc.ifc_len/sizeof(struct ifreq); --n >= 0; pifr++) {
	if((pifr->ifr_flags & IFF_UP) == 0) {
	  do_one(pifr->ifr_name);
	  printf("%s %s %s %s %s\n", pifr->ifr_name, g_hw, g_addr, g_net, g_brd);
	}
  }
}


/*****************************************************************************
 * main
 *****************************************************************************/
extern char *optarg;
extern int optind, opterr, optopt;

int
main(int argc, char* argv[])
{
  int c, i;
  char errstr[20];
  int typ = 0;
	
  args = argv;

  while(1) {
	c = getopt(argc, argv, "+vahinb");
	if(c == -1) break;
	typ = c;
	switch(c) {
	case 'v': version(); break;
	case 'a': case 'h': case 'i': case 'n': case 'b': break;
	case '?': usage(); fprintf(stderr, "unrecognized char \"%c\" ?\n", optopt);
	  exit(1);
	default: usage(); fprintf(stderr, "getopt returned character 0%o ?\n", c);
	  exit(1);
	}
  }
  if((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
	perror("socket");
	exit(1);
  }
  if(typ == 'a') {
	do_all();
  }
  else {
	while(optind < argc) {
	  do_one(argv[optind]);
	  switch(typ) {
	  case 'h': printf("%s\n", g_hw); break;
	  case 'i': printf("%s\n", g_addr); break;
	  case 'n': printf("%s\n", g_net); break;
	  case 'b': if(g_flags & IFF_BROADCAST) printf("%s\n", g_brd); break;
	  default:
		if(g_flags & IFF_BROADCAST) printf("%s %s\n", g_addr, g_net);
		else printf("%s %s %s\n", g_addr, g_net, g_brd);
	  }
	  optind++;
	}
  }
  (void) close(skfd);
  exit(0);
}

/*
 * Local variables:
 * c-indent-level: 4
 * tab-width: 4
 * End:
 */

