#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <alloca.h>
#include <sys/systeminfo.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <sys/statvfs.h>
#include <libdevinfo.h>
static char *program;
static int s4, s6;
static boolean_t
open_sockets(void)
{
if ((s4 = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
(void) fprintf(stderr, "%s: inet socket: %s\n", program,
strerror(errno));
return (B_FALSE);
}
if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) {
(void) fprintf(stderr, "%s: inet6 socket: %s\n", program,
strerror(errno));
return (B_FALSE);
}
return (B_TRUE);
}
static void
close_sockets(void)
{
(void) close(s4);
(void) close(s6);
}
static char *
get_root_fstype()
{
static struct statvfs vfs;
if (statvfs("/", &vfs) < 0) {
return ("none");
} else {
if (strncmp(vfs.f_basetype, "nfs", sizeof ("nfs") - 1) == 0)
vfs.f_basetype[sizeof ("nfs") - 1] = '\0';
return (vfs.f_basetype);
}
}
static boolean_t
boot_properties_present()
{
const char *required_properties[] = {
"host-ip",
"subnet-mask",
"server-path",
"server-name",
"server-ip",
NULL,
};
const char **prop = required_properties;
char *prop_value;
di_node_t dn;
if ((dn = di_init("/", DINFOPROP)) == DI_NODE_NIL) {
(void) fprintf(stderr, "%s: di_init: %s\n", program,
strerror(errno));
di_fini(dn);
return (B_FALSE);
}
while (*prop != NULL) {
if (di_prop_lookup_strings(DDI_DEV_T_ANY,
dn, *prop, &prop_value) != 1) {
di_fini(dn);
return (B_FALSE);
}
prop++;
}
di_fini(dn);
return (B_TRUE);
}
static char *
get_first_interface(boolean_t *dhcpflag)
{
struct lifnum ifnum;
struct lifconf ifconf;
struct lifreq *ifr;
static char interface[LIFNAMSIZ];
boolean_t isv4, found_one = B_FALSE;
ifnum.lifn_family = AF_UNSPEC;
ifnum.lifn_flags = 0;
ifnum.lifn_count = 0;
if (ioctl(s4, SIOCGLIFNUM, &ifnum) < 0) {
(void) fprintf(stderr, "%s: SIOCGLIFNUM: %s\n", program,
strerror(errno));
return (NULL);
}
ifconf.lifc_family = AF_UNSPEC;
ifconf.lifc_flags = 0;
ifconf.lifc_len = ifnum.lifn_count * sizeof (struct lifreq);
ifconf.lifc_buf = alloca(ifconf.lifc_len);
if (ioctl(s4, SIOCGLIFCONF, &ifconf) < 0) {
(void) fprintf(stderr, "%s: SIOCGLIFCONF: %s\n", program,
strerror(errno));
return (NULL);
}
for (ifr = ifconf.lifc_req; ifr < &ifconf.lifc_req[ifconf.lifc_len /
sizeof (ifconf.lifc_req[0])]; ifr++) {
struct lifreq flifr;
struct sockaddr_in *sin;
if (strchr(ifr->lifr_name, ':') != NULL)
continue;
isv4 = ifr->lifr_addr.ss_family == AF_INET;
(void) strncpy(flifr.lifr_name, ifr->lifr_name, LIFNAMSIZ);
if (ioctl(isv4 ? s4 : s6, SIOCGLIFFLAGS, &flifr) < 0) {
(void) fprintf(stderr, "%s: SIOCGLIFFLAGS: %s\n",
program, strerror(errno));
continue;
}
if (!(flifr.lifr_flags & IFF_UP) ||
(flifr.lifr_flags & (IFF_VIRTUAL|IFF_POINTOPOINT)))
continue;
found_one = B_TRUE;
(void) strncpy(interface, ifr->lifr_name, LIFNAMSIZ);
*dhcpflag = (flifr.lifr_flags & IFF_DHCPRUNNING) != 0;
sin = (struct sockaddr_in *)&ifr->lifr_addr;
if (isv4 && (sin->sin_addr.s_addr == INADDR_ANY)) {
continue;
}
return (interface);
}
return (found_one ? interface : NULL);
}
int
main(int argc, char *argv[])
{
char *root, *interface, *strategy, dummy;
long len;
boolean_t dhcp_running = B_FALSE;
root = interface = strategy = NULL;
program = argv[0];
root = get_root_fstype();
if (!open_sockets()) {
(void) fprintf(stderr,
"%s: cannot get interface information\n", program);
return (2);
}
if ((strcmp(root, "nfs") == 0) && boot_properties_present()) {
strategy = "bootprops";
interface = get_first_interface(&dhcp_running);
if (interface == NULL) {
(void) fprintf(stderr,
"%s: cannot identify root interface.\n", program);
close_sockets();
return (2);
}
(void) printf("%s %s %s\n", root, interface, strategy);
close_sockets();
return (0);
}
if ((len = sysinfo(SI_DHCP_CACHE, &dummy, sizeof (dummy))) > 1) {
strategy = "dhcp";
interface = alloca(len);
(void) sysinfo(SI_DHCP_CACHE, interface, len);
(void) printf("%s %s %s\n", root, interface, strategy);
close_sockets();
return (0);
}
interface = get_first_interface(&dhcp_running);
if (dhcp_running)
strategy = "dhcp";
if (strcmp(root, "nfs") == 0) {
if (interface == NULL) {
(void) fprintf(stderr,
"%s: cannot identify root interface.\n", program);
close_sockets();
return (2);
}
if (strategy == NULL)
strategy = "rarp";
} else {
if (interface == NULL || strategy == NULL)
interface = strategy = "none";
}
(void) printf("%s %s %s\n", root, interface, strategy);
close_sockets();
return (0);
}