xref: /titanic_50/usr/src/cmd/cmd-inet/sbin/netstrategy/netstrategy.c (revision bdfc6d18da790deeec2e0eb09c625902defe2498)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * This program does the following:
31  *
32  * a) Returns:
33  *	0	- if the program successfully determined the net strategy.
34  *	!0	- if an error occurred.
35  *
36  * b) If the program is successful, it prints three tokens to
37  *    stdout: <root fs type> <interface name> <net config strategy>.
38  *    where:
39  *	<root fs type>		-	"nfs" or "ufs"
40  *	<interface name>	-	"hme0" or "none"
41  *	<net config strategy>	-	"dhcp", "rarp", or "none"
42  *
43  *    Eg:
44  *	# /sbin/netstrategy
45  *	ufs hme0 dhcp
46  *
47  *    <root fs type> identifies the system's root file system type.
48  *
49  *    <interface name> is the 16 char name of the root interface, and is only
50  *	set if rarp/dhcp was used to configure the interface.
51  *
52  *    <net config strategy> can be either "rarp", "dhcp", or "none" depending
53  *	on which strategy was used to configure the interface. Is "none" if
54  *	no interface was configured using a net-based strategy.
55  *
56  * CAVEATS: what about autoclient systems? XXX
57  */
58 
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <unistd.h>
62 #include <string.h>
63 #include <sys/types.h>
64 #include <errno.h>
65 #include <alloca.h>
66 #include <sys/systeminfo.h>
67 #include <sys/socket.h>
68 #include <sys/sockio.h>
69 #include <net/if.h>
70 #include <sys/statvfs.h>
71 
72 /* ARGSUSED */
73 int
74 main(int argc, char *argv[])
75 {
76 	struct statvfs	vfs;
77 	char		*root, *interface, *strategy, dummy;
78 	long		len;
79 	int		fd, numifs;
80 	struct ifreq	*ifr;
81 	struct ifconf	ifconf;
82 
83 	/* root location */
84 	if (statvfs("/", &vfs) < 0)
85 		root = "none";
86 	else {
87 		if (strncmp(vfs.f_basetype, "nfs", sizeof ("nfs") - 1) == 0)
88 			vfs.f_basetype[sizeof ("nfs") - 1] = '\0';
89 		root = vfs.f_basetype;
90 	}
91 
92 	/*
93 	 * Handle the simple case where diskless dhcp tells us everything
94 	 * we need to know.
95 	 */
96 	if ((len = sysinfo(SI_DHCP_CACHE, &dummy, sizeof (dummy))) > 1) {
97 		/* interface is first thing in cache. */
98 		strategy = "dhcp";
99 		interface = alloca(len);
100 		(void) sysinfo(SI_DHCP_CACHE, interface, len);
101 		(void) printf("%s %s %s\n", root, interface, strategy);
102 		return (0);
103 	}
104 
105 	/*
106 	 * We're not "nfs dhcp", "nfs none" is impossible, and we don't handle
107 	 * "ufs rarp" (consumers are coded to deal with this reality), so
108 	 * there are three possible situations:
109 	 *
110 	 *	1. We're "ufs dhcp" if there are any interfaces which have
111 	 *	   obtained their addresses through DHCP.  That is, if there
112 	 *	   are any IFF_UP and non-IFF_VIRTUAL interfaces also have
113 	 *	   IFF_DHCPRUNNING set.
114 	 *
115 	 *	2. We're "ufs none" if our filesystem is local and there
116 	 *	   are no interfaces which have obtained their addresses
117 	 *	   through DHCP.
118 	 *
119 	 *	3. We're "nfs rarp" if our filesystem is remote and there's
120 	 *	   at least IFF_UP non-IFF_VIRTUAL interface (which there
121 	 *	   *must* be, since we're running over NFS somehow), then
122 	 *	   it must be RARP since SI_DHCP_CACHE call above failed.
123 	 *	   It's too bad there isn't an IFF_RARPRUNNING flag.
124 	 */
125 
126 	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
127 		(void) fprintf(stderr, "%s: socket: %s\n", argv[0],
128 		    strerror(errno));
129 		return (2);
130 	}
131 
132 	if (ioctl(fd, SIOCGIFNUM, &numifs) < 0) {
133 		(void) fprintf(stderr, "%s: SIOCGIFNUM: %s\n", argv[0],
134 		    strerror(errno));
135 		(void) close(fd);
136 		return (2);
137 	}
138 
139 	ifconf.ifc_len = numifs * sizeof (struct ifreq);
140 	ifconf.ifc_buf = alloca(ifconf.ifc_len);
141 
142 	if (ioctl(fd, SIOCGIFCONF, &ifconf) < 0) {
143 		(void) fprintf(stderr, "%s: SIOCGIFCONF: %s\n", argv[0],
144 		    strerror(errno));
145 		(void) close(fd);
146 		return (2);
147 	}
148 
149 	strategy = NULL;
150 	interface = NULL;
151 
152 	for (ifr = ifconf.ifc_req; ifr < &ifconf.ifc_req[ifconf.ifc_len /
153 	    sizeof (struct ifreq)]; ifr++) {
154 
155 		if (strchr(ifr->ifr_name, ':') != NULL)
156 			continue;	/* skip virtual interfaces */
157 
158 		if (ioctl(fd, SIOCGIFFLAGS, ifr) < 0) {
159 			(void) fprintf(stderr, "%s: SIOCGIFFLAGS: %s\n",
160 			    argv[0], strerror(errno));
161 			continue;
162 		}
163 
164 		if (ifr->ifr_flags & (IFF_VIRTUAL|IFF_POINTOPOINT))
165 			continue;
166 
167 		if (ifr->ifr_flags & IFF_UP) {
168 			/*
169 			 * For the "nfs rarp" case, we assume that the first
170 			 * IFF_UP interface is the one using RARP, so stash
171 			 * away the first interface in case we need it.
172 			 *
173 			 * Since the order of the interfaces retrieved via
174 			 * SIOCGLIFCONF is not deterministic, this is largely
175 			 * silliness, but (a) "it's always been this way", (b)
176 			 * machines booted via diskless RARP typically only
177 			 * have one interface, and (c) no one consumes the
178 			 * interface name in the RARP case anyway.
179 			 */
180 			if (interface == NULL)
181 				interface = ifr->ifr_name;
182 
183 			if (ifr->ifr_flags & IFF_DHCPRUNNING) {
184 				interface = ifr->ifr_name;
185 				strategy = "dhcp";
186 				break;
187 			}
188 		}
189 	}
190 
191 	(void) close(fd);
192 
193 	if (strcmp(root, "nfs") == 0 || strcmp(root, "cachefs") == 0) {
194 		if (interface == NULL) {
195 			(void) fprintf(stderr,
196 			    "%s: cannot identify root interface.\n", argv[0]);
197 			return (2);
198 		}
199 		if (strategy == NULL)
200 			strategy = "rarp";	/*  must be rarp/bootparams */
201 	} else {
202 		if (interface == NULL || strategy == NULL)
203 			interface = strategy = "none";
204 	}
205 
206 	(void) printf("%s %s %s\n", root, interface, strategy);
207 	return (0);
208 }
209