10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 22*761Smeem 230Sstevel@tonic-gate /* 24*761Smeem * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 250Sstevel@tonic-gate * Use is subject to license terms. 260Sstevel@tonic-gate */ 270Sstevel@tonic-gate 280Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 290Sstevel@tonic-gate 300Sstevel@tonic-gate /* 310Sstevel@tonic-gate * This program does the following: 320Sstevel@tonic-gate * 330Sstevel@tonic-gate * a) Returns: 340Sstevel@tonic-gate * 0 - if the program successfully determined the net strategy. 350Sstevel@tonic-gate * !0 - if an error occurred. 360Sstevel@tonic-gate * 370Sstevel@tonic-gate * b) If the program is successful, it prints three tokens to 380Sstevel@tonic-gate * stdout: <root fs type> <interface name> <net config strategy>. 390Sstevel@tonic-gate * where: 400Sstevel@tonic-gate * <root fs type> - "nfs" or "ufs" 410Sstevel@tonic-gate * <interface name> - "hme0" or "none" 420Sstevel@tonic-gate * <net config strategy> - "dhcp", "rarp", or "none" 430Sstevel@tonic-gate * 440Sstevel@tonic-gate * Eg: 450Sstevel@tonic-gate * # /sbin/netstrategy 460Sstevel@tonic-gate * ufs hme0 dhcp 470Sstevel@tonic-gate * 480Sstevel@tonic-gate * <root fs type> identifies the system's root file system type. 490Sstevel@tonic-gate * 500Sstevel@tonic-gate * <interface name> is the 16 char name of the root interface, and is only 510Sstevel@tonic-gate * set if rarp/dhcp was used to configure the interface. 520Sstevel@tonic-gate * 530Sstevel@tonic-gate * <net config strategy> can be either "rarp", "dhcp", or "none" depending 540Sstevel@tonic-gate * on which strategy was used to configure the interface. Is "none" if 550Sstevel@tonic-gate * no interface was configured using a net-based strategy. 560Sstevel@tonic-gate * 570Sstevel@tonic-gate * CAVEATS: what about autoclient systems? XXX 580Sstevel@tonic-gate */ 590Sstevel@tonic-gate 600Sstevel@tonic-gate #include <stdio.h> 610Sstevel@tonic-gate #include <stdlib.h> 620Sstevel@tonic-gate #include <unistd.h> 630Sstevel@tonic-gate #include <string.h> 640Sstevel@tonic-gate #include <sys/types.h> 650Sstevel@tonic-gate #include <errno.h> 660Sstevel@tonic-gate #include <alloca.h> 670Sstevel@tonic-gate #include <sys/systeminfo.h> 680Sstevel@tonic-gate #include <sys/socket.h> 690Sstevel@tonic-gate #include <sys/sockio.h> 700Sstevel@tonic-gate #include <net/if.h> 710Sstevel@tonic-gate #include <sys/statvfs.h> 720Sstevel@tonic-gate 730Sstevel@tonic-gate /* ARGSUSED */ 740Sstevel@tonic-gate int 750Sstevel@tonic-gate main(int argc, char *argv[]) 760Sstevel@tonic-gate { 770Sstevel@tonic-gate struct statvfs vfs; 780Sstevel@tonic-gate char *root, *interface, *strategy, dummy; 790Sstevel@tonic-gate long len; 80*761Smeem int fd, nifs, nlifr; 81*761Smeem struct lifreq *lifr; 82*761Smeem struct lifconf lifc; 830Sstevel@tonic-gate 840Sstevel@tonic-gate /* root location */ 850Sstevel@tonic-gate if (statvfs("/", &vfs) < 0) 860Sstevel@tonic-gate root = "none"; 870Sstevel@tonic-gate else { 880Sstevel@tonic-gate if (strncmp(vfs.f_basetype, "nfs", sizeof ("nfs") - 1) == 0) 890Sstevel@tonic-gate vfs.f_basetype[sizeof ("nfs") - 1] = '\0'; 900Sstevel@tonic-gate root = vfs.f_basetype; 910Sstevel@tonic-gate } 920Sstevel@tonic-gate 930Sstevel@tonic-gate /* 940Sstevel@tonic-gate * Handle the simple case where diskless dhcp tells us everything 950Sstevel@tonic-gate * we need to know. 960Sstevel@tonic-gate */ 970Sstevel@tonic-gate if ((len = sysinfo(SI_DHCP_CACHE, &dummy, sizeof (dummy))) > 1) { 980Sstevel@tonic-gate /* interface is first thing in cache. */ 990Sstevel@tonic-gate strategy = "dhcp"; 1000Sstevel@tonic-gate interface = alloca(len); 1010Sstevel@tonic-gate (void) sysinfo(SI_DHCP_CACHE, interface, len); 1020Sstevel@tonic-gate (void) printf("%s %s %s\n", root, interface, strategy); 1030Sstevel@tonic-gate return (0); 1040Sstevel@tonic-gate } 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate /* 1070Sstevel@tonic-gate * We're not "nfs dhcp", "nfs none" is impossible, and we don't handle 1080Sstevel@tonic-gate * "ufs rarp" (consumers are coded to deal with this reality), so 1090Sstevel@tonic-gate * there are three possible situations: 1100Sstevel@tonic-gate * 1110Sstevel@tonic-gate * 1. We're "ufs dhcp" if there are any interfaces which have 1120Sstevel@tonic-gate * obtained their addresses through DHCP. That is, if there 1130Sstevel@tonic-gate * are any IFF_UP and non-IFF_VIRTUAL interfaces also have 1140Sstevel@tonic-gate * IFF_DHCPRUNNING set. 1150Sstevel@tonic-gate * 1160Sstevel@tonic-gate * 2. We're "ufs none" if our filesystem is local and there 1170Sstevel@tonic-gate * are no interfaces which have obtained their addresses 1180Sstevel@tonic-gate * through DHCP. 1190Sstevel@tonic-gate * 1200Sstevel@tonic-gate * 3. We're "nfs rarp" if our filesystem is remote and there's 1210Sstevel@tonic-gate * at least IFF_UP non-IFF_VIRTUAL interface (which there 1220Sstevel@tonic-gate * *must* be, since we're running over NFS somehow), then 1230Sstevel@tonic-gate * it must be RARP since SI_DHCP_CACHE call above failed. 1240Sstevel@tonic-gate * It's too bad there isn't an IFF_RARPRUNNING flag. 1250Sstevel@tonic-gate */ 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { 1280Sstevel@tonic-gate (void) fprintf(stderr, "%s: socket: %s\n", argv[0], 1290Sstevel@tonic-gate strerror(errno)); 1300Sstevel@tonic-gate return (2); 1310Sstevel@tonic-gate } 1320Sstevel@tonic-gate 133*761Smeem if (ioctl(fd, SIOCGIFNUM, &nifs) < 0) { 1340Sstevel@tonic-gate (void) fprintf(stderr, "%s: SIOCGIFNUM: %s\n", argv[0], 1350Sstevel@tonic-gate strerror(errno)); 1360Sstevel@tonic-gate (void) close(fd); 1370Sstevel@tonic-gate return (2); 1380Sstevel@tonic-gate } 1390Sstevel@tonic-gate 140*761Smeem lifc.lifc_len = nifs * sizeof (struct lifreq); 141*761Smeem lifc.lifc_buf = alloca(lifc.lifc_len); 142*761Smeem lifc.lifc_flags = 0; 143*761Smeem lifc.lifc_family = AF_INET; 1440Sstevel@tonic-gate 145*761Smeem if (ioctl(fd, SIOCGLIFCONF, &lifc) < 0) { 146*761Smeem (void) fprintf(stderr, "%s: SIOCGLIFCONF: %s\n", argv[0], 1470Sstevel@tonic-gate strerror(errno)); 1480Sstevel@tonic-gate (void) close(fd); 1490Sstevel@tonic-gate return (2); 1500Sstevel@tonic-gate } 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate strategy = NULL; 1530Sstevel@tonic-gate interface = NULL; 1540Sstevel@tonic-gate 155*761Smeem nlifr = lifc.lifc_len / sizeof (struct lifreq); 156*761Smeem for (lifr = lifc.lifc_req; nlifr > 0; lifr++, nlifr--) { 1570Sstevel@tonic-gate 158*761Smeem if (strchr(lifr->lifr_name, ':') != NULL) 159*761Smeem continue; /* skip logical interfaces */ 1600Sstevel@tonic-gate 161*761Smeem if (ioctl(fd, SIOCGLIFFLAGS, lifr) < 0) { 162*761Smeem (void) fprintf(stderr, "%s: SIOCGLIFFLAGS: %s\n", 1630Sstevel@tonic-gate argv[0], strerror(errno)); 1640Sstevel@tonic-gate continue; 1650Sstevel@tonic-gate } 1660Sstevel@tonic-gate 167*761Smeem if (lifr->lifr_flags & (IFF_VIRTUAL|IFF_POINTOPOINT)) 1680Sstevel@tonic-gate continue; 1690Sstevel@tonic-gate 170*761Smeem if (lifr->lifr_flags & IFF_UP) { 1710Sstevel@tonic-gate /* 1720Sstevel@tonic-gate * For the "nfs rarp" case, we assume that the first 1730Sstevel@tonic-gate * IFF_UP interface is the one using RARP, so stash 1740Sstevel@tonic-gate * away the first interface in case we need it. 1750Sstevel@tonic-gate * 1760Sstevel@tonic-gate * Since the order of the interfaces retrieved via 1770Sstevel@tonic-gate * SIOCGLIFCONF is not deterministic, this is largely 1780Sstevel@tonic-gate * silliness, but (a) "it's always been this way", (b) 1790Sstevel@tonic-gate * machines booted via diskless RARP typically only 1800Sstevel@tonic-gate * have one interface, and (c) no one consumes the 1810Sstevel@tonic-gate * interface name in the RARP case anyway. 1820Sstevel@tonic-gate */ 1830Sstevel@tonic-gate if (interface == NULL) 184*761Smeem interface = lifr->lifr_name; 1850Sstevel@tonic-gate 186*761Smeem if (lifr->lifr_flags & IFF_DHCPRUNNING) { 187*761Smeem interface = lifr->lifr_name; 1880Sstevel@tonic-gate strategy = "dhcp"; 1890Sstevel@tonic-gate break; 1900Sstevel@tonic-gate } 1910Sstevel@tonic-gate } 1920Sstevel@tonic-gate } 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate (void) close(fd); 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate if (strcmp(root, "nfs") == 0 || strcmp(root, "cachefs") == 0) { 1970Sstevel@tonic-gate if (interface == NULL) { 1980Sstevel@tonic-gate (void) fprintf(stderr, 1990Sstevel@tonic-gate "%s: cannot identify root interface.\n", argv[0]); 2000Sstevel@tonic-gate return (2); 2010Sstevel@tonic-gate } 2020Sstevel@tonic-gate if (strategy == NULL) 2030Sstevel@tonic-gate strategy = "rarp"; /* must be rarp/bootparams */ 2040Sstevel@tonic-gate } else { 2050Sstevel@tonic-gate if (interface == NULL || strategy == NULL) 2060Sstevel@tonic-gate interface = strategy = "none"; 2070Sstevel@tonic-gate } 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate (void) printf("%s %s %s\n", root, interface, strategy); 2100Sstevel@tonic-gate return (0); 2110Sstevel@tonic-gate } 212