xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/routeadm/routeadm.c (revision 3048:ce5ba5995ea4)
1*3048Samaguire /*
2*3048Samaguire  * CDDL HEADER START
3*3048Samaguire  *
4*3048Samaguire  * The contents of this file are subject to the terms of the
5*3048Samaguire  * Common Development and Distribution License (the "License").
6*3048Samaguire  * You may not use this file except in compliance with the License.
7*3048Samaguire  *
8*3048Samaguire  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*3048Samaguire  * or http://www.opensolaris.org/os/licensing.
10*3048Samaguire  * See the License for the specific language governing permissions
11*3048Samaguire  * and limitations under the License.
12*3048Samaguire  *
13*3048Samaguire  * When distributing Covered Code, include this CDDL HEADER in each
14*3048Samaguire  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*3048Samaguire  * If applicable, add the following below this CDDL HEADER, with the
16*3048Samaguire  * fields enclosed by brackets "[]" replaced with your own identifying
17*3048Samaguire  * information: Portions Copyright [yyyy] [name of copyright owner]
18*3048Samaguire  *
19*3048Samaguire  * CDDL HEADER END
20*3048Samaguire  */
21*3048Samaguire /*
22*3048Samaguire  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23*3048Samaguire  * Use is subject to license terms.
24*3048Samaguire  */
25*3048Samaguire 
26*3048Samaguire #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*3048Samaguire 
28*3048Samaguire #include <stdio.h>
29*3048Samaguire #include <string.h>
30*3048Samaguire #include <stdlib.h>
31*3048Samaguire #include <unistd.h>
32*3048Samaguire #include <limits.h>
33*3048Samaguire #include <ctype.h>
34*3048Samaguire #include <stropts.h>
35*3048Samaguire #include <errno.h>
36*3048Samaguire #include <libintl.h>
37*3048Samaguire #include <locale.h>
38*3048Samaguire #include <fcntl.h>
39*3048Samaguire #include <sys/types.h>
40*3048Samaguire #include <sys/stat.h>
41*3048Samaguire #include <libscf.h>
42*3048Samaguire #include <libscf_priv.h>
43*3048Samaguire #include <libuutil.h>
44*3048Samaguire 
45*3048Samaguire /*
46*3048Samaguire  * This program moves routing management under SMF.  We do this by giving
47*3048Samaguire  * routeadm options that allow interaction with SMF services.  These include:
48*3048Samaguire  * - setting the routing services routeadm will enable
49*3048Samaguire  *	# routeadm -s routing-svcs="fmri [fmri...]"
50*3048Samaguire  * where each fmri is an SMF routing service.
51*3048Samaguire  * - changing properties of routing services
52*3048Samaguire  *	# routeadm -m fmri key=value [key=value...]
53*3048Samaguire  * - listing routing daemon properties
54*3048Samaguire  *	# routeadm -l fmri
55*3048Samaguire  * where all properties in the "routing" property group are listed.
56*3048Samaguire  *
57*3048Samaguire  * By providing legacy routing services (legacy-routing:ipv4 and ipv6), we
58*3048Samaguire  * can also support running of routing daemons with no SMF service under SMF.
59*3048Samaguire  * Specifying a routing daemon with no SMF counterpart results in the
60*3048Samaguire  * daemon, it`s arguments and stop command being set in the appropriate instance
61*3048Samaguire  * to be picked up by start/stop methods.
62*3048Samaguire  *
63*3048Samaguire  * Internally, routeadm keeps track of routing services by setting the
64*3048Samaguire  * "current-routing-svc" property to "true" in the services it manages.
65*3048Samaguire  * So for example, running
66*3048Samaguire  *	# routeadm -s routing-svcs="route:default ripng:default"
67*3048Samaguire  * sets this variable in each instance specified. If the user specifies a
68*3048Samaguire  * non-SMF routing daemon via
69*3048Samaguire  * 	# routeadm -s ipv4-routing-daemon=/usr/sbin/mydaemon
70*3048Samaguire  * the variable will be set for the legacy-routing:ipv4 instance.
71*3048Samaguire  *
72*3048Samaguire  * In order to ensure that the SMF versions of routing daemons are used
73*3048Samaguire  * where possible, routeadm will check the daemons specified in
74*3048Samaguire  * ipv4-routing-daemon/ipv6-routing-daemon to determine if there is an
75*3048Samaguire  * SMF counterpart.  If so, rather than running the legacy service
76*3048Samaguire  * we move configuration, specifically the associated daemon arguments
77*3048Samaguire  * to the SMF counterpart.  From there,  when the daemon is enabled,  it
78*3048Samaguire  * will pick up the daemon arguments setting,  transfer the argument string
79*3048Samaguire  * to the appropriate properties and run the service.
80*3048Samaguire  *
81*3048Samaguire  * To support the semantics of routeadm -e (enable at next boot) through SMF,
82*3048Samaguire  * we make use of temporary state changes,  which last only until reboot.
83*3048Samaguire  * For example, if a service is disabled,  and it is to be enabled via
84*3048Samaguire  * routeadm -e,  we simply change the disable to a temporary disable,
85*3048Samaguire  * and set the persistent enabled value to true.  This ensures the daemon
86*3048Samaguire  * will run at next boot,  but not now.  The reverse is true for disabling
87*3048Samaguire  * enabled instances  (and if the daemon is enabled when we issue the enable,
88*3048Samaguire  * we do nothing since it is already in the desired state).
89*3048Samaguire  *
90*3048Samaguire  * Since the code is quite involved,  we provide a guide to the more complex
91*3048Samaguire  * actions taken in response to user commands.
92*3048Samaguire  *
93*3048Samaguire  * routeadm -e[d] ipv4[6]-routing[forwarding]
94*3048Samaguire  *
95*3048Samaguire  * 	In this case,  the goal is to prepare the configured routing daemons
96*3048Samaguire  * 	(specified through routeadm -s routing-svcs="...") or forwarding
97*3048Samaguire  *	services to switch on (-e) or of (-d) at next boot.
98*3048Samaguire  *
99*3048Samaguire  *	Since this operation must be applied to multiple services in the
100*3048Samaguire  *	routing daemon case (as opposed to the single ipv4[6]-forwarding
101*3048Samaguire  *	service),  we make use of the scf_walk_fmri() function,  which
102*3048Samaguire  *	applies a callback function to all matching functions.  In the case
103*3048Samaguire  *	of the routing daemons,  we pass in a NULL signifying that all
104*3048Samaguire  *	instances should be walked  (we then weed out the relevant routing
105*3048Samaguire  *	services through presence of the routeadm/protocol property).  In
106*3048Samaguire  *	the case of enable, a routing service is enabled IFF it has the
107*3048Samaguire  *	previously-mentioned property - with an appropriate value (i.e. ipv4
108*3048Samaguire  *	for "routeadm -e ipv4-routing") - and it has routeadm/curr-routing-svc
109*3048Samaguire  *	property set to true  (this is set by other operations such as
110*3048Samaguire  *	routeadm -s routing-svcs="...").  Then,  smf_enable_instance() or
111*3048Samaguire  *	smf_disable_instance() is called,  setting the temporary state to
112*3048Samaguire  *	the current state of the service.  This then allows setting of
113*3048Samaguire  *	general/enabled value to next-boot value.  In the case of disabling
114*3048Samaguire  *	ipv4[6]-routing,  all valid ipv4[6] routing daemons are prepared
115*3048Samaguire  *	for next-boot disable, not just those specified via routing-svcs (this
116*3048Samaguire  *	means that if the user enables routing daemons with "svcadm enable",
117*3048Samaguire  *	disabling global routing does really switch off all routing daemons).
118*3048Samaguire  *
119*3048Samaguire  *	This is implemented through the ra_get_set_opt_common_cb() function,
120*3048Samaguire  *	called by the ra_set_persistent_opt_cb() function.  The same
121*3048Samaguire  *	function can be used for both routing and forwarding options,  in the
122*3048Samaguire  *	latter case we simply provide the specific FMRI of the forwarding
123*3048Samaguire  *	service in question (ipv4-forwarding or ipv6-forwarding),  and dispense
124*3048Samaguire  *	with the eligibility tests we need to weed out the routing services
125*3048Samaguire  *	from the rest.
126*3048Samaguire  *
127*3048Samaguire  *	Before we initiate the "enable" however, we must check routing daemons
128*3048Samaguire  *	specified via the legacy variables (ipv4-routing-daemon etc).
129*3048Samaguire  *	If they map to SMF routing services,  we wish to transfer their
130*3048Samaguire  *	configuration to the corresponding services and use them instead of
131*3048Samaguire  *	the legacy services.  To do this,  we need to match the daemon program
132*3048Samaguire  *	against the routeadm/daemon property of each routing daemon (we use
133*3048Samaguire  *	scf_walk_fmri() and the routeadm/protocol property again to identify
134*3048Samaguire  *	daemons).  If a match is found,  the daemon arguments are transferred
135*3048Samaguire  *	to the appropriate service`s daemon-args property, to be picked up
136*3048Samaguire  *	by it`s start method and converted into appropriate property values.
137*3048Samaguire  *	This is accomplished by ra_check_legacy_daemons(), and the callback
138*3048Samaguire  *	operation is carried out by ra_upgrade_legacy_daemons_cb().  If the
139*3048Samaguire  *	daemon was not upgraded,  we need to mark the legacy-routing:ipv4[6]
140*3048Samaguire  *	instance to be enabled (by routeadm -e),  since it now must run the
141*3048Samaguire  *	un-upgradeable legacy daemon.
142*3048Samaguire  *
143*3048Samaguire  * routeadm -l fmri
144*3048Samaguire  *
145*3048Samaguire  *	Lists all properties and values in the routing property group associated
146*3048Samaguire  *	with instance fmri.  We simply walk through the composed property
147*3048Samaguire  *	group, displaying all values.  See ra_list_props_cb().
148*3048Samaguire  *
149*3048Samaguire  * routeadm -m fmri key=value ...
150*3048Samaguire  *
151*3048Samaguire  *	Modify property values in the routing property group.  If the same
152*3048Samaguire  *	key is used more than once,  multiple property values are set for that
153*3048Samaguire  *	property.  Properties must exist in the composed property group,  but
154*3048Samaguire  *	will only ever be set at the instance level to prevent multiple
155*3048Samaguire  *	instances inheriting the property in error.  See ra_modify_props_cb().
156*3048Samaguire  *
157*3048Samaguire  * routeadm -s var=value
158*3048Samaguire  *
159*3048Samaguire  *	In all cases bar the routing-svcs variable,  this simply involves
160*3048Samaguire  *	setting the appropriate SMF property value for the variable.  The
161*3048Samaguire  *	routing-svcs case is more complex,  since we would like operations
162*3048Samaguire  *	like the following to have intuitive effects:
163*3048Samaguire  *		# routeadm -s routing-svcs=route -e ipv4-routing -u
164*3048Samaguire  *		# routeadm -s routing-svcs=rdisc -u
165*3048Samaguire  *	i.e., in the end, rdisc is the only routing service running.  To
166*3048Samaguire  *	accomplish this switchover,  we need to disable the old routing-svcs
167*3048Samaguire  *	and enable the new, marking the latter with the curr-routing-svc
168*3048Samaguire  *	property so that routeadm -e will pick them up.  This is carried
169*3048Samaguire  *	out by the ra_update_routing_svcs() function.
170*3048Samaguire  *
171*3048Samaguire  * routeadm -R alt_root ...
172*3048Samaguire  *
173*3048Samaguire  *	Used to support use of routeadm in Custom Jumpstart scripts,  this
174*3048Samaguire  *	option causes all subsequent commands to be appended to the
175*3048Samaguire  *	/var/svc/profile/upgrade file,  which is run on the subsequent boot.
176*3048Samaguire  *	This is done because the SMF repository is not available to make
177*3048Samaguire  *	the modifications to property values required in routeadm operations.
178*3048Samaguire  *
179*3048Samaguire  * routeadm -u
180*3048Samaguire  *
181*3048Samaguire  *	Update applies the "next boot" state to the current system.  Here
182*3048Samaguire  *	we simply take the persistent state (general/enabled value) and
183*3048Samaguire  *	make it the current state through smf_enable_instance() or
184*3048Samaguire  *	smf_disable_instance() as appropriate (these calls,  without the
185*3048Samaguire  *	temporary flag set,  delete the general_ovr/enabled property).
186*3048Samaguire  */
187*3048Samaguire 
188*3048Samaguire #define	RA_OPT_IPV4_ROUTING	"ipv4-routing"
189*3048Samaguire #define	RA_OPT_IPV6_ROUTING	"ipv6-routing"
190*3048Samaguire #define	RA_OPT_IPV4_FORWARDING	"ipv4-forwarding"
191*3048Samaguire #define	RA_OPT_IPV6_FORWARDING	"ipv6-forwarding"
192*3048Samaguire 
193*3048Samaguire #define	IS_ROUTING_OPT(opt)	(strcmp(opt, RA_OPT_IPV4_ROUTING) == 0 || \
194*3048Samaguire 				strcmp(opt, RA_OPT_IPV6_ROUTING) == 0)
195*3048Samaguire 
196*3048Samaguire #define	RA_VAR_IPV4_ROUTING_DAEMON	"ipv4-routing-daemon"
197*3048Samaguire #define	RA_VAR_IPV4_ROUTING_DAEMON_ARGS	"ipv4-routing-daemon-args"
198*3048Samaguire #define	RA_VAR_IPV4_ROUTING_STOP_CMD	"ipv4-routing-stop-cmd"
199*3048Samaguire #define	RA_VAR_IPV6_ROUTING_DAEMON	"ipv6-routing-daemon"
200*3048Samaguire #define	RA_VAR_IPV6_ROUTING_DAEMON_ARGS	"ipv6-routing-daemon-args"
201*3048Samaguire #define	RA_VAR_IPV6_ROUTING_STOP_CMD	"ipv6-routing-stop-cmd"
202*3048Samaguire #define	RA_VAR_ROUTING_SVCS		"routing-svcs"
203*3048Samaguire 
204*3048Samaguire 
205*3048Samaguire #define	RA_INSTANCE_ALL			NULL
206*3048Samaguire #define	RA_INSTANCE_ROUTING_SETUP	"svc:/network/routing-setup:default"
207*3048Samaguire #define	RA_INSTANCE_IPV4_FORWARDING	"svc:/network/ipv4-forwarding:default"
208*3048Samaguire #define	RA_INSTANCE_IPV6_FORWARDING	"svc:/network/ipv6-forwarding:default"
209*3048Samaguire #define	RA_INSTANCE_LEGACY_ROUTING_IPV4 \
210*3048Samaguire 	"svc:/network/routing/legacy-routing:ipv4"
211*3048Samaguire #define	RA_INSTANCE_LEGACY_ROUTING_IPV6 \
212*3048Samaguire 	"svc:/network/routing/legacy-routing:ipv6"
213*3048Samaguire 
214*3048Samaguire #define	RA_PG_ROUTEADM			"routeadm"
215*3048Samaguire #define	RA_PROP_CURR_ROUTING_SVC	"current-routing-svc"
216*3048Samaguire #define	RA_PROP_ROUTING_SVCS		"routing-svcs"
217*3048Samaguire #define	RA_PROP_DEFAULT_ROUTING_SVCS	"default-routing-svcs"
218*3048Samaguire #define	RA_PROP_PROTO			"protocol"
219*3048Samaguire #define	RA_PROP_DAEMON			"daemon"
220*3048Samaguire #define	RA_PROP_DEFAULT_DAEMON		"default-daemon"
221*3048Samaguire #define	RA_PROP_DAEMON_ARGS		"daemon-args"
222*3048Samaguire #define	RA_PROP_DEFAULT_DAEMON_ARGS	"default-daemon-args"
223*3048Samaguire #define	RA_PROP_DAEMON_STOP_CMD		"daemon-stop-cmd"
224*3048Samaguire #define	RA_PROP_DEFAULT_STOP_CMD	"default-daemon"
225*3048Samaguire #define	RA_PROP_LEGACY_DAEMON		"legacy-daemon"
226*3048Samaguire #define	RA_PROP_DEFAULT_IPV4_ROUTING	"default-ipv4-routing"
227*3048Samaguire #define	RA_PROP_DEFAULT_IPV6_ROUTING	"default-ipv6-routing"
228*3048Samaguire #define	RA_PROP_DEFAULT_IPV4_FORWARDING	"default-ipv4-forwarding"
229*3048Samaguire #define	RA_PROP_DEFAULT_IPV6_FORWARDING	"default-ipv6-forwarding"
230*3048Samaguire #define	RA_PROP_IPV4_ROUTING_SET	"ipv4-routing-set"
231*3048Samaguire #define	RA_PROP_IPV6_ROUTING_SET	"ipv6-routing-set"
232*3048Samaguire #define	RA_PROP_ROUTING_CONF_READ	"routing-conf-read"
233*3048Samaguire 
234*3048Samaguire #define	RA_PG_ROUTING			"routing"
235*3048Samaguire 
236*3048Samaguire #define	RA_PROPVAL_BOOLEAN_TRUE		"true"
237*3048Samaguire #define	RA_PROPVAL_BOOLEAN_FALSE	"false"
238*3048Samaguire #define	RA_PROPVAL_PROTO_IPV4		"ipv4"
239*3048Samaguire #define	RA_PROPVAL_PROTO_IPV6		"ipv6"
240*3048Samaguire 
241*3048Samaguire #define	RA_SVC_FLAG_NONE		0x0
242*3048Samaguire #define	RA_SVC_FLAG_IPV4_ROUTING	0x1
243*3048Samaguire #define	RA_SVC_FLAG_IPV6_ROUTING	0x2
244*3048Samaguire 
245*3048Samaguire #define	RA_SMF_UPGRADE_FILE		"/var/svc/profile/upgrade"
246*3048Samaguire #define	RA_SMF_UPGRADE_MSG		" # added by routeadm(1M)"
247*3048Samaguire #define	RA_CONF_FILE			"/etc/inet/routing.conf"
248*3048Samaguire #define	RA_CONF_FILE_OLD		"/etc/inet/routing.conf.old"
249*3048Samaguire #define	RA_MAX_CONF_LINE		256
250*3048Samaguire 
251*3048Samaguire /*
252*3048Samaguire  * Option value.  Each option requires an FMRI identifying which services
253*3048Samaguire  * to run the get_current/persistent scf_walk_fmri() function with,  and
254*3048Samaguire  * associated flags (to ensure that in the case that multiple services
255*3048Samaguire  * match, we select the correct ones). In addition, we specify the FMRI
256*3048Samaguire  * and property used to set default option value.  The opt_enabled field
257*3048Samaguire  * is used to hold retrieved state from get_*_opt_() callbacks and to specify
258*3048Samaguire  * desired state for set_*_opt() operations.
259*3048Samaguire  */
260*3048Samaguire 
261*3048Samaguire typedef struct raopt {
262*3048Samaguire 	const char	*opt_name;
263*3048Samaguire 	const char	*opt_fmri;
264*3048Samaguire 	int		opt_flags;
265*3048Samaguire 	boolean_t	opt_enabled;
266*3048Samaguire 	const char	*opt_default_fmri;
267*3048Samaguire 	const char	*opt_default_prop;
268*3048Samaguire 	boolean_t	opt_default_enabled;
269*3048Samaguire } raopt_t;
270*3048Samaguire 
271*3048Samaguire 
272*3048Samaguire raopt_t ra_opts[] = {
273*3048Samaguire 	{ RA_OPT_IPV4_ROUTING, RA_INSTANCE_ALL, RA_SVC_FLAG_IPV4_ROUTING,
274*3048Samaguire 	B_FALSE, RA_INSTANCE_ROUTING_SETUP, RA_PROP_DEFAULT_IPV4_ROUTING,
275*3048Samaguire 	B_FALSE },
276*3048Samaguire 	{ RA_OPT_IPV6_ROUTING, RA_INSTANCE_ALL, RA_SVC_FLAG_IPV6_ROUTING,
277*3048Samaguire 	B_FALSE, RA_INSTANCE_ROUTING_SETUP, RA_PROP_DEFAULT_IPV6_ROUTING,
278*3048Samaguire 	B_FALSE },
279*3048Samaguire 	{ RA_OPT_IPV4_FORWARDING, RA_INSTANCE_IPV4_FORWARDING, RA_SVC_FLAG_NONE,
280*3048Samaguire 	B_FALSE, RA_INSTANCE_IPV4_FORWARDING, RA_PROP_DEFAULT_IPV4_FORWARDING,
281*3048Samaguire 	B_FALSE },
282*3048Samaguire 	{ RA_OPT_IPV6_FORWARDING, RA_INSTANCE_IPV6_FORWARDING, RA_SVC_FLAG_NONE,
283*3048Samaguire 	B_FALSE, RA_INSTANCE_IPV6_FORWARDING, RA_PROP_DEFAULT_IPV6_FORWARDING,
284*3048Samaguire 	B_FALSE },
285*3048Samaguire 	{ NULL, NULL, RA_SVC_FLAG_NONE, B_FALSE, NULL, NULL, B_FALSE }
286*3048Samaguire };
287*3048Samaguire 
288*3048Samaguire typedef enum option_values {
289*3048Samaguire 	OPT_INVALID, OPT_ENABLED, OPT_DISABLED, OPT_DEFAULT, OPT_UNKNOWN
290*3048Samaguire } oval_t;
291*3048Samaguire 
292*3048Samaguire typedef struct ra_var {
293*3048Samaguire 	const char	*var_name;
294*3048Samaguire 	const char	*var_fmri;
295*3048Samaguire 	const char	*var_prop;
296*3048Samaguire 	char		*var_value;
297*3048Samaguire 	const char	*var_default_fmri;
298*3048Samaguire 	const char	*var_default_prop;
299*3048Samaguire 	char		*var_default_value;
300*3048Samaguire } ravar_t;
301*3048Samaguire 
302*3048Samaguire ravar_t ra_vars[] = {
303*3048Samaguire 	{ RA_VAR_IPV4_ROUTING_DAEMON, RA_INSTANCE_LEGACY_ROUTING_IPV4,
304*3048Samaguire 	RA_PROP_DAEMON, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV4,
305*3048Samaguire 	RA_PROP_DEFAULT_DAEMON, NULL},
306*3048Samaguire 	{ RA_VAR_IPV4_ROUTING_DAEMON_ARGS, RA_INSTANCE_LEGACY_ROUTING_IPV4,
307*3048Samaguire 	RA_PROP_DAEMON_ARGS, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV4,
308*3048Samaguire 	RA_PROP_DEFAULT_DAEMON_ARGS, NULL },
309*3048Samaguire 	{ RA_VAR_IPV4_ROUTING_STOP_CMD, RA_INSTANCE_LEGACY_ROUTING_IPV4,
310*3048Samaguire 	RA_PROP_DAEMON_STOP_CMD, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV4,
311*3048Samaguire 	RA_PROP_DEFAULT_STOP_CMD, NULL },
312*3048Samaguire 	{ RA_VAR_IPV6_ROUTING_DAEMON, RA_INSTANCE_LEGACY_ROUTING_IPV6,
313*3048Samaguire 	RA_PROP_DAEMON, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV6,
314*3048Samaguire 	RA_PROP_DEFAULT_DAEMON, NULL },
315*3048Samaguire 	{ RA_VAR_IPV6_ROUTING_DAEMON_ARGS, RA_INSTANCE_LEGACY_ROUTING_IPV6,
316*3048Samaguire 	RA_PROP_DAEMON_ARGS, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV6,
317*3048Samaguire 	RA_PROP_DEFAULT_DAEMON_ARGS, NULL },
318*3048Samaguire 	{ RA_VAR_IPV6_ROUTING_STOP_CMD, RA_INSTANCE_LEGACY_ROUTING_IPV6,
319*3048Samaguire 	RA_PROP_DAEMON_STOP_CMD, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV6,
320*3048Samaguire 	RA_PROP_DEFAULT_STOP_CMD, NULL },
321*3048Samaguire 	{ RA_VAR_ROUTING_SVCS, RA_INSTANCE_ROUTING_SETUP,
322*3048Samaguire 	RA_PROP_ROUTING_SVCS, NULL, RA_INSTANCE_ROUTING_SETUP,
323*3048Samaguire 	RA_PROP_DEFAULT_ROUTING_SVCS, NULL },
324*3048Samaguire 	{ NULL, NULL, NULL, NULL, NULL, NULL, NULL }
325*3048Samaguire };
326*3048Samaguire 
327*3048Samaguire char *v_opt[] = {
328*3048Samaguire #define	IPV4_ROUTING_DAEMON			0
329*3048Samaguire 	RA_VAR_IPV4_ROUTING_DAEMON,
330*3048Samaguire #define	IPV4_ROUTING_DAEMON_ARGS		1
331*3048Samaguire 	RA_VAR_IPV4_ROUTING_DAEMON_ARGS,
332*3048Samaguire #define	IPV4_ROUTING_STOP_CMD			2
333*3048Samaguire 	RA_VAR_IPV4_ROUTING_STOP_CMD,
334*3048Samaguire #define	IPV6_ROUTING_DAEMON			3
335*3048Samaguire 	RA_VAR_IPV6_ROUTING_DAEMON,
336*3048Samaguire #define	IPV6_ROUTING_DAEMON_ARGS		4
337*3048Samaguire 	RA_VAR_IPV6_ROUTING_DAEMON_ARGS,
338*3048Samaguire #define	IPV6_ROUTING_STOP_CMD			5
339*3048Samaguire 	RA_VAR_IPV6_ROUTING_STOP_CMD,
340*3048Samaguire #define	ROUTING_SVCS				6
341*3048Samaguire 	RA_VAR_ROUTING_SVCS,
342*3048Samaguire 	NULL
343*3048Samaguire };
344*3048Samaguire 
345*3048Samaguire #define	IS_IPV4_VAR(varname)	(strncmp(varname, "ipv4", 4) == 0)
346*3048Samaguire #define	IS_IPV6_VAR(varname)	(strncmp(varname, "ipv6", 4) == 0)
347*3048Samaguire #define	VAR_PROTO_MATCH(varname, proto)	(strncmp(varname, proto, 4) == 0)
348*3048Samaguire #define	IPV4_VARS_UNSET \
349*3048Samaguire 	(strtok(ra_vars[IPV4_ROUTING_DAEMON].var_value, " \t") == NULL && \
350*3048Samaguire 	strtok(ra_vars[IPV4_ROUTING_DAEMON_ARGS].var_value, " \t") == NULL && \
351*3048Samaguire 	strtok(ra_vars[IPV4_ROUTING_STOP_CMD].var_value, " \t") == NULL)
352*3048Samaguire 
353*3048Samaguire #define	IPV6_VARS_UNSET	\
354*3048Samaguire 	(strtok(ra_vars[IPV6_ROUTING_DAEMON].var_value, " \t") == NULL && \
355*3048Samaguire 	strtok(ra_vars[IPV6_ROUTING_DAEMON_ARGS].var_value, " \t") == NULL && \
356*3048Samaguire 	strtok(ra_vars[IPV6_ROUTING_STOP_CMD].var_value, " \t") == NULL)
357*3048Samaguire 
358*3048Samaguire /*
359*3048Samaguire  * Structure used in modify operations to tie property name and multiple values
360*3048Samaguire  * together.
361*3048Samaguire  */
362*3048Samaguire typedef struct ra_prop {
363*3048Samaguire 	char	*prop_name;
364*3048Samaguire 	char	**prop_values;
365*3048Samaguire 	int	prop_numvalues;
366*3048Samaguire } ra_prop_t;
367*3048Samaguire 
368*3048Samaguire typedef int (*ra_smf_cb_t)(void *, scf_walkinfo_t *);
369*3048Samaguire 
370*3048Samaguire /* Used to store program name */
371*3048Samaguire static const char	*myname;
372*3048Samaguire 
373*3048Samaguire static void usage(void);
374*3048Samaguire 
375*3048Samaguire static int ra_check_legacy_daemons(void);
376*3048Samaguire static int ra_upgrade_legacy_daemons(void);
377*3048Samaguire static int ra_upgrade_cmd(char, int, char **);
378*3048Samaguire static int ra_update(void);
379*3048Samaguire static int ra_update_routing_svcs(char *);
380*3048Samaguire static int ra_report(boolean_t, const char *);
381*3048Samaguire static int ra_smf_cb(ra_smf_cb_t, const char *, void *);
382*3048Samaguire static int ra_upgrade_from_legacy_conf(void);
383*3048Samaguire static int ra_parseconf(void);
384*3048Samaguire static int ra_parseopt(char *, int, raopt_t *);
385*3048Samaguire static int ra_parsevar(char *, ravar_t *);
386*3048Samaguire static oval_t ra_str2oval(const char *);
387*3048Samaguire static raopt_t *ra_str2opt(const char *);
388*3048Samaguire static void ra_resetopts(void);
389*3048Samaguire static ravar_t *ra_str2var(const char *);
390*3048Samaguire static void ra_resetvars(const char *);
391*3048Samaguire static char *ra_intloptname(const char *);
392*3048Samaguire 
393*3048Samaguire /* Callback for upgrade of legacy daemons */
394*3048Samaguire static int ra_upgrade_legacy_daemons_cb(void *, scf_walkinfo_t *);
395*3048Samaguire 
396*3048Samaguire /* Callbacks used to set/retieve routing options */
397*3048Samaguire static int ra_set_current_opt_cb(void *, scf_walkinfo_t *);
398*3048Samaguire static int ra_set_persistent_opt_cb(void *, scf_walkinfo_t *);
399*3048Samaguire static int ra_set_default_opt_cb(void *, scf_walkinfo_t *);
400*3048Samaguire static int ra_get_current_opt_cb(void *, scf_walkinfo_t *);
401*3048Samaguire static int ra_get_persistent_opt_cb(void *, scf_walkinfo_t *);
402*3048Samaguire static int ra_get_default_opt_cb(void *, scf_walkinfo_t *);
403*3048Samaguire static int ra_get_set_opt_common_cb(raopt_t *, scf_walkinfo_t *, boolean_t,
404*3048Samaguire     boolean_t);
405*3048Samaguire 
406*3048Samaguire /* Callbacks used to set/retrieve routing variables */
407*3048Samaguire static int ra_set_persistent_var_cb(void *, scf_walkinfo_t *);
408*3048Samaguire static int ra_get_persistent_var_cb(void *, scf_walkinfo_t *);
409*3048Samaguire static int ra_get_default_var_cb(void *, scf_walkinfo_t *);
410*3048Samaguire static int ra_mark_routing_svcs_cb(void *, scf_walkinfo_t *);
411*3048Samaguire 
412*3048Samaguire /* Callbacks used to list/set daemon properties and list daemons and states. */
413*3048Samaguire static int ra_list_props_cb(void *, scf_walkinfo_t *);
414*3048Samaguire static int ra_modify_props_cb(void *, scf_walkinfo_t *);
415*3048Samaguire static int ra_print_state_cb(void *, scf_walkinfo_t *);
416*3048Samaguire 
417*3048Samaguire /* Utility functions for SMF operations */
418*3048Samaguire static int ra_get_pg(scf_handle_t *, scf_instance_t *, const char *,
419*3048Samaguire     boolean_t, boolean_t, scf_propertygroup_t **);
420*3048Samaguire static int ra_get_boolean_prop(scf_handle_t *, scf_instance_t *,
421*3048Samaguire     const char *, const char *,  boolean_t, boolean_t, boolean_t *);
422*3048Samaguire static int ra_get_single_prop_as_string(scf_handle_t *, scf_instance_t *,
423*3048Samaguire     const char *, const char *, boolean_t, boolean_t, scf_type_t *, char **);
424*3048Samaguire static int ra_get_prop_as_string(scf_handle_t *, scf_instance_t *,
425*3048Samaguire     const char *, const char *, boolean_t, boolean_t, scf_type_t *, int *,
426*3048Samaguire     char ***);
427*3048Samaguire static void ra_free_prop_values(int, char **);
428*3048Samaguire static int ra_set_boolean_prop(scf_handle_t *, scf_instance_t *,
429*3048Samaguire     const char *, const char *, boolean_t, boolean_t);
430*3048Samaguire static int ra_set_prop_from_string(scf_handle_t *, scf_instance_t *,
431*3048Samaguire     const char *, const char *, scf_type_t, boolean_t, int,
432*3048Samaguire     const char **);
433*3048Samaguire 
434*3048Samaguire static void
435*3048Samaguire usage(void)
436*3048Samaguire {
437*3048Samaguire 	(void) fprintf(stderr, gettext(
438*3048Samaguire 	    "usage: %1$s [-p] [-R <root-dir>]\n"
439*3048Samaguire 	    "       %1$s [-e <option>] [-d <option>] [-r <option>]\n"
440*3048Samaguire 	    "           [-l <FMRI>] [-m <FMRI> key=value [...]]\n"
441*3048Samaguire 	    "           [-s <var>=<val>] [-R <root-dir>]\n"
442*3048Samaguire 	    "       %1$s -u\n\n"
443*3048Samaguire 	    "       <option> is one of:\n"
444*3048Samaguire 	    "       ipv4-forwarding\n"
445*3048Samaguire 	    "       ipv4-routing\n"
446*3048Samaguire 	    "       ipv6-forwarding\n"
447*3048Samaguire 	    "       ipv6-routing\n\n"
448*3048Samaguire 	    "       <var> is one of:\n"
449*3048Samaguire 	    "       ipv4-routing-daemon\n"
450*3048Samaguire 	    "       ipv4-routing-daemon-args\n"
451*3048Samaguire 	    "       ipv4-routing-stop-cmd\n"
452*3048Samaguire 	    "       ipv6-routing-daemon\n"
453*3048Samaguire 	    "       ipv6-routing-daemon-args\n"
454*3048Samaguire 	    "       ipv6-routing-stop-cmd\n"
455*3048Samaguire 	    "       routing-svcs\n"), myname);
456*3048Samaguire }
457*3048Samaguire 
458*3048Samaguire int
459*3048Samaguire main(int argc, char *argv[])
460*3048Samaguire {
461*3048Samaguire 	int		opt, opt_index, numargs, status = 0;
462*3048Samaguire 	int		numvalues, i;
463*3048Samaguire 	ssize_t		keylen;
464*3048Samaguire 	boolean_t	modify = B_FALSE, report = B_TRUE, update = B_FALSE;
465*3048Samaguire 	boolean_t	alt_root_set = B_FALSE;
466*3048Samaguire 	boolean_t	parseable = B_FALSE;
467*3048Samaguire 	char		*key, *nk, *keyend, *val, **vals, *options, *fmri;
468*3048Samaguire 	char		*parseopt = NULL;
469*3048Samaguire 	raopt_t		*raopt;
470*3048Samaguire 	ravar_t		*ravar;
471*3048Samaguire 	ra_prop_t	raprop;
472*3048Samaguire 
473*3048Samaguire 	myname = argv[0];
474*3048Samaguire 
475*3048Samaguire 	(void) setlocale(LC_ALL, "");
476*3048Samaguire 
477*3048Samaguire #if	!defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
478*3048Samaguire #define	TEXT_DOMAIN	"SYS_TEST"
479*3048Samaguire #endif
480*3048Samaguire 
481*3048Samaguire 	(void) textdomain(TEXT_DOMAIN);
482*3048Samaguire 
483*3048Samaguire 	/*
484*3048Samaguire 	 * Before processing any options, we parse /etc/inet/routing.conf
485*3048Samaguire 	 * (if present) and transfer values to SMF.
486*3048Samaguire 	 */
487*3048Samaguire 	if (ra_upgrade_from_legacy_conf() == -1)
488*3048Samaguire 		exit(EXIT_FAILURE);
489*3048Samaguire 	while ((opt = getopt(argc, argv, ":d:e:l:m:p:R:r:s:u")) != EOF) {
490*3048Samaguire 		switch (opt) {
491*3048Samaguire 		case 'd':
492*3048Samaguire 		case 'e':
493*3048Samaguire 		case 'r':
494*3048Samaguire 			if (alt_root_set) {
495*3048Samaguire 				if (ra_upgrade_cmd(opt, 1, &optarg) != 0)
496*3048Samaguire 					exit(EXIT_FAILURE);
497*3048Samaguire 				modify = B_TRUE;
498*3048Samaguire 				break;
499*3048Samaguire 			}
500*3048Samaguire 			if ((raopt = ra_str2opt(optarg)) != NULL) {
501*3048Samaguire 				/* Set current value appropriately */
502*3048Samaguire 				switch (opt) {
503*3048Samaguire 				case 'd':
504*3048Samaguire 					raopt->opt_enabled = B_FALSE;
505*3048Samaguire 					break;
506*3048Samaguire 				case 'e':
507*3048Samaguire 					/*
508*3048Samaguire 					 * Check legacy daemons, mark
509*3048Samaguire 					 * routing-svcs.
510*3048Samaguire 					 */
511*3048Samaguire 					if (IS_ROUTING_OPT(optarg) &&
512*3048Samaguire 					    ra_check_legacy_daemons() == -1)
513*3048Samaguire 						exit(EXIT_FAILURE);
514*3048Samaguire 					raopt->opt_enabled = B_TRUE;
515*3048Samaguire 					break;
516*3048Samaguire 				case 'r':
517*3048Samaguire 					/*
518*3048Samaguire 					 * This callback sets opt_enabled to
519*3048Samaguire 					 * the default value.
520*3048Samaguire 					 */
521*3048Samaguire 					ra_resetopts();
522*3048Samaguire 					if (ra_smf_cb(ra_get_default_opt_cb,
523*3048Samaguire 					    raopt->opt_default_fmri, raopt)
524*3048Samaguire 					    == -1)
525*3048Samaguire 						exit(EXIT_FAILURE);
526*3048Samaguire 					if (raopt->opt_enabled &&
527*3048Samaguire 					    IS_ROUTING_OPT(optarg) &&
528*3048Samaguire 					    ra_check_legacy_daemons() == -1)
529*3048Samaguire 						exit(EXIT_FAILURE);
530*3048Samaguire 					/* set value to default */
531*3048Samaguire 					raopt->opt_enabled =
532*3048Samaguire 					    raopt->opt_default_enabled;
533*3048Samaguire 					break;
534*3048Samaguire 				}
535*3048Samaguire 				if (ra_smf_cb(ra_set_persistent_opt_cb,
536*3048Samaguire 				    raopt->opt_fmri, raopt) == -1)
537*3048Samaguire 					exit(EXIT_FAILURE);
538*3048Samaguire 			} else if ((ravar = ra_str2var(optarg)) != NULL) {
539*3048Samaguire 				if (opt != 'r') {
540*3048Samaguire 					usage();
541*3048Samaguire 					exit(EXIT_FAILURE);
542*3048Samaguire 				}
543*3048Samaguire 				/* set current value to default */
544*3048Samaguire 				ra_resetopts();
545*3048Samaguire 				if (ra_smf_cb(ra_get_default_var_cb,
546*3048Samaguire 				    ravar->var_default_fmri, ravar) == -1)
547*3048Samaguire 					exit(EXIT_FAILURE);
548*3048Samaguire 				/* Need special case for routing-svcs var */
549*3048Samaguire 				if (strcmp(ravar->var_name, RA_VAR_ROUTING_SVCS)
550*3048Samaguire 				    == 0) {
551*3048Samaguire 					if (ra_update_routing_svcs(
552*3048Samaguire 					    ravar->var_default_value) == -1)
553*3048Samaguire 						exit(EXIT_FAILURE);
554*3048Samaguire 				} else if (ra_smf_cb(ra_set_persistent_var_cb,
555*3048Samaguire 				    ravar->var_fmri, ravar) == -1)
556*3048Samaguire 					exit(EXIT_FAILURE);
557*3048Samaguire 			} else {
558*3048Samaguire 				(void) fprintf(stderr, gettext(
559*3048Samaguire 				    "%1$s: invalid option: %2$s\n"), myname,
560*3048Samaguire 				    optarg);
561*3048Samaguire 				usage();
562*3048Samaguire 				exit(EXIT_FAILURE);
563*3048Samaguire 			}
564*3048Samaguire 			modify = B_TRUE;
565*3048Samaguire 			break;
566*3048Samaguire 		case 'l':
567*3048Samaguire 			if (ra_smf_cb(ra_list_props_cb, optarg, NULL) == -1)
568*3048Samaguire 				exit(EXIT_FAILURE);
569*3048Samaguire 			report = B_FALSE;
570*3048Samaguire 			break;
571*3048Samaguire 		case 'm':
572*3048Samaguire 			fmri = optarg;
573*3048Samaguire 			modify = B_TRUE;
574*3048Samaguire 			/*
575*3048Samaguire 			 * Argument list of key=value pairs, we need to
576*3048Samaguire 			 * collate all matching keys to set multiple values.
577*3048Samaguire 			 */
578*3048Samaguire 			numargs = 1;
579*3048Samaguire 			i = optind;
580*3048Samaguire 			for (numargs = 1; argv[i] != NULL && argv[i][0] != '-';
581*3048Samaguire 			    numargs++)
582*3048Samaguire 				i++;
583*3048Samaguire 			if (numargs == 1) {
584*3048Samaguire 				(void) fprintf(stderr, gettext(
585*3048Samaguire 				    "%s: key=value required for "
586*3048Samaguire 				    "property change\n"), myname);
587*3048Samaguire 				usage();
588*3048Samaguire 				exit(EXIT_FAILURE);
589*3048Samaguire 			}
590*3048Samaguire 			if (alt_root_set) {
591*3048Samaguire 				if (ra_upgrade_cmd(opt, numargs,
592*3048Samaguire 				    &argv[optind - 1]) == -1)
593*3048Samaguire 					exit(EXIT_FAILURE);
594*3048Samaguire 				optind += numargs - 1;
595*3048Samaguire 				break;
596*3048Samaguire 			}
597*3048Samaguire 			/*
598*3048Samaguire 			 * Collect all key=value pairs which use same key
599*3048Samaguire 			 * so we can add multiple property values.
600*3048Samaguire 			 */
601*3048Samaguire 			for (key = argv[optind]; key != NULL && key[0] != '-';
602*3048Samaguire 			    key = argv[++optind]) {
603*3048Samaguire 				if (key[0] == '\0')
604*3048Samaguire 					continue;
605*3048Samaguire 				vals = malloc(sizeof (char *));
606*3048Samaguire 				if ((vals[0] = strchr(key, '=')) == NULL) {
607*3048Samaguire 					(void) fprintf(stderr, gettext(
608*3048Samaguire 					    "%s: Malformed name=value "
609*3048Samaguire 					    "pair %s\n"), myname, key);
610*3048Samaguire 					exit(EXIT_FAILURE);
611*3048Samaguire 				}
612*3048Samaguire 				numvalues = 1;
613*3048Samaguire 				*(vals[0]) = '\0';
614*3048Samaguire 				(vals[0])++;
615*3048Samaguire 				i = optind + 1;
616*3048Samaguire 				for (nk = argv[i];
617*3048Samaguire 				    nk != NULL && nk[0] != '-';
618*3048Samaguire 				    nk = argv[++i]) {
619*3048Samaguire 					if (nk[0] == '\0')
620*3048Samaguire 						continue;
621*3048Samaguire 					if ((keyend = strchr(nk, '='))
622*3048Samaguire 					    == NULL) {
623*3048Samaguire 						(void) fprintf(stderr, gettext(
624*3048Samaguire 						    "%s: Malformed name=value "
625*3048Samaguire 						    " pair %s\n"), myname, nk);
626*3048Samaguire 						exit(EXIT_FAILURE);
627*3048Samaguire 					}
628*3048Samaguire 					if ((keylen = keyend - nk) !=
629*3048Samaguire 					    strlen(key))
630*3048Samaguire 						continue;
631*3048Samaguire 					if (strncmp(key, nk, keylen) == 0) {
632*3048Samaguire 						vals = realloc(vals, ++numvalues
633*3048Samaguire 						    * sizeof (char *));
634*3048Samaguire 						vals[numvalues - 1] = ++keyend;
635*3048Samaguire 						nk[0] = '\0';
636*3048Samaguire 						optind++;
637*3048Samaguire 					}
638*3048Samaguire 				}
639*3048Samaguire 				raprop.prop_name = key;
640*3048Samaguire 				raprop.prop_values = vals;
641*3048Samaguire 				raprop.prop_numvalues = numvalues;
642*3048Samaguire 				if (ra_smf_cb(ra_modify_props_cb, fmri,
643*3048Samaguire 				    &raprop) == -1)
644*3048Samaguire 					exit(EXIT_FAILURE);
645*3048Samaguire 			}
646*3048Samaguire 			break;
647*3048Samaguire 		case 'p':
648*3048Samaguire 			parseable = B_TRUE;
649*3048Samaguire 			parseopt = optarg;
650*3048Samaguire 			break;
651*3048Samaguire 		case 'R':
652*3048Samaguire 			if (chroot(optarg) == -1) {
653*3048Samaguire 				(void) fprintf(stderr, gettext(
654*3048Samaguire 				    "%1$s: failed to chroot to %2$s: %3$s\n"),
655*3048Samaguire 				    myname, optarg, strerror(errno));
656*3048Samaguire 				exit(EXIT_FAILURE);
657*3048Samaguire 			}
658*3048Samaguire 			alt_root_set = B_TRUE;
659*3048Samaguire 			report = B_FALSE;
660*3048Samaguire 			break;
661*3048Samaguire 		case 's':
662*3048Samaguire 			if (alt_root_set) {
663*3048Samaguire 				if (ra_upgrade_cmd(opt, 1, &optarg) == -1)
664*3048Samaguire 					exit(EXIT_FAILURE);
665*3048Samaguire 				modify = B_TRUE;
666*3048Samaguire 				break;
667*3048Samaguire 			}
668*3048Samaguire 			options = optarg;
669*3048Samaguire 			while (*options != '\0') {
670*3048Samaguire 				opt_index = getsubopt(&options, v_opt, &val);
671*3048Samaguire 				if (val == NULL) {
672*3048Samaguire 					usage();
673*3048Samaguire 					exit(EXIT_FAILURE);
674*3048Samaguire 				}
675*3048Samaguire 				if (opt_index == -1) {
676*3048Samaguire 					(void) fprintf(stderr, gettext(
677*3048Samaguire 					    "%1$s: invalid variable: %2$s\n"),
678*3048Samaguire 					    myname, optarg);
679*3048Samaguire 					usage();
680*3048Samaguire 					exit(EXIT_FAILURE);
681*3048Samaguire 				}
682*3048Samaguire 				ravar = &ra_vars[opt_index];
683*3048Samaguire 				/* Need special case for routing-svcs var */
684*3048Samaguire 				if (strcmp(ravar->var_name, RA_VAR_ROUTING_SVCS)
685*3048Samaguire 				    == 0) {
686*3048Samaguire 					if (ra_update_routing_svcs(val) == -1)
687*3048Samaguire 						return (-1);
688*3048Samaguire 				} else {
689*3048Samaguire 					ravar->var_value = strdup(val);
690*3048Samaguire 					if (ra_smf_cb(ra_set_persistent_var_cb,
691*3048Samaguire 					    ravar->var_fmri, ravar) == -1)
692*3048Samaguire 						exit(EXIT_FAILURE);
693*3048Samaguire 				}
694*3048Samaguire 			}
695*3048Samaguire 			modify = B_TRUE;
696*3048Samaguire 			break;
697*3048Samaguire 		case 'u':
698*3048Samaguire 			update = B_TRUE;
699*3048Samaguire 			break;
700*3048Samaguire 		case ':':
701*3048Samaguire 			/* if not 'p', usage failure */
702*3048Samaguire 			if (strcmp(argv[optind - 1], "-p") != 0) {
703*3048Samaguire 				(void) fprintf(stderr, gettext(
704*3048Samaguire 				    "%s: option requires an argument -%s\n"),
705*3048Samaguire 				    myname, argv[optind - 1]);
706*3048Samaguire 				usage();
707*3048Samaguire 				exit(EXIT_FAILURE);
708*3048Samaguire 			}
709*3048Samaguire 			parseable = B_TRUE;
710*3048Samaguire 			break;
711*3048Samaguire 		case '?':
712*3048Samaguire 			usage();
713*3048Samaguire 			exit(EXIT_FAILURE);
714*3048Samaguire 		}
715*3048Samaguire 	}
716*3048Samaguire 
717*3048Samaguire 	if (argc > optind) {
718*3048Samaguire 		/* There shouldn't be any extra args. */
719*3048Samaguire 		usage();
720*3048Samaguire 		exit(EXIT_FAILURE);
721*3048Samaguire 	}
722*3048Samaguire 
723*3048Samaguire 	if (parseable && (update || modify)) {
724*3048Samaguire 		(void) fprintf(stderr, gettext("%s: the -p option cannot be "
725*3048Samaguire 		    "used with any of -demrsu\n"), myname);
726*3048Samaguire 		usage();
727*3048Samaguire 		exit(EXIT_FAILURE);
728*3048Samaguire 	}
729*3048Samaguire 
730*3048Samaguire 	if (update && ! alt_root_set)
731*3048Samaguire 		status = ra_update();
732*3048Samaguire 
733*3048Samaguire 	if (report && !modify && !update)
734*3048Samaguire 		status = ra_report(parseable, parseopt);
735*3048Samaguire 
736*3048Samaguire 	return (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
737*3048Samaguire }
738*3048Samaguire 
739*3048Samaguire /*
740*3048Samaguire  * Upgrade legacy daemons,  mark to-be-enabled routing services.
741*3048Samaguire  */
742*3048Samaguire static int
743*3048Samaguire ra_check_legacy_daemons(void)
744*3048Samaguire {
745*3048Samaguire 	ravar_t		*routing_svcs = ra_str2var(RA_VAR_ROUTING_SVCS);
746*3048Samaguire 	ravar_t		*v4d = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON);
747*3048Samaguire 	ravar_t		*v6d = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON);
748*3048Samaguire 	char		*fmri, *nextfmri;
749*3048Samaguire 	boolean_t	mark = B_FALSE;
750*3048Samaguire 
751*3048Samaguire 	if (ra_smf_cb(ra_get_persistent_var_cb, routing_svcs->var_fmri,
752*3048Samaguire 	    routing_svcs) == -1)
753*3048Samaguire 		return (-1);
754*3048Samaguire 
755*3048Samaguire 	/* First unmark all services */
756*3048Samaguire 	if (ra_smf_cb(ra_mark_routing_svcs_cb, NULL, &mark) == -1)
757*3048Samaguire 		return (-1);
758*3048Samaguire 
759*3048Samaguire 	mark = B_TRUE;
760*3048Samaguire 	if (routing_svcs->var_value != NULL) {
761*3048Samaguire 		/*
762*3048Samaguire 		 * For routing-svcs variable, mark each named
763*3048Samaguire 		 * service as a current-routing-svc.
764*3048Samaguire 		 */
765*3048Samaguire 		if ((fmri = strdup(routing_svcs->var_value)) == NULL) {
766*3048Samaguire 			(void) fprintf(stderr, gettext(
767*3048Samaguire 			    "%s: out of memory\n"), myname);
768*3048Samaguire 			return (-1);
769*3048Samaguire 		}
770*3048Samaguire 		/* Now, mark each service named in routing-svcs. */
771*3048Samaguire 		for (nextfmri = strtok(fmri, " \t");
772*3048Samaguire 		    nextfmri != NULL;
773*3048Samaguire 		    nextfmri = strtok(NULL, " \t")) {
774*3048Samaguire 			if (ra_smf_cb(ra_mark_routing_svcs_cb, nextfmri,
775*3048Samaguire 			    &mark) == -1) {
776*3048Samaguire 				free(fmri);
777*3048Samaguire 				return (-1);
778*3048Samaguire 			}
779*3048Samaguire 		}
780*3048Samaguire 		free(fmri);
781*3048Samaguire 	}
782*3048Samaguire 
783*3048Samaguire 	/*
784*3048Samaguire 	 * Now check if legacy variables (if specified) map to SMF routing
785*3048Samaguire 	 * daemons.  If so, transfer associated daemon arguments.
786*3048Samaguire 	 */
787*3048Samaguire 	if (ra_upgrade_legacy_daemons() == -1)
788*3048Samaguire 		return (-1);
789*3048Samaguire 
790*3048Samaguire 	ra_resetvars(NULL);
791*3048Samaguire 	/*
792*3048Samaguire 	 * At this point, if the legacy services still have ipv4/ipv6
793*3048Samaguire 	 * routing daemons specified, we know they weren`t upgraded, so
794*3048Samaguire 	 * we mark them also.
795*3048Samaguire 	 */
796*3048Samaguire 	if (ra_smf_cb(ra_get_persistent_var_cb, v4d->var_fmri, v4d) == -1 ||
797*3048Samaguire 	    ra_smf_cb(ra_get_persistent_var_cb, v6d->var_fmri, v6d) == -1)
798*3048Samaguire 		return (-1);
799*3048Samaguire 
800*3048Samaguire 	if (v4d->var_value != NULL && strtok(v4d->var_value, " \t") != NULL &&
801*3048Samaguire 	    ra_smf_cb(ra_mark_routing_svcs_cb, RA_INSTANCE_LEGACY_ROUTING_IPV4,
802*3048Samaguire 	    &mark) == -1)
803*3048Samaguire 		return (-1);
804*3048Samaguire 	if (v6d->var_value != NULL && strtok(v6d->var_value, " \t") != NULL &&
805*3048Samaguire 	    ra_smf_cb(ra_mark_routing_svcs_cb, RA_INSTANCE_LEGACY_ROUTING_IPV6,
806*3048Samaguire 	    &mark) == -1)
807*3048Samaguire 		return (-1);
808*3048Samaguire 
809*3048Samaguire 	return (0);
810*3048Samaguire }
811*3048Samaguire 
812*3048Samaguire /*
813*3048Samaguire  * Retrieve legacy daemon variables,  and check if any SMF routing daemons
814*3048Samaguire  * run the daemons specified.  If so, the legacy configuration (arguments
815*3048Samaguire  * to the daemon) is transferred to the routeadm/daemon-args property
816*3048Samaguire  * of the corresponding instance.  From there,  the instance picks up the
817*3048Samaguire  * value and will transfer the daemon arguments to individiual properties
818*3048Samaguire  * when enabled.
819*3048Samaguire  */
820*3048Samaguire static int
821*3048Samaguire ra_upgrade_legacy_daemons(void)
822*3048Samaguire {
823*3048Samaguire 	ravar_t	*v4d = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON);
824*3048Samaguire 	ravar_t	*v6d = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON);
825*3048Samaguire 	ravar_t	*v4args = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON_ARGS);
826*3048Samaguire 	ravar_t	*v6args = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON_ARGS);
827*3048Samaguire 	ravar_t	*v4stop = ra_str2var(RA_VAR_IPV4_ROUTING_STOP_CMD);
828*3048Samaguire 	ravar_t	*v6stop = ra_str2var(RA_VAR_IPV6_ROUTING_STOP_CMD);
829*3048Samaguire 
830*3048Samaguire 	if (ra_smf_cb(ra_get_persistent_var_cb, v4d->var_fmri, v4d) == -1 ||
831*3048Samaguire 	    ra_smf_cb(ra_get_persistent_var_cb, v6d->var_fmri, v6d) == -1 ||
832*3048Samaguire 	    ra_smf_cb(ra_get_persistent_var_cb, v4args->var_fmri, v4args)
833*3048Samaguire 	    == -1 ||
834*3048Samaguire 	    ra_smf_cb(ra_get_persistent_var_cb, v6args->var_fmri, v6args)
835*3048Samaguire 	    == -1 ||
836*3048Samaguire 	    ra_smf_cb(ra_get_persistent_var_cb, v4stop->var_fmri, v4stop)
837*3048Samaguire 	    == -1 ||
838*3048Samaguire 	    ra_smf_cb(ra_get_persistent_var_cb, v6stop->var_fmri, v6stop)
839*3048Samaguire 	    == -1)
840*3048Samaguire 		return (-1);
841*3048Samaguire 
842*3048Samaguire 	return (ra_smf_cb(ra_upgrade_legacy_daemons_cb, NULL, NULL));
843*3048Samaguire }
844*3048Samaguire 
845*3048Samaguire /*
846*3048Samaguire  * Determine if service runs the same daemon as that which is specified
847*3048Samaguire  * in ipv4-routing-daemon or ipv6-routing-daemon.  If so, the associated
848*3048Samaguire  * daemon arguments are transferred to the service.
849*3048Samaguire  */
850*3048Samaguire 
851*3048Samaguire /* ARGSUSED0 */
852*3048Samaguire static int
853*3048Samaguire ra_upgrade_legacy_daemons_cb(void *data, scf_walkinfo_t *wip)
854*3048Samaguire {
855*3048Samaguire 	const char	*inst_fmri = wip->fmri;
856*3048Samaguire 	scf_instance_t	*inst = wip->inst;
857*3048Samaguire 	scf_handle_t	*h = scf_instance_handle(inst);
858*3048Samaguire 	char		*daemon, *l_daemon = NULL;
859*3048Samaguire 	ravar_t		*v4d = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON);
860*3048Samaguire 	ravar_t		*v6d = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON);
861*3048Samaguire 	ravar_t		*v4args = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON_ARGS);
862*3048Samaguire 	ravar_t		*v6args = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON_ARGS);
863*3048Samaguire 	ravar_t		*v4stop = ra_str2var(RA_VAR_IPV4_ROUTING_STOP_CMD);
864*3048Samaguire 	ravar_t		*v6stop = ra_str2var(RA_VAR_IPV6_ROUTING_STOP_CMD);
865*3048Samaguire 	ravar_t		*routing_svcs = ra_str2var(RA_VAR_ROUTING_SVCS);
866*3048Samaguire 	boolean_t	mark, marked;
867*3048Samaguire 	char		*new_routing_svcs;
868*3048Samaguire 
869*3048Samaguire 	/*
870*3048Samaguire 	 * Ensure instance is a routing service, and not one of the
871*3048Samaguire 	 * legacy instances - if it is, the daemon property is already
872*3048Samaguire 	 * set to the legacy daemon.
873*3048Samaguire 	 */
874*3048Samaguire 	if (ra_get_single_prop_as_string(h, inst, RA_PG_ROUTEADM,
875*3048Samaguire 	    RA_PROP_DAEMON, B_TRUE, B_FALSE, NULL, &daemon) == -1 ||
876*3048Samaguire 	    strcmp(RA_INSTANCE_LEGACY_ROUTING_IPV4, inst_fmri) == 0 ||
877*3048Samaguire 	    strcmp(RA_INSTANCE_LEGACY_ROUTING_IPV6, inst_fmri) == 0)
878*3048Samaguire 		return (0);
879*3048Samaguire 
880*3048Samaguire 	/* A legacy daemon may be defined */
881*3048Samaguire 	(void) ra_get_single_prop_as_string(h, inst, RA_PG_ROUTEADM,
882*3048Samaguire 	    RA_PROP_LEGACY_DAEMON, B_TRUE, B_FALSE, NULL, &l_daemon);
883*3048Samaguire 
884*3048Samaguire 	/*
885*3048Samaguire 	 * If we match daemon/legacy_daemon with ipv4-routing-daemon or
886*3048Samaguire 	 * ipv6-routing-daemon values, transfer daemon-args value
887*3048Samaguire 	 * to the matching service.
888*3048Samaguire 	 */
889*3048Samaguire 	if (v4d->var_value != NULL && (strcmp(v4d->var_value, daemon) == 0 ||
890*3048Samaguire 	    (l_daemon != NULL && strcmp(v4d->var_value, l_daemon) == 0))) {
891*3048Samaguire 		(void) printf(gettext("%s: migrating daemon configuration "
892*3048Samaguire 		    "for %s to %s\n"), myname, l_daemon != NULL ?
893*3048Samaguire 		    l_daemon : daemon, inst_fmri);
894*3048Samaguire 		/* Transfer daemon-args value, clear legacy v4 values */
895*3048Samaguire 		if (ra_set_prop_from_string(h, inst, RA_PG_ROUTEADM,
896*3048Samaguire 		    RA_PROP_DAEMON_ARGS, SCF_TYPE_ASTRING, B_TRUE, 1,
897*3048Samaguire 		    (const char **)&(v4args->var_value)) == -1)
898*3048Samaguire 			return (-1);
899*3048Samaguire 		ra_resetvars(RA_PROPVAL_PROTO_IPV4);
900*3048Samaguire 		if (ra_smf_cb(ra_set_persistent_var_cb,
901*3048Samaguire 		    RA_INSTANCE_LEGACY_ROUTING_IPV4, v4d) == -1 ||
902*3048Samaguire 		    ra_smf_cb(ra_set_persistent_var_cb,
903*3048Samaguire 		    RA_INSTANCE_LEGACY_ROUTING_IPV4, v4args) == -1 ||
904*3048Samaguire 		    ra_smf_cb(ra_set_persistent_var_cb,
905*3048Samaguire 		    RA_INSTANCE_LEGACY_ROUTING_IPV4, v4stop) == -1)
906*3048Samaguire 			return (-1);
907*3048Samaguire 	} else if (v6d->var_value != NULL && (strcmp(v6d->var_value, daemon)
908*3048Samaguire 	    == 0 ||
909*3048Samaguire 	    (l_daemon != NULL && strcmp(v6d->var_value, l_daemon) == 0))) {
910*3048Samaguire 		(void) printf(gettext("%s: migrating daemon configuration "
911*3048Samaguire 		    "for %s to %s\n"), myname, l_daemon != NULL ?
912*3048Samaguire 		    l_daemon : daemon, inst_fmri);
913*3048Samaguire 		/* Transfer daemon-args value, clear legacy v6 values */
914*3048Samaguire 		if (ra_set_prop_from_string(h, inst, RA_PG_ROUTEADM,
915*3048Samaguire 		    RA_PROP_DAEMON_ARGS, SCF_TYPE_ASTRING, B_TRUE, 1,
916*3048Samaguire 		    (const char **)&(v6args->var_value)) == -1)
917*3048Samaguire 			return (-1);
918*3048Samaguire 		ra_resetvars(RA_PROPVAL_PROTO_IPV6);
919*3048Samaguire 		if (ra_smf_cb(ra_set_persistent_var_cb,
920*3048Samaguire 		    RA_INSTANCE_LEGACY_ROUTING_IPV6, v6d) == -1 ||
921*3048Samaguire 		    ra_smf_cb(ra_set_persistent_var_cb,
922*3048Samaguire 		    RA_INSTANCE_LEGACY_ROUTING_IPV6, v6args) == -1 ||
923*3048Samaguire 		    ra_smf_cb(ra_set_persistent_var_cb,
924*3048Samaguire 		    RA_INSTANCE_LEGACY_ROUTING_IPV6, v6stop) == -1)
925*3048Samaguire 			return (-1);
926*3048Samaguire 	} else
927*3048Samaguire 		return (0);
928*3048Samaguire 
929*3048Samaguire 	/*
930*3048Samaguire 	 * If service is unmarked at this point, add it to routing-svcs and
931*3048Samaguire 	 * mark it.
932*3048Samaguire 	 */
933*3048Samaguire 	if (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
934*3048Samaguire 	    RA_PROP_CURR_ROUTING_SVC, B_FALSE, B_FALSE, &marked) == -1 ||
935*3048Samaguire 	    marked == B_FALSE) {
936*3048Samaguire 		mark = B_TRUE;
937*3048Samaguire 		if (ra_smf_cb(ra_mark_routing_svcs_cb, inst_fmri, &mark)
938*3048Samaguire 		    == -1 ||
939*3048Samaguire 		    ra_smf_cb(ra_get_persistent_var_cb, routing_svcs->var_fmri,
940*3048Samaguire 		    routing_svcs) == -1)
941*3048Samaguire 			return (-1);
942*3048Samaguire 		if ((new_routing_svcs =
943*3048Samaguire 		    malloc(strlen(routing_svcs->var_value) +
944*3048Samaguire 		    strlen(inst_fmri) + 2)) == NULL) {
945*3048Samaguire 			(void) fprintf(stderr, gettext(
946*3048Samaguire 			    "%s: out of memory"), myname);
947*3048Samaguire 			return (-1);
948*3048Samaguire 		}
949*3048Samaguire 		if (strlen(routing_svcs->var_value) == 0)
950*3048Samaguire 			(void) snprintf(new_routing_svcs,
951*3048Samaguire 			    strlen(inst_fmri) + 1, "%s", inst_fmri);
952*3048Samaguire 		else
953*3048Samaguire 			(void) snprintf(new_routing_svcs,
954*3048Samaguire 			    strlen(routing_svcs->var_value) +
955*3048Samaguire 			    strlen(inst_fmri) + 2, "%s %s",
956*3048Samaguire 			    routing_svcs->var_value, inst_fmri);
957*3048Samaguire 		free(routing_svcs->var_value);
958*3048Samaguire 		routing_svcs->var_value = new_routing_svcs;
959*3048Samaguire 		(void) smf_refresh_instance(inst_fmri);
960*3048Samaguire 		return (ra_smf_cb(ra_set_persistent_var_cb,
961*3048Samaguire 		    routing_svcs->var_fmri, routing_svcs));
962*3048Samaguire 	}
963*3048Samaguire 	(void) smf_refresh_instance(inst_fmri);
964*3048Samaguire 	return (0);
965*3048Samaguire }
966*3048Samaguire 
967*3048Samaguire /*
968*3048Samaguire  * If we are upgrading,  append operation to <alt_root>/var/svc/profile/upgrade.
969*3048Samaguire  */
970*3048Samaguire static int
971*3048Samaguire ra_upgrade_cmd(char opt, int argc, char **argv)
972*3048Samaguire {
973*3048Samaguire 	FILE	*fp;
974*3048Samaguire 	int	i;
975*3048Samaguire 
976*3048Samaguire 	if ((fp = fopen(RA_SMF_UPGRADE_FILE, "a+")) == NULL) {
977*3048Samaguire 		(void) fprintf(stderr, gettext(
978*3048Samaguire 		    "%1$s: failed to open %2$s: %3$s\n"),
979*3048Samaguire 		    myname, RA_SMF_UPGRADE_FILE, strerror(errno));
980*3048Samaguire 		return (-1);
981*3048Samaguire 	}
982*3048Samaguire 	(void) fprintf(fp, "/sbin/routeadm -%c ", opt);
983*3048Samaguire 	if (argv != NULL) {
984*3048Samaguire 		for (i = 0; i < argc; i++)
985*3048Samaguire 			(void) fprintf(fp, "%s ", argv[i]);
986*3048Samaguire 	}
987*3048Samaguire 	(void) fprintf(fp, "%s\n", RA_SMF_UPGRADE_MSG);
988*3048Samaguire 	(void) fclose(fp);
989*3048Samaguire 	return (0);
990*3048Samaguire }
991*3048Samaguire 
992*3048Samaguire /*
993*3048Samaguire  * Set current state to "next boot" state, i.e. if general/enabled
994*3048Samaguire  * value is overlaid by a general_ovr/enabled value, set the current state
995*3048Samaguire  * to the value of the latter.  Doing this applies "next boot" changes to
996*3048Samaguire  * the current setup.
997*3048Samaguire  */
998*3048Samaguire static int
999*3048Samaguire ra_update(void)
1000*3048Samaguire {
1001*3048Samaguire 	int	i, ret = 0;
1002*3048Samaguire 
1003*3048Samaguire 	if (ra_check_legacy_daemons() == -1)
1004*3048Samaguire 		return (-1);
1005*3048Samaguire 	for (i = 0; ra_opts[i].opt_name != NULL; i++) {
1006*3048Samaguire 		if ((ret = ra_smf_cb(ra_set_current_opt_cb, ra_opts[i].opt_fmri,
1007*3048Samaguire 		    &ra_opts[i])) == -1)
1008*3048Samaguire 			break;
1009*3048Samaguire 	}
1010*3048Samaguire 	return (ret);
1011*3048Samaguire }
1012*3048Samaguire 
1013*3048Samaguire /*
1014*3048Samaguire  * Here we catch the special case where ipv4/ipv6 routing was enabled,
1015*3048Samaguire  * and the user updates the routing-svcs list.  The problem is that
1016*3048Samaguire  * the enabled state is the result of services on the old routing-svcs list
1017*3048Samaguire  * being enabled, and we want to support users doing something like this:
1018*3048Samaguire  *
1019*3048Samaguire  * # routeadm -s routing-svcs=route -e ipv4-routing -u
1020*3048Samaguire  *
1021*3048Samaguire  * followed by
1022*3048Samaguire  *
1023*3048Samaguire  * # routeadm -s routing-svcs=rdisc -u
1024*3048Samaguire  *
1025*3048Samaguire  * To do this, we need to:
1026*3048Samaguire  *	- cache the old ipv4-routing/ipv6-routing values.
1027*3048Samaguire  *	- persistently disable the old routing-svcs list.
1028*3048Samaguire  *	- if ipv4-routing was enabled, mark and persistently enable all the new
1029*3048Samaguire  *	v4 routing-svcs
1030*3048Samaguire  *	- if ipv6-routing was enabled, mark and persistently enable all the new
1031*3048Samaguire  *	v6 routing-svcs.
1032*3048Samaguire  * This will result in the next "-u" switching on the new routing-svcs, and
1033*3048Samaguire  * switching off the old ones,  as the user would expect.
1034*3048Samaguire  */
1035*3048Samaguire static int
1036*3048Samaguire ra_update_routing_svcs(char *routing_svcs_new)
1037*3048Samaguire {
1038*3048Samaguire 	raopt_t		*v4opt = ra_str2opt(RA_OPT_IPV4_ROUTING);
1039*3048Samaguire 	raopt_t		*v6opt = ra_str2opt(RA_OPT_IPV6_ROUTING);
1040*3048Samaguire 	ravar_t		*routing_svcs = ra_str2var(RA_VAR_ROUTING_SVCS);
1041*3048Samaguire 	char		*routing_svcs_old, *fmri;
1042*3048Samaguire 	boolean_t	v4_old, v6_old, mark = B_FALSE;
1043*3048Samaguire 
1044*3048Samaguire 	ra_resetopts();
1045*3048Samaguire 	if (ra_smf_cb(ra_get_persistent_opt_cb, v4opt->opt_fmri, v4opt) == -1 ||
1046*3048Samaguire 	    ra_smf_cb(ra_get_persistent_opt_cb, v6opt->opt_fmri, v6opt) == -1 ||
1047*3048Samaguire 	    ra_smf_cb(ra_get_persistent_var_cb, routing_svcs->var_fmri,
1048*3048Samaguire 	    routing_svcs) == -1)
1049*3048Samaguire 		return (-1);
1050*3048Samaguire 	v4_old = v4opt->opt_enabled;
1051*3048Samaguire 	v6_old = v6opt->opt_enabled;
1052*3048Samaguire 	routing_svcs_old = routing_svcs->var_value;
1053*3048Samaguire 	routing_svcs->var_value = routing_svcs_new;
1054*3048Samaguire 
1055*3048Samaguire 	if (ra_smf_cb(ra_set_persistent_var_cb, routing_svcs->var_fmri,
1056*3048Samaguire 	    routing_svcs) == -1) {
1057*3048Samaguire 		free(routing_svcs_old);
1058*3048Samaguire 		return (-1);
1059*3048Samaguire 	}
1060*3048Samaguire 
1061*3048Samaguire 	if (!v4_old && !v6_old) {
1062*3048Samaguire 		/* We don`t need to do anything, since services were disabled */
1063*3048Samaguire 		free(routing_svcs_old);
1064*3048Samaguire 		return (0);
1065*3048Samaguire 	}
1066*3048Samaguire 	v4opt->opt_enabled = B_FALSE;
1067*3048Samaguire 	v6opt->opt_enabled = B_FALSE;
1068*3048Samaguire 
1069*3048Samaguire 	/* Persistently disable each old v4/v6 "routing-svc" */
1070*3048Samaguire 	for (fmri = strtok(routing_svcs_old, " \t"); fmri != NULL;
1071*3048Samaguire 	    fmri = strtok(NULL, " \t")) {
1072*3048Samaguire 		if (ra_smf_cb(ra_mark_routing_svcs_cb, fmri, &mark) == -1) {
1073*3048Samaguire 			free(routing_svcs_old);
1074*3048Samaguire 			return (-1);
1075*3048Samaguire 		}
1076*3048Samaguire 		if (v4_old &&
1077*3048Samaguire 		    ra_smf_cb(ra_set_persistent_opt_cb, fmri, v4opt) == -1) {
1078*3048Samaguire 			free(routing_svcs_old);
1079*3048Samaguire 			return (-1);
1080*3048Samaguire 		}
1081*3048Samaguire 		if (v6_old &&
1082*3048Samaguire 		    ra_smf_cb(ra_set_persistent_opt_cb, fmri, v6opt) == -1) {
1083*3048Samaguire 			free(routing_svcs_old);
1084*3048Samaguire 			return (-1);
1085*3048Samaguire 		}
1086*3048Samaguire 	}
1087*3048Samaguire 	free(routing_svcs_old);
1088*3048Samaguire 	v4opt->opt_enabled = v4_old;
1089*3048Samaguire 	v6opt->opt_enabled = v6_old;
1090*3048Samaguire 
1091*3048Samaguire 	/* Persistently enable each new v4/v6 "routing-svc" */
1092*3048Samaguire 	mark = B_TRUE;
1093*3048Samaguire 	for (fmri = strtok(routing_svcs_new, " \t"); fmri != NULL;
1094*3048Samaguire 	    fmri = strtok(NULL, " \t")) {
1095*3048Samaguire 		if (ra_smf_cb(ra_mark_routing_svcs_cb, fmri, &mark) == -1)
1096*3048Samaguire 			return (-1);
1097*3048Samaguire 		if (v4_old &&
1098*3048Samaguire 		    ra_smf_cb(ra_set_persistent_opt_cb, fmri, v4opt) == -1)
1099*3048Samaguire 			return (-1);
1100*3048Samaguire 		if (v6_old &&
1101*3048Samaguire 		    ra_smf_cb(ra_set_persistent_opt_cb, fmri, v6opt) == -1)
1102*3048Samaguire 			return (-1);
1103*3048Samaguire 	}
1104*3048Samaguire 	return (0);
1105*3048Samaguire }
1106*3048Samaguire 
1107*3048Samaguire /*
1108*3048Samaguire  * Display status,  in parseable form if required.  If param is
1109*3048Samaguire  * specified,  only the named option/variable is displayed  (this option is
1110*3048Samaguire  * for parseable display only).
1111*3048Samaguire  */
1112*3048Samaguire static int
1113*3048Samaguire ra_report(boolean_t parseable, const char *param)
1114*3048Samaguire {
1115*3048Samaguire 	int		i;
1116*3048Samaguire 	char		*c_state, *d_state, *p_state, *p_var, *d_var;
1117*3048Samaguire 	char		*enabled = "enabled";
1118*3048Samaguire 	char		*disabled = "disabled";
1119*3048Samaguire 	boolean_t	param_found = B_FALSE;
1120*3048Samaguire 
1121*3048Samaguire 	if (!parseable) {
1122*3048Samaguire 		(void) printf(gettext(
1123*3048Samaguire 		    "              Configuration   Current              "
1124*3048Samaguire 		    "Current\n"
1125*3048Samaguire 		    "                     Option   Configuration        "
1126*3048Samaguire 		    "System State\n"
1127*3048Samaguire 		    "---------------------------------------------------"
1128*3048Samaguire 		    "------------\n"));
1129*3048Samaguire 	}
1130*3048Samaguire 	for (i = 0; ra_opts[i].opt_name != NULL; i++) {
1131*3048Samaguire 		if (param != NULL) {
1132*3048Samaguire 			if (strcmp(ra_opts[i].opt_name, param) == 0)
1133*3048Samaguire 				param_found = B_TRUE;
1134*3048Samaguire 			else
1135*3048Samaguire 				continue;
1136*3048Samaguire 		}
1137*3048Samaguire 		if (ra_smf_cb(ra_get_current_opt_cb,
1138*3048Samaguire 		    ra_opts[i].opt_fmri, &ra_opts[i]) == -1)
1139*3048Samaguire 			return (-1);
1140*3048Samaguire 		c_state = ra_opts[i].opt_enabled ? enabled : disabled;
1141*3048Samaguire 		ra_resetopts();
1142*3048Samaguire 		if (ra_smf_cb(ra_get_persistent_opt_cb,
1143*3048Samaguire 		    ra_opts[i].opt_fmri, &ra_opts[i]) == -1)
1144*3048Samaguire 			return (-1);
1145*3048Samaguire 		p_state = ra_opts[i].opt_enabled ? enabled : disabled;
1146*3048Samaguire 		ra_resetopts();
1147*3048Samaguire 		if (ra_smf_cb(ra_get_default_opt_cb,
1148*3048Samaguire 		    ra_opts[i].opt_default_fmri, &ra_opts[i]) == -1)
1149*3048Samaguire 			return (-1);
1150*3048Samaguire 		d_state = ra_opts[i].opt_default_enabled ? enabled : disabled;
1151*3048Samaguire 		ra_resetopts();
1152*3048Samaguire 		if (parseable) {
1153*3048Samaguire 			if (param == NULL)
1154*3048Samaguire 				(void) printf("%s ", ra_opts[i].opt_name);
1155*3048Samaguire 			(void) printf("persistent=%s default=%s "
1156*3048Samaguire 			    "current=%s\n", p_state, d_state, c_state);
1157*3048Samaguire 		} else {
1158*3048Samaguire 			(void) printf(gettext("%1$27s   %2$-21s%3$s\n"),
1159*3048Samaguire 			    ra_intloptname(ra_opts[i].opt_name),
1160*3048Samaguire 			    p_state, c_state);
1161*3048Samaguire 		}
1162*3048Samaguire 	}
1163*3048Samaguire 	if (!parseable)
1164*3048Samaguire 		(void) printf("\n");
1165*3048Samaguire 
1166*3048Samaguire 	ra_resetvars(NULL);
1167*3048Samaguire 
1168*3048Samaguire 	/* Gather persistent/default variable values */
1169*3048Samaguire 	for (i = 0; ra_vars[i].var_name != NULL; i++) {
1170*3048Samaguire 		if (ra_smf_cb(ra_get_persistent_var_cb,
1171*3048Samaguire 		    ra_vars[i].var_fmri, &ra_vars[i]) == -1 ||
1172*3048Samaguire 		    ra_smf_cb(ra_get_default_var_cb,
1173*3048Samaguire 		    ra_vars[i].var_default_fmri, &ra_vars[i]) == -1)
1174*3048Samaguire 			return (-1);
1175*3048Samaguire 
1176*3048Samaguire 	}
1177*3048Samaguire 	for (i = 0; ra_vars[i].var_name != NULL; i++) {
1178*3048Samaguire 		if (param != NULL) {
1179*3048Samaguire 			if (strcmp(ra_vars[i].var_name, param) == 0)
1180*3048Samaguire 				param_found = B_TRUE;
1181*3048Samaguire 			else
1182*3048Samaguire 				continue;
1183*3048Samaguire 		}
1184*3048Samaguire 		p_var = ra_vars[i].var_value == NULL ? "":
1185*3048Samaguire 		    ra_vars[i].var_value;
1186*3048Samaguire 		d_var = ra_vars[i].var_default_value == NULL ?
1187*3048Samaguire 		    "": ra_vars[i].var_default_value;
1188*3048Samaguire 		if (parseable) {
1189*3048Samaguire 			if (param == NULL)
1190*3048Samaguire 				(void) printf("%s ", ra_vars[i].var_name);
1191*3048Samaguire 			(void) printf("persistent=\"%s\" "
1192*3048Samaguire 			    "default=\"%s\" \n", p_var, d_var);
1193*3048Samaguire 		} else {
1194*3048Samaguire 			/* If daemon variables are not set, do not display. */
1195*3048Samaguire 			if ((IS_IPV4_VAR(ra_vars[i].var_name) &&
1196*3048Samaguire 			    IPV4_VARS_UNSET) ||
1197*3048Samaguire 			    (IS_IPV6_VAR(ra_vars[i].var_name) &&
1198*3048Samaguire 			    IPV6_VARS_UNSET))
1199*3048Samaguire 				continue;
1200*3048Samaguire 			(void) printf(gettext("%1$27s   \"%2$s\"\n"),
1201*3048Samaguire 			    ra_intloptname(ra_vars[i].var_name), p_var);
1202*3048Samaguire 		}
1203*3048Samaguire 	}
1204*3048Samaguire 
1205*3048Samaguire 	if (param != NULL && !param_found) {
1206*3048Samaguire 		(void) fprintf(stderr, gettext(
1207*3048Samaguire 		    "%s: no such option/variable %s\n"), myname, param);
1208*3048Samaguire 		return (-1);
1209*3048Samaguire 	}
1210*3048Samaguire 	if (parseable)
1211*3048Samaguire 		return (0);
1212*3048Samaguire 	(void) printf(gettext("\nRouting daemons:\n"));
1213*3048Samaguire 	(void) printf("\n                      %s   %s\n", "STATE", "FMRI");
1214*3048Samaguire 	if (ra_smf_cb(ra_print_state_cb, NULL, NULL) == -1)
1215*3048Samaguire 		return (-1);
1216*3048Samaguire 	return (0);
1217*3048Samaguire }
1218*3048Samaguire 
1219*3048Samaguire /*
1220*3048Samaguire  * Call scf_walk_fmri() with appropriate function, fmri, and data.
1221*3048Samaguire  * A NULL fmri causes scf_walk_fmri() to run on all instances.  We make
1222*3048Samaguire  * use of this many times in applying changes to the routing services.
1223*3048Samaguire  */
1224*3048Samaguire static int
1225*3048Samaguire ra_smf_cb(ra_smf_cb_t cbfunc, const char *fmri, void *data)
1226*3048Samaguire {
1227*3048Samaguire 	scf_handle_t	*h;
1228*3048Samaguire 	int		exit_status = 0;
1229*3048Samaguire 
1230*3048Samaguire 	if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
1231*3048Samaguire 	    scf_handle_bind(h) == -1) {
1232*3048Samaguire 		(void) fprintf(stderr, gettext(
1233*3048Samaguire 		    "%s: cannot connect to SMF repository\n"), myname);
1234*3048Samaguire 		return (-1);
1235*3048Samaguire 	}
1236*3048Samaguire 	return (scf_walk_fmri(h, fmri == NULL ? 0 : 1,
1237*3048Samaguire 	    fmri == NULL ? NULL : (char **)&fmri, 0,
1238*3048Samaguire 	    cbfunc, data, &exit_status, uu_die));
1239*3048Samaguire }
1240*3048Samaguire 
1241*3048Samaguire /*
1242*3048Samaguire  * Applies persistent configuration settings to current setup.
1243*3048Samaguire  */
1244*3048Samaguire static int
1245*3048Samaguire ra_set_current_opt_cb(void *data, scf_walkinfo_t *wip)
1246*3048Samaguire {
1247*3048Samaguire 	return (ra_get_set_opt_common_cb(data, wip, B_FALSE, B_FALSE));
1248*3048Samaguire }
1249*3048Samaguire 
1250*3048Samaguire /*
1251*3048Samaguire  * Sets persistent value for option,  to be applied on next boot
1252*3048Samaguire  * or by "routeadm -u".
1253*3048Samaguire  */
1254*3048Samaguire static int
1255*3048Samaguire ra_set_persistent_opt_cb(void *data, scf_walkinfo_t *wip)
1256*3048Samaguire {
1257*3048Samaguire 	return (ra_get_set_opt_common_cb(data, wip, B_TRUE, B_FALSE));
1258*3048Samaguire }
1259*3048Samaguire 
1260*3048Samaguire static int
1261*3048Samaguire ra_get_current_opt_cb(void *data, scf_walkinfo_t *wip)
1262*3048Samaguire {
1263*3048Samaguire 	return (ra_get_set_opt_common_cb(data, wip, B_FALSE, B_TRUE));
1264*3048Samaguire }
1265*3048Samaguire 
1266*3048Samaguire static int
1267*3048Samaguire ra_get_persistent_opt_cb(void *data, scf_walkinfo_t *wip)
1268*3048Samaguire {
1269*3048Samaguire 	return (ra_get_set_opt_common_cb(data, wip, B_TRUE, B_TRUE));
1270*3048Samaguire }
1271*3048Samaguire 
1272*3048Samaguire /*
1273*3048Samaguire  * Shared function that either sets or determines persistent or current
1274*3048Samaguire  * state. Setting persistent state (for next boot) involves setting
1275*3048Samaguire  * the general_ovr/enabled value to the current service state, and
1276*3048Samaguire  * the general/enabled value to the desired (next-boot) state.
1277*3048Samaguire  * Setting current state involves removing the temporary state
1278*3048Samaguire  * setting so the persistent state has effect.
1279*3048Samaguire  *
1280*3048Samaguire  * Persistent state is reported as being enabled if any of the
1281*3048Samaguire  * candidate services have a general/enabled value set to true,
1282*3048Samaguire  * while current state is reported as being enabled if any of the
1283*3048Samaguire  * candidate services has a general_ovr/enabled or general/enabled
1284*3048Samaguire  * value set to true.
1285*3048Samaguire  */
1286*3048Samaguire static int
1287*3048Samaguire ra_get_set_opt_common_cb(raopt_t *raopt, scf_walkinfo_t *wip,
1288*3048Samaguire     boolean_t persistent, boolean_t get)
1289*3048Samaguire {
1290*3048Samaguire 	const char		*inst_fmri = wip->fmri;
1291*3048Samaguire 	scf_instance_t		*inst = wip->inst;
1292*3048Samaguire 	scf_instance_t		*rinst = NULL;
1293*3048Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
1294*3048Samaguire 	scf_propertygroup_t	*routeadm_pg;
1295*3048Samaguire 	boolean_t		persistent_state_enabled;
1296*3048Samaguire 	boolean_t		temporary_state_enabled;
1297*3048Samaguire 	boolean_t		current_state_enabled;
1298*3048Samaguire 	boolean_t		curr_svc = B_TRUE;
1299*3048Samaguire 	boolean_t		found_proto;
1300*3048Samaguire 	char			**protolist = NULL;
1301*3048Samaguire 	int			i, ret, numvalues = 0;
1302*3048Samaguire 
1303*3048Samaguire 	/*
1304*3048Samaguire 	 * Ensure we are dealing with a routeadm-managed service.  If
1305*3048Samaguire 	 * the FMRI used for walking instances is NULL,  it is reasonable
1306*3048Samaguire 	 * that a service not have a routeadm property group as we will
1307*3048Samaguire 	 * check all services in this case.
1308*3048Samaguire 	 */
1309*3048Samaguire 	if (ra_get_pg(h, inst, RA_PG_ROUTEADM, B_TRUE, raopt->opt_fmri != NULL,
1310*3048Samaguire 	    &routeadm_pg) == -1) {
1311*3048Samaguire 			/* Not a routing service, not an error. */
1312*3048Samaguire 			if (scf_error() == SCF_ERROR_NOT_FOUND &&
1313*3048Samaguire 			    raopt->opt_fmri == NULL)
1314*3048Samaguire 				return (0);
1315*3048Samaguire 			return (-1);
1316*3048Samaguire 	}
1317*3048Samaguire 	scf_pg_destroy(routeadm_pg);
1318*3048Samaguire 
1319*3048Samaguire 	/* Services with no "protocol" property are not routing daemons */
1320*3048Samaguire 	if (raopt->opt_fmri == NULL && ra_get_prop_as_string(h, inst,
1321*3048Samaguire 	    RA_PG_ROUTEADM, RA_PROP_PROTO, B_TRUE, B_FALSE, NULL, &numvalues,
1322*3048Samaguire 	    &protolist) == -1) {
1323*3048Samaguire 		if (scf_error() == SCF_ERROR_NOT_FOUND)
1324*3048Samaguire 			return (0);
1325*3048Samaguire 		return (-1);
1326*3048Samaguire 	}
1327*3048Samaguire 
1328*3048Samaguire 	/*
1329*3048Samaguire 	 * Skip invalid services based on flag settings.  Flags are used when
1330*3048Samaguire 	 * we run callback functions on all instances to identify
1331*3048Samaguire 	 * the correct instances to operate on.
1332*3048Samaguire 	 */
1333*3048Samaguire 	if (raopt->opt_flags & RA_SVC_FLAG_IPV4_ROUTING) {
1334*3048Samaguire 		found_proto = B_FALSE;
1335*3048Samaguire 		if (protolist != NULL) {
1336*3048Samaguire 			/* Check if protolist contains "ipv4" */
1337*3048Samaguire 			for (i = 0; i < numvalues; i++) {
1338*3048Samaguire 				if (protolist[i] != NULL && strcmp(
1339*3048Samaguire 				    protolist[i], RA_PROPVAL_PROTO_IPV4) == 0)
1340*3048Samaguire 					found_proto = B_TRUE;
1341*3048Samaguire 			}
1342*3048Samaguire 		}
1343*3048Samaguire 		/* If not an ipv4 routing service, skip. */
1344*3048Samaguire 		if (protolist == NULL || !found_proto) {
1345*3048Samaguire 			ra_free_prop_values(numvalues, protolist);
1346*3048Samaguire 			return (0);
1347*3048Samaguire 		}
1348*3048Samaguire 	}
1349*3048Samaguire 	if (raopt->opt_flags & RA_SVC_FLAG_IPV6_ROUTING) {
1350*3048Samaguire 		found_proto = B_FALSE;
1351*3048Samaguire 		if (protolist != NULL) {
1352*3048Samaguire 			/* Check if protolist contains "ipv6" */
1353*3048Samaguire 			for (i = 0; i < numvalues; i++) {
1354*3048Samaguire 				if (protolist[i] != NULL && strcmp(
1355*3048Samaguire 				    protolist[i], RA_PROPVAL_PROTO_IPV6) == 0)
1356*3048Samaguire 					found_proto = B_TRUE;
1357*3048Samaguire 			}
1358*3048Samaguire 		}
1359*3048Samaguire 		/* If not an ipv6 routing service, skip. */
1360*3048Samaguire 		if (protolist == NULL || !found_proto) {
1361*3048Samaguire 			ra_free_prop_values(numvalues, protolist);
1362*3048Samaguire 			return (0);
1363*3048Samaguire 		}
1364*3048Samaguire 	}
1365*3048Samaguire 	ra_free_prop_values(numvalues, protolist);
1366*3048Samaguire 
1367*3048Samaguire 	/* If enabling routing services, select only current routing services */
1368*3048Samaguire 	if (raopt->opt_fmri == NULL && !get && raopt->opt_enabled) {
1369*3048Samaguire 		if (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
1370*3048Samaguire 		    RA_PROP_CURR_ROUTING_SVC, B_FALSE, B_FALSE,
1371*3048Samaguire 		    &curr_svc) == -1)
1372*3048Samaguire 			return (0);
1373*3048Samaguire 		else if (!curr_svc && persistent) {
1374*3048Samaguire 			/*
1375*3048Samaguire 			 * We apply "current" routing changes to all routing
1376*3048Samaguire 			 * daemons, whether current or not, so bail if
1377*3048Samaguire 			 * we are trying to make a persistent update to a
1378*3048Samaguire 			 * non-"routing-svc".
1379*3048Samaguire 			 */
1380*3048Samaguire 			return (0);
1381*3048Samaguire 		}
1382*3048Samaguire 	}
1383*3048Samaguire 	if (ra_get_boolean_prop(h, inst, SCF_PG_GENERAL, SCF_PROPERTY_ENABLED,
1384*3048Samaguire 	    B_FALSE, B_TRUE, &persistent_state_enabled) == -1)
1385*3048Samaguire 		return (-1);
1386*3048Samaguire 
1387*3048Samaguire 	current_state_enabled = persistent_state_enabled;
1388*3048Samaguire 
1389*3048Samaguire 	if (ra_get_boolean_prop(h, inst, SCF_PG_GENERAL_OVR,
1390*3048Samaguire 	    SCF_PROPERTY_ENABLED, B_FALSE, B_FALSE, &temporary_state_enabled)
1391*3048Samaguire 	    == 0)
1392*3048Samaguire 		current_state_enabled = temporary_state_enabled;
1393*3048Samaguire 
1394*3048Samaguire 	if (get) {
1395*3048Samaguire 		/*
1396*3048Samaguire 		 * Persistent state is enabled if any services are
1397*3048Samaguire 		 * persistently enabled, i.e. general/enabled == true).
1398*3048Samaguire 		 * current state is enabled if any services
1399*3048Samaguire 		 * services are currently enabled, i.e. if defined,
1400*3048Samaguire 		 * general_ovr/enabled == true, if not, general/enabled == true.
1401*3048Samaguire 		 */
1402*3048Samaguire 		if (persistent)
1403*3048Samaguire 			raopt->opt_enabled = raopt->opt_enabled ||
1404*3048Samaguire 			    persistent_state_enabled;
1405*3048Samaguire 		else
1406*3048Samaguire 			raopt->opt_enabled = raopt->opt_enabled ||
1407*3048Samaguire 			    current_state_enabled;
1408*3048Samaguire 	} else {
1409*3048Samaguire 		if (persistent) {
1410*3048Samaguire 			/*
1411*3048Samaguire 			 * For peristent state changes, from -e/-d,
1412*3048Samaguire 			 * we set the general_ovr/enabled value to the
1413*3048Samaguire 			 * current state (to ensure it is preserved),
1414*3048Samaguire 			 * while setting the general/enabled value to
1415*3048Samaguire 			 * the desired value.  This has the effect of
1416*3048Samaguire 			 * the desired value coming into effect on next boot.
1417*3048Samaguire 			 */
1418*3048Samaguire 			ret = current_state_enabled ?
1419*3048Samaguire 			    smf_enable_instance(inst_fmri, SMF_TEMPORARY) :
1420*3048Samaguire 			    smf_disable_instance(inst_fmri, SMF_TEMPORARY);
1421*3048Samaguire 			if (ret != 0) {
1422*3048Samaguire 				(void) fprintf(stderr, gettext(
1423*3048Samaguire 				    "%s: unexpected libscf error: %s\n"),
1424*3048Samaguire 				    myname, scf_strerror(scf_error()));
1425*3048Samaguire 				return (-1);
1426*3048Samaguire 			}
1427*3048Samaguire 			/*
1428*3048Samaguire 			 * Refresh here so general_ovr/enabled state overrides
1429*3048Samaguire 			 * general/enabled state.
1430*3048Samaguire 			 */
1431*3048Samaguire 			(void) smf_refresh_instance(inst_fmri);
1432*3048Samaguire 			/*
1433*3048Samaguire 			 * Now we can safely set the general/enabled value
1434*3048Samaguire 			 * to the value we require on next boot (or
1435*3048Samaguire 			 * "routeadm -u").
1436*3048Samaguire 			 */
1437*3048Samaguire 			ret = ra_set_boolean_prop(h, inst, SCF_PG_GENERAL,
1438*3048Samaguire 			    SCF_PROPERTY_ENABLED, B_FALSE, raopt->opt_enabled);
1439*3048Samaguire 			if (ret != 0)
1440*3048Samaguire 				return (-1);
1441*3048Samaguire 			/*
1442*3048Samaguire 			 * Refresh here so general/enabled value is set.
1443*3048Samaguire 			 */
1444*3048Samaguire 			(void) smf_refresh_instance(inst_fmri);
1445*3048Samaguire 			if (raopt->opt_fmri != NULL)
1446*3048Samaguire 				return (0);
1447*3048Samaguire 			/*
1448*3048Samaguire 			 * Notify network/routing-setup service that
1449*3048Samaguire 			 * administrator has explicitly set ipv4(6)-routing
1450*3048Samaguire 			 * value.  If no explicit setting of this value is
1451*3048Samaguire 			 * done, ipv4-routing can be enabled in the situation
1452*3048Samaguire 			 * when no default routes can be determined.
1453*3048Samaguire 			 */
1454*3048Samaguire 			if ((rinst = scf_instance_create(h)) == NULL ||
1455*3048Samaguire 			    scf_handle_decode_fmri(h, RA_INSTANCE_ROUTING_SETUP,
1456*3048Samaguire 			    NULL, NULL, rinst, NULL, NULL,
1457*3048Samaguire 			    SCF_DECODE_FMRI_EXACT) == -1) {
1458*3048Samaguire 				(void) fprintf(stderr, gettext(
1459*3048Samaguire 				    "%s: unexpected libscf error: %s\n"),
1460*3048Samaguire 				    myname, scf_strerror(scf_error()));
1461*3048Samaguire 				return (-1);
1462*3048Samaguire 			}
1463*3048Samaguire 			ret = ra_set_boolean_prop(h, rinst, RA_PG_ROUTEADM,
1464*3048Samaguire 			    raopt->opt_flags & RA_SVC_FLAG_IPV4_ROUTING ?
1465*3048Samaguire 			    RA_PROP_IPV4_ROUTING_SET :
1466*3048Samaguire 			    RA_PROP_IPV6_ROUTING_SET, B_FALSE, B_TRUE);
1467*3048Samaguire 			scf_instance_destroy(rinst);
1468*3048Samaguire 			if (ret != 0)
1469*3048Samaguire 				return (-1);
1470*3048Samaguire 			(void) smf_refresh_instance(RA_INSTANCE_ROUTING_SETUP);
1471*3048Samaguire 		} else {
1472*3048Samaguire 			/*
1473*3048Samaguire 			 * For current changes (result of -u), we
1474*3048Samaguire 			 * enable/disable depending on persistent value
1475*3048Samaguire 			 * stored in general/enabled.  Here we disable
1476*3048Samaguire 			 * old routing-svcs (identified by a current-routing-svc
1477*3048Samaguire 			 * value of false) also.
1478*3048Samaguire 			 */
1479*3048Samaguire 			ret = persistent_state_enabled && curr_svc ?
1480*3048Samaguire 			    smf_enable_instance(inst_fmri, 0) :
1481*3048Samaguire 			    smf_disable_instance(inst_fmri, 0);
1482*3048Samaguire 			if (ret != 0) {
1483*3048Samaguire 				(void) fprintf(stderr, gettext(
1484*3048Samaguire 				    "%s: unexpected libscf error: %s\n"),
1485*3048Samaguire 				    myname, scf_strerror(scf_error()));
1486*3048Samaguire 				return (-1);
1487*3048Samaguire 			}
1488*3048Samaguire 			(void) smf_refresh_instance(inst_fmri);
1489*3048Samaguire 		}
1490*3048Samaguire 	}
1491*3048Samaguire 	return (0);
1492*3048Samaguire }
1493*3048Samaguire 
1494*3048Samaguire static int
1495*3048Samaguire ra_set_default_opt_cb(void *data, scf_walkinfo_t *wip)
1496*3048Samaguire {
1497*3048Samaguire 	scf_instance_t		*inst = wip->inst;
1498*3048Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
1499*3048Samaguire 	raopt_t			*raopt = data;
1500*3048Samaguire 
1501*3048Samaguire 	return (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
1502*3048Samaguire 	    raopt->opt_default_prop, B_FALSE, raopt->opt_default_enabled));
1503*3048Samaguire }
1504*3048Samaguire 
1505*3048Samaguire static int
1506*3048Samaguire ra_get_default_opt_cb(void *data, scf_walkinfo_t *wip)
1507*3048Samaguire {
1508*3048Samaguire 	scf_instance_t		*inst = wip->inst;
1509*3048Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
1510*3048Samaguire 	raopt_t			*raopt = data;
1511*3048Samaguire 
1512*3048Samaguire 	return (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
1513*3048Samaguire 	    raopt->opt_default_prop, B_TRUE, B_TRUE,
1514*3048Samaguire 	    &(raopt->opt_default_enabled)));
1515*3048Samaguire }
1516*3048Samaguire 
1517*3048Samaguire /*
1518*3048Samaguire  * Callbacks to set/retrieve persistent/default routing variable values.
1519*3048Samaguire  * The set functions use the value stored in the var_value/var_default_value
1520*3048Samaguire  * field of the associated ra_var_t, while the retrieval functions store
1521*3048Samaguire  * the value retrieved in that field.
1522*3048Samaguire  */
1523*3048Samaguire static int
1524*3048Samaguire ra_get_persistent_var_cb(void *data, scf_walkinfo_t *wip)
1525*3048Samaguire {
1526*3048Samaguire 	scf_instance_t		*inst = wip->inst;
1527*3048Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
1528*3048Samaguire 	ravar_t			*ravar = data;
1529*3048Samaguire 
1530*3048Samaguire 	return (ra_get_single_prop_as_string(h, inst, RA_PG_ROUTEADM,
1531*3048Samaguire 	    ravar->var_prop, B_TRUE, B_TRUE, NULL, &ravar->var_value));
1532*3048Samaguire }
1533*3048Samaguire 
1534*3048Samaguire static int
1535*3048Samaguire ra_set_persistent_var_cb(void *data, scf_walkinfo_t *wip)
1536*3048Samaguire {
1537*3048Samaguire 	scf_instance_t		*inst = wip->inst;
1538*3048Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
1539*3048Samaguire 	ravar_t			*ravar = data;
1540*3048Samaguire 
1541*3048Samaguire 	return (ra_set_prop_from_string(h, inst, RA_PG_ROUTEADM,
1542*3048Samaguire 	    ravar->var_prop, SCF_TYPE_INVALID, B_FALSE, 1,
1543*3048Samaguire 	    (const char **)&ravar->var_value));
1544*3048Samaguire }
1545*3048Samaguire 
1546*3048Samaguire static int
1547*3048Samaguire ra_get_default_var_cb(void *data, scf_walkinfo_t *wip)
1548*3048Samaguire {
1549*3048Samaguire 	scf_instance_t		*inst = wip->inst;
1550*3048Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
1551*3048Samaguire 	ravar_t			*ravar = data;
1552*3048Samaguire 
1553*3048Samaguire 	return (ra_get_single_prop_as_string(h, inst, RA_PG_ROUTEADM,
1554*3048Samaguire 	    ravar->var_default_prop, B_TRUE, B_TRUE, NULL,
1555*3048Samaguire 	    &ravar->var_default_value));
1556*3048Samaguire }
1557*3048Samaguire 
1558*3048Samaguire /*
1559*3048Samaguire  * Depending on the value of the boolean_t * passed in,  this callback
1560*3048Samaguire  * either marks the relevant service(s) as current-routing-svcs (or unmarking)
1561*3048Samaguire  * by setting that property to true or false.  When routing services
1562*3048Samaguire  * are to be enabled,  the a current-routing-svc value of true flags the
1563*3048Samaguire  * service as one to be enabled.
1564*3048Samaguire  */
1565*3048Samaguire static int
1566*3048Samaguire ra_mark_routing_svcs_cb(void *data, scf_walkinfo_t *wip)
1567*3048Samaguire {
1568*3048Samaguire 	scf_instance_t		*inst = wip->inst;
1569*3048Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
1570*3048Samaguire 	boolean_t		*mark = data;
1571*3048Samaguire 	boolean_t		marked;
1572*3048Samaguire 	int			numvalues = 0;
1573*3048Samaguire 	char			**protolist = NULL;
1574*3048Samaguire 
1575*3048Samaguire 	/* Check we are dealing with a routing daemon service */
1576*3048Samaguire 	if (ra_get_prop_as_string(h, inst, RA_PG_ROUTEADM, RA_PROP_PROTO,
1577*3048Samaguire 	    B_TRUE, B_FALSE, NULL, &numvalues, &protolist) == -1)
1578*3048Samaguire 		return (0);
1579*3048Samaguire 	ra_free_prop_values(numvalues, protolist);
1580*3048Samaguire 	if (*mark)
1581*3048Samaguire 		return (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
1582*3048Samaguire 		    RA_PROP_CURR_ROUTING_SVC, B_TRUE, B_TRUE));
1583*3048Samaguire 	/* Unmark service. */
1584*3048Samaguire 	if (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
1585*3048Samaguire 	    RA_PROP_CURR_ROUTING_SVC, B_TRUE, B_FALSE, &marked) == 0 && marked)
1586*3048Samaguire 		return (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
1587*3048Samaguire 		    RA_PROP_CURR_ROUTING_SVC, B_TRUE, B_FALSE));
1588*3048Samaguire 	return (0);
1589*3048Samaguire }
1590*3048Samaguire 
1591*3048Samaguire /*
1592*3048Samaguire  * List property values for all properties in the "routing" property
1593*3048Samaguire  * group of the routing service instance.
1594*3048Samaguire  */
1595*3048Samaguire 
1596*3048Samaguire /* ARGSUSED0 */
1597*3048Samaguire static int
1598*3048Samaguire ra_list_props_cb(void *data, scf_walkinfo_t *wip)
1599*3048Samaguire {
1600*3048Samaguire 	const char		*inst_fmri = wip->fmri;
1601*3048Samaguire 	scf_instance_t		*inst = wip->inst;
1602*3048Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
1603*3048Samaguire 	scf_iter_t		*propiter, *valiter;
1604*3048Samaguire 	scf_propertygroup_t	*pg;
1605*3048Samaguire 	scf_property_t		*prop;
1606*3048Samaguire 	scf_value_t		*val;
1607*3048Samaguire 	char			**protolist = NULL, *pnamebuf, *valbuf;
1608*3048Samaguire 	ssize_t			pnamelen, vallen;
1609*3048Samaguire 	int			numvalues = 0;
1610*3048Samaguire 	int			propiterret, valiterret, retval = 0;
1611*3048Samaguire 
1612*3048Samaguire 	/* Services with no "protocol" property are not routing daemons */
1613*3048Samaguire 	if (ra_get_prop_as_string(h, inst, RA_PG_ROUTEADM, RA_PROP_PROTO,
1614*3048Samaguire 	    B_TRUE, B_FALSE, NULL, &numvalues, &protolist) == -1) {
1615*3048Samaguire 		if (scf_error() == SCF_ERROR_NOT_FOUND)
1616*3048Samaguire 			(void) fprintf(stderr,
1617*3048Samaguire 			    gettext("%s: %s is not a routing daemon service\n"),
1618*3048Samaguire 			    myname, inst_fmri);
1619*3048Samaguire 		else
1620*3048Samaguire 			(void) fprintf(stderr,
1621*3048Samaguire 			    gettext("%s: unexpected libscf error: %s\n"),
1622*3048Samaguire 			    myname, scf_strerror(scf_error()));
1623*3048Samaguire 		ra_free_prop_values(numvalues, protolist);
1624*3048Samaguire 		return (-1);
1625*3048Samaguire 	}
1626*3048Samaguire 	ra_free_prop_values(numvalues, protolist);
1627*3048Samaguire 
1628*3048Samaguire 	if (ra_get_pg(h, inst, RA_PG_ROUTING, B_TRUE, B_FALSE, &pg) == -1) {
1629*3048Samaguire 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
1630*3048Samaguire 			(void) printf("%s: no %s property group for %s\n",
1631*3048Samaguire 			    myname, RA_PG_ROUTING, inst_fmri);
1632*3048Samaguire 			return (0);
1633*3048Samaguire 		}
1634*3048Samaguire 		(void) fprintf(stderr,
1635*3048Samaguire 		    gettext("%s: unexpected libscf error: %s\n"),
1636*3048Samaguire 		    myname, scf_strerror(scf_error()));
1637*3048Samaguire 		return (-1);
1638*3048Samaguire 	}
1639*3048Samaguire 
1640*3048Samaguire 	(void) printf("%s:\n", inst_fmri);
1641*3048Samaguire 
1642*3048Samaguire 	/* Create an iterator to walk through all properties */
1643*3048Samaguire 	if ((propiter = scf_iter_create(h)) == NULL ||
1644*3048Samaguire 	    (prop = scf_property_create(h)) == NULL ||
1645*3048Samaguire 	    scf_iter_pg_properties(propiter, pg) != 0) {
1646*3048Samaguire 		(void) fprintf(stderr, gettext
1647*3048Samaguire 		    ("%s: could not iterate through properties for %s: %s\n"),
1648*3048Samaguire 		    myname, inst_fmri, scf_strerror(scf_error()));
1649*3048Samaguire 	}
1650*3048Samaguire 	while ((propiterret = scf_iter_next_property(propiter, prop)) == 1) {
1651*3048Samaguire 		if ((pnamelen = scf_property_get_name(prop, NULL, 0) + 1)
1652*3048Samaguire 		    == 0) {
1653*3048Samaguire 			(void) fprintf(stderr, gettext("%s: could not retrieve "
1654*3048Samaguire 			    "property name for instance %s: %s\n"), myname,
1655*3048Samaguire 			    inst_fmri, scf_strerror(scf_error()));
1656*3048Samaguire 			retval = -1;
1657*3048Samaguire 			break;
1658*3048Samaguire 		}
1659*3048Samaguire 		if ((pnamebuf = malloc(pnamelen)) == NULL) {
1660*3048Samaguire 			(void) fprintf(stderr,
1661*3048Samaguire 			    gettext("%s: out of memory\n"), myname);
1662*3048Samaguire 			retval = -1;
1663*3048Samaguire 			break;
1664*3048Samaguire 		}
1665*3048Samaguire 		(void) scf_property_get_name(prop, pnamebuf,
1666*3048Samaguire 		    pnamelen);
1667*3048Samaguire 		(void) printf("\t%s = ", pnamebuf);
1668*3048Samaguire 		if ((valiter = scf_iter_create(h)) == NULL ||
1669*3048Samaguire 		    (val = scf_value_create(h)) == NULL ||
1670*3048Samaguire 		    scf_iter_property_values(valiter, prop)
1671*3048Samaguire 		    != 0) {
1672*3048Samaguire 			(void) fprintf(stderr, gettext
1673*3048Samaguire 			    ("%s: could not iterate through "
1674*3048Samaguire 			    "properties for %s: %s\n"), myname, inst_fmri,
1675*3048Samaguire 			    scf_strerror(scf_error()));
1676*3048Samaguire 			scf_value_destroy(val);
1677*3048Samaguire 			scf_iter_destroy(valiter);
1678*3048Samaguire 			free(pnamebuf);
1679*3048Samaguire 			retval = -1;
1680*3048Samaguire 			break;
1681*3048Samaguire 		}
1682*3048Samaguire 		while ((valiterret = scf_iter_next_value(valiter, val)) == 1) {
1683*3048Samaguire 			if ((vallen = scf_value_get_as_string
1684*3048Samaguire 			    (val, NULL, 0) + 1) == 0) {
1685*3048Samaguire 				(void) fprintf(stderr, gettext
1686*3048Samaguire 				    ("%s: could not retrieve "
1687*3048Samaguire 				    "property value for instance %s, "
1688*3048Samaguire 				    "property %s: %s\n"), myname, inst_fmri,
1689*3048Samaguire 				    pnamebuf, scf_strerror(scf_error()));
1690*3048Samaguire 				retval = -1;
1691*3048Samaguire 			} else if ((valbuf = malloc(vallen)) == NULL) {
1692*3048Samaguire 				(void) fprintf(stderr,
1693*3048Samaguire 				    gettext("%s: out of memory\n"), myname);
1694*3048Samaguire 				retval = -1;
1695*3048Samaguire 			}
1696*3048Samaguire 			if (retval == -1) {
1697*3048Samaguire 				scf_iter_destroy(valiter);
1698*3048Samaguire 				scf_value_destroy(val);
1699*3048Samaguire 				free(pnamebuf);
1700*3048Samaguire 				goto out;
1701*3048Samaguire 			}
1702*3048Samaguire 			(void) scf_value_get_as_string(val, valbuf, vallen);
1703*3048Samaguire 			(void) printf("%s ", valbuf);
1704*3048Samaguire 			free(valbuf);
1705*3048Samaguire 		}
1706*3048Samaguire 		(void) printf("\n");
1707*3048Samaguire 		scf_iter_destroy(valiter);
1708*3048Samaguire 		scf_value_destroy(val);
1709*3048Samaguire 		free(pnamebuf);
1710*3048Samaguire 		if (valiterret == -1) {
1711*3048Samaguire 			(void) fprintf(stderr,
1712*3048Samaguire 			    gettext("%s: could not iterate through"
1713*3048Samaguire 			    "properties for %s: %s\n"), myname, inst_fmri,
1714*3048Samaguire 			    scf_strerror(scf_error()));
1715*3048Samaguire 			retval = -1;
1716*3048Samaguire 			break;
1717*3048Samaguire 		}
1718*3048Samaguire 	}
1719*3048Samaguire out:
1720*3048Samaguire 	scf_iter_destroy(propiter);
1721*3048Samaguire 	scf_property_destroy(prop);
1722*3048Samaguire 	scf_pg_destroy(pg);
1723*3048Samaguire 	if (propiterret == -1)
1724*3048Samaguire 		(void) fprintf(stderr, gettext
1725*3048Samaguire 		    ("%s: could not iterate through properties for %s: %s\n"),
1726*3048Samaguire 		    myname, inst_fmri, scf_strerror(scf_error()));
1727*3048Samaguire 	return (retval);
1728*3048Samaguire }
1729*3048Samaguire 
1730*3048Samaguire /*
1731*3048Samaguire  * Modify property with name stored in passed-in ra_prop_t to have
1732*3048Samaguire  * the assocatied values.  Only works for existing properties in
1733*3048Samaguire  * the "routing" property group for routing daemon services,  so all
1734*3048Samaguire  * routing daemons should place configurable options in that group.
1735*3048Samaguire  */
1736*3048Samaguire static int
1737*3048Samaguire ra_modify_props_cb(void *data, scf_walkinfo_t *wip)
1738*3048Samaguire {
1739*3048Samaguire 	const char		*inst_fmri = wip->fmri;
1740*3048Samaguire 	scf_instance_t		*inst = wip->inst;
1741*3048Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
1742*3048Samaguire 	ra_prop_t		*raprop = data;
1743*3048Samaguire 	int			numvalues = 0;
1744*3048Samaguire 	char			**protolist = NULL;
1745*3048Samaguire 
1746*3048Samaguire 	/* Services with no "protocol" property are not routing daemons */
1747*3048Samaguire 	if (ra_get_prop_as_string(h, inst, RA_PG_ROUTEADM, RA_PROP_PROTO,
1748*3048Samaguire 	    B_TRUE, B_FALSE, NULL, &numvalues, &protolist) == -1) {
1749*3048Samaguire 		if (scf_error() == SCF_ERROR_NOT_FOUND)
1750*3048Samaguire 			(void) fprintf(stderr,
1751*3048Samaguire 			    gettext("%s: %s is not a routing daemon service\n"),
1752*3048Samaguire 			    myname, inst_fmri);
1753*3048Samaguire 		else
1754*3048Samaguire 			(void) fprintf(stderr,
1755*3048Samaguire 			    gettext("%s: unexpected libscf error: %s\n"),
1756*3048Samaguire 			    myname, scf_strerror(scf_error()));
1757*3048Samaguire 		ra_free_prop_values(numvalues, protolist);
1758*3048Samaguire 		return (-1);
1759*3048Samaguire 	}
1760*3048Samaguire 	ra_free_prop_values(numvalues, protolist);
1761*3048Samaguire 
1762*3048Samaguire 	if (ra_set_prop_from_string(h, inst, RA_PG_ROUTING, raprop->prop_name,
1763*3048Samaguire 	    SCF_TYPE_INVALID, B_FALSE, raprop->prop_numvalues,
1764*3048Samaguire 	    (const char **)raprop->prop_values) == -1)
1765*3048Samaguire 		return (-1);
1766*3048Samaguire 
1767*3048Samaguire 	(void) smf_refresh_instance(inst_fmri);
1768*3048Samaguire 	return (0);
1769*3048Samaguire }
1770*3048Samaguire 
1771*3048Samaguire /*
1772*3048Samaguire  * Display FMRI, state for each routing daemon service.
1773*3048Samaguire  */
1774*3048Samaguire 
1775*3048Samaguire /* ARGSUSED0 */
1776*3048Samaguire static int
1777*3048Samaguire ra_print_state_cb(void *data, scf_walkinfo_t *wip)
1778*3048Samaguire {
1779*3048Samaguire 	const char		*inst_fmri = wip->fmri;
1780*3048Samaguire 	scf_instance_t		*inst = wip->inst;
1781*3048Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
1782*3048Samaguire 	char			*inst_state, **protolist = NULL;
1783*3048Samaguire 	int			numvalues = 0;
1784*3048Samaguire 
1785*3048Samaguire 	/* Ensure service is a routing daemon */
1786*3048Samaguire 	if (ra_get_prop_as_string(h, inst, RA_PG_ROUTEADM, RA_PROP_PROTO,
1787*3048Samaguire 	    B_TRUE, B_FALSE, NULL, &numvalues, &protolist) == -1)
1788*3048Samaguire 		return (0);
1789*3048Samaguire 	ra_free_prop_values(numvalues, protolist);
1790*3048Samaguire 
1791*3048Samaguire 	if ((inst_state = smf_get_state(inst_fmri)) == NULL) {
1792*3048Samaguire 		(void) fprintf(stderr,
1793*3048Samaguire 		    gettext("%s: could not retrieve state for %s: %s\n"),
1794*3048Samaguire 		    myname, inst_fmri, scf_strerror(scf_error()));
1795*3048Samaguire 		return (-1);
1796*3048Samaguire 	}
1797*3048Samaguire 	(void) printf("%27s   %2s\n", inst_state, inst_fmri);
1798*3048Samaguire 	free(inst_state);
1799*3048Samaguire 
1800*3048Samaguire 	return (0);
1801*3048Samaguire }
1802*3048Samaguire 
1803*3048Samaguire static int
1804*3048Samaguire ra_get_pg(scf_handle_t *h, scf_instance_t *inst, const char *pgname,
1805*3048Samaguire     boolean_t composed, boolean_t required, scf_propertygroup_t **pg)
1806*3048Samaguire {
1807*3048Samaguire 	/* Retrieve (possibly composed) property group for instance */
1808*3048Samaguire 	if ((*pg = scf_pg_create(h)) == NULL || (composed &&
1809*3048Samaguire 	    scf_instance_get_pg_composed(inst, NULL, pgname, *pg) != 0) ||
1810*3048Samaguire 	    (!composed && scf_instance_get_pg(inst, pgname, *pg) != 0)) {
1811*3048Samaguire 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
1812*3048Samaguire 			if (required)
1813*3048Samaguire 				(void) fprintf(stderr, gettext(
1814*3048Samaguire 				    "%s: no such property group %s\n"),
1815*3048Samaguire 				    myname, pgname);
1816*3048Samaguire 			return (-1);
1817*3048Samaguire 		}
1818*3048Samaguire 		if (required)
1819*3048Samaguire 			(void) fprintf(stderr, gettext(
1820*3048Samaguire 			    "%s: unexpected libscf error: %s\n"), myname,
1821*3048Samaguire 			    scf_strerror(scf_error()));
1822*3048Samaguire 		return (-1);
1823*3048Samaguire 	}
1824*3048Samaguire 	return (0);
1825*3048Samaguire }
1826*3048Samaguire 
1827*3048Samaguire static int
1828*3048Samaguire ra_get_boolean_prop(scf_handle_t *h, scf_instance_t *inst,
1829*3048Samaguire     const char *pgname, const char *propname, boolean_t composed,
1830*3048Samaguire     boolean_t required, boolean_t *val)
1831*3048Samaguire {
1832*3048Samaguire 	char	*valstr;
1833*3048Samaguire 
1834*3048Samaguire 	if (ra_get_single_prop_as_string(h, inst, pgname, propname,
1835*3048Samaguire 	    composed, required, NULL, &valstr) != 0)
1836*3048Samaguire 		return (-1);
1837*3048Samaguire 	*val = strcmp(valstr, RA_PROPVAL_BOOLEAN_TRUE) == 0;
1838*3048Samaguire 	free(valstr);
1839*3048Samaguire 	return (0);
1840*3048Samaguire }
1841*3048Samaguire 
1842*3048Samaguire static int
1843*3048Samaguire ra_get_single_prop_as_string(scf_handle_t *h, scf_instance_t *inst,
1844*3048Samaguire     const char *pgname, const char *propname, boolean_t composed,
1845*3048Samaguire     boolean_t required, scf_type_t *type, char **value)
1846*3048Samaguire {
1847*3048Samaguire 	char	**values;
1848*3048Samaguire 	int	numvalues = 1;
1849*3048Samaguire 
1850*3048Samaguire 	if (ra_get_prop_as_string(h, inst, pgname, propname, composed, required,
1851*3048Samaguire 	    type, &numvalues, &values) == -1)
1852*3048Samaguire 		return (-1);
1853*3048Samaguire 	*value = values[0];
1854*3048Samaguire 	free(values);
1855*3048Samaguire 	return (0);
1856*3048Samaguire }
1857*3048Samaguire 
1858*3048Samaguire /*
1859*3048Samaguire  * Retrieve property named in propname,  possibly using the composed
1860*3048Samaguire  * property group view (union of instance and service-level properties,
1861*3048Samaguire  * where instance-level properties override service-level values).
1862*3048Samaguire  */
1863*3048Samaguire static int
1864*3048Samaguire ra_get_prop_as_string(scf_handle_t *h, scf_instance_t *inst,
1865*3048Samaguire     const char *pgname, const char *propname, boolean_t composed,
1866*3048Samaguire     boolean_t required, scf_type_t *type, int *numvalues, char ***values)
1867*3048Samaguire {
1868*3048Samaguire 	scf_propertygroup_t	*pg = NULL;
1869*3048Samaguire 	scf_property_t		*prop = NULL;
1870*3048Samaguire 	scf_iter_t		*valiter = NULL;
1871*3048Samaguire 	scf_value_t		*val = NULL;
1872*3048Samaguire 	ssize_t			vallen = 0;
1873*3048Samaguire 	int			valiterret, i, numvalues_retrieved, ret = 0;
1874*3048Samaguire 
1875*3048Samaguire 	if (ra_get_pg(h, inst, pgname, composed, required, &pg) == -1)
1876*3048Samaguire 		return (-1);
1877*3048Samaguire 
1878*3048Samaguire 	*values = NULL;
1879*3048Samaguire 	/*
1880*3048Samaguire 	 * Retrieve values. All values routeadm needs to retrieve
1881*3048Samaguire 	 * (bar those gathered by routeadm -l), are known to be single-valued.
1882*3048Samaguire 	 */
1883*3048Samaguire 	if ((prop = scf_property_create(h)) == NULL)
1884*3048Samaguire 		goto error;
1885*3048Samaguire 	if (scf_pg_get_property(pg, propname, prop) != 0) {
1886*3048Samaguire 		*numvalues = 0;
1887*3048Samaguire 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
1888*3048Samaguire 			if (required)
1889*3048Samaguire 				(void) fprintf(stderr, gettext(
1890*3048Samaguire 				    "%s: property %s/%s not found\n"),
1891*3048Samaguire 				    myname, pgname, propname);
1892*3048Samaguire 			ret = -1;
1893*3048Samaguire 			goto out;
1894*3048Samaguire 		}
1895*3048Samaguire 		goto error;
1896*3048Samaguire 	}
1897*3048Samaguire 	if ((val = scf_value_create(h)) == NULL &&
1898*3048Samaguire 	    scf_property_get_value(prop, val) != 0 ||
1899*3048Samaguire 	    (valiter = scf_iter_create(h)) == NULL ||
1900*3048Samaguire 	    scf_iter_property_values(valiter, prop) != 0)
1901*3048Samaguire 		goto error;
1902*3048Samaguire 	/* retrieve each value */
1903*3048Samaguire 	for (numvalues_retrieved = 0;
1904*3048Samaguire 	    (valiterret = scf_iter_next_value(valiter, val)) == 1;
1905*3048Samaguire 	    numvalues_retrieved++) {
1906*3048Samaguire 		if ((vallen = scf_value_get_as_string
1907*3048Samaguire 		    (val, NULL, 0) + 1) == 0)
1908*3048Samaguire 			goto error;
1909*3048Samaguire 		if ((*values = realloc(*values,
1910*3048Samaguire 		    sizeof (*values) + sizeof (char *))) == NULL ||
1911*3048Samaguire 		    ((*values)[numvalues_retrieved] = malloc(vallen)) == NULL) {
1912*3048Samaguire 			(void) fprintf(stderr, gettext(
1913*3048Samaguire 			    "%s: out of memory\n"), myname);
1914*3048Samaguire 			ret = -1;
1915*3048Samaguire 			goto out;
1916*3048Samaguire 		}
1917*3048Samaguire 		(void) scf_value_get_as_string(val,
1918*3048Samaguire 		    (*values)[numvalues_retrieved], vallen);
1919*3048Samaguire 	}
1920*3048Samaguire 	if (valiterret == -1)
1921*3048Samaguire 		goto error;
1922*3048Samaguire 	/*
1923*3048Samaguire 	 * if *numvalues != 0, it holds expected number of values.  If a
1924*3048Samaguire 	 * different number are found, it is an error.
1925*3048Samaguire 	 */
1926*3048Samaguire 	if (*numvalues != 0 && *numvalues != numvalues_retrieved) {
1927*3048Samaguire 		(void) fprintf(stderr, gettext(
1928*3048Samaguire 		    "%s: got %d values for property %s/%s, expected %d\n"),
1929*3048Samaguire 		    myname, numvalues_retrieved, pgname, propname, *numvalues);
1930*3048Samaguire 		ret = -1;
1931*3048Samaguire 		goto out;
1932*3048Samaguire 	}
1933*3048Samaguire 	*numvalues = numvalues_retrieved;
1934*3048Samaguire 
1935*3048Samaguire 	/* Retrieve property type if required. */
1936*3048Samaguire 	if (type != NULL)
1937*3048Samaguire 		(void) scf_property_type(prop, type);
1938*3048Samaguire 
1939*3048Samaguire 	goto out;
1940*3048Samaguire error:
1941*3048Samaguire 	if (scf_error() == SCF_ERROR_NOT_FOUND) {
1942*3048Samaguire 		(void) fprintf(stderr, gettext(
1943*3048Samaguire 		    "%s: property %s not found"), myname, propname);
1944*3048Samaguire 	} else {
1945*3048Samaguire 		(void) fprintf(stderr, gettext(
1946*3048Samaguire 		    "%s: unexpected libscf error: %s, "), myname);
1947*3048Samaguire 	}
1948*3048Samaguire 	for (i = 0; i < numvalues_retrieved; i++)
1949*3048Samaguire 		free((*values)[i]);
1950*3048Samaguire 	if (*values != NULL)
1951*3048Samaguire 		free(*values);
1952*3048Samaguire 
1953*3048Samaguire 	ret = -1;
1954*3048Samaguire out:
1955*3048Samaguire 	if (val != NULL)
1956*3048Samaguire 		scf_value_destroy(val);
1957*3048Samaguire 	if (valiter != NULL)
1958*3048Samaguire 		scf_iter_destroy(valiter);
1959*3048Samaguire 	if (prop != NULL)
1960*3048Samaguire 		scf_property_destroy(prop);
1961*3048Samaguire 	if (pg != NULL)
1962*3048Samaguire 		scf_pg_destroy(pg);
1963*3048Samaguire 	return (ret);
1964*3048Samaguire }
1965*3048Samaguire 
1966*3048Samaguire static void
1967*3048Samaguire ra_free_prop_values(int numvalues, char **values)
1968*3048Samaguire {
1969*3048Samaguire 	int	i;
1970*3048Samaguire 	if (values != NULL) {
1971*3048Samaguire 		for (i = 0; i < numvalues; i++)
1972*3048Samaguire 			free(values[i]);
1973*3048Samaguire 		free(values);
1974*3048Samaguire 	}
1975*3048Samaguire }
1976*3048Samaguire 
1977*3048Samaguire static int
1978*3048Samaguire ra_set_boolean_prop(scf_handle_t *h, scf_instance_t *inst, const char *pgname,
1979*3048Samaguire     const char *prop, boolean_t create, boolean_t propval)
1980*3048Samaguire {
1981*3048Samaguire 	const char	*val = propval ? RA_PROPVAL_BOOLEAN_TRUE :
1982*3048Samaguire 	    RA_PROPVAL_BOOLEAN_FALSE;
1983*3048Samaguire 
1984*3048Samaguire 	return (ra_set_prop_from_string(h, inst, pgname, prop, SCF_TYPE_BOOLEAN,
1985*3048Samaguire 	    create, 1, &val));
1986*3048Samaguire }
1987*3048Samaguire 
1988*3048Samaguire /*
1989*3048Samaguire  * Set the property named in propname to the values passed in in the propvals
1990*3048Samaguire  * array.  Only create a new property if "create" is true.
1991*3048Samaguire  */
1992*3048Samaguire static int
1993*3048Samaguire ra_set_prop_from_string(scf_handle_t *h, scf_instance_t *inst,
1994*3048Samaguire     const char *pgname, const char *propname, scf_type_t proptype,
1995*3048Samaguire     boolean_t create, int numpropvals, const char **propvals)
1996*3048Samaguire {
1997*3048Samaguire 	scf_propertygroup_t	*instpg = NULL, *cpg = NULL;
1998*3048Samaguire 	scf_type_t		oldproptype, newproptype = proptype;
1999*3048Samaguire 	scf_property_t		*prop = NULL;
2000*3048Samaguire 	scf_value_t		**values = NULL;
2001*3048Samaguire 	scf_transaction_t	*tx = NULL;
2002*3048Samaguire 	scf_transaction_entry_t	*ent = NULL;
2003*3048Samaguire 	boolean_t		new = B_FALSE;
2004*3048Samaguire 	int			i, retval, numvalues = 0, ret = 0;
2005*3048Samaguire 	char			*pgtype = NULL, **ovalues;
2006*3048Samaguire 	ssize_t			typelen;
2007*3048Samaguire 
2008*3048Samaguire 	/* Firstly, does property exist? If not, and create is false, bail */
2009*3048Samaguire 	if (ra_get_prop_as_string(h, inst, pgname, propname, B_TRUE,
2010*3048Samaguire 	    B_FALSE, &oldproptype, &numvalues, &ovalues) == -1) {
2011*3048Samaguire 		if (scf_error() != SCF_ERROR_NOT_FOUND)
2012*3048Samaguire 			goto error;
2013*3048Samaguire 		if (!create) {
2014*3048Samaguire 			(void) fprintf(stderr, gettext(
2015*3048Samaguire 			    "%s: no such property %s/%s\n"), myname, pgname,
2016*3048Samaguire 			    propname);
2017*3048Samaguire 			return (-1);
2018*3048Samaguire 		}
2019*3048Samaguire 	} else
2020*3048Samaguire 		ra_free_prop_values(numvalues, ovalues);
2021*3048Samaguire 
2022*3048Samaguire 	/* Use old property type */
2023*3048Samaguire 	if (proptype == SCF_TYPE_INVALID)
2024*3048Samaguire 		newproptype = oldproptype;
2025*3048Samaguire 
2026*3048Samaguire 	/*
2027*3048Samaguire 	 * Does property group exist at instance level?  If not, we need to
2028*3048Samaguire 	 * create it,  since the composed view of the property group did
2029*3048Samaguire 	 * contain the property.  We never modify properties at the service
2030*3048Samaguire 	 * level,  as it`s possible that multiple instances will inherit those
2031*3048Samaguire 	 * settings.
2032*3048Samaguire 	 */
2033*3048Samaguire 	if (ra_get_pg(h, inst, pgname, B_FALSE, B_FALSE, &instpg) == -1) {
2034*3048Samaguire 		if (scf_error() != SCF_ERROR_NOT_FOUND)
2035*3048Samaguire 			goto error;
2036*3048Samaguire 		/* Ensure pg exists at service level, get composed pg */
2037*3048Samaguire 		if (ra_get_pg(h, inst, pgname, B_TRUE, B_FALSE, &cpg) == -1)
2038*3048Samaguire 			goto error;
2039*3048Samaguire 
2040*3048Samaguire 		/* Create instance-level property group */
2041*3048Samaguire 		if ((typelen = scf_pg_get_type(cpg, NULL, 0) + 1) == 0)
2042*3048Samaguire 			goto error;
2043*3048Samaguire 		if ((pgtype = malloc(typelen)) == NULL) {
2044*3048Samaguire 			(void) fprintf(stderr, gettext(
2045*3048Samaguire 			    "%s: out of memory\n"), myname);
2046*3048Samaguire 			goto error;
2047*3048Samaguire 		}
2048*3048Samaguire 		(void) scf_pg_get_type(cpg, pgtype, typelen);
2049*3048Samaguire 		if ((instpg = scf_pg_create(h)) == NULL ||
2050*3048Samaguire 		    scf_instance_add_pg(inst, pgname, pgtype, 0, instpg)
2051*3048Samaguire 		    == -1) {
2052*3048Samaguire 			(void) fprintf(stderr, gettext(
2053*3048Samaguire 			    "%s: could not create property group %s\n"),
2054*3048Samaguire 			    myname, pgname);
2055*3048Samaguire 			goto error;
2056*3048Samaguire 		}
2057*3048Samaguire 	}
2058*3048Samaguire 	if ((prop = scf_property_create(h)) == NULL)
2059*3048Samaguire 		goto error;
2060*3048Samaguire 	if ((values = calloc(numpropvals, sizeof (scf_value_t *))) == NULL) {
2061*3048Samaguire 		(void) fprintf(stderr, gettext("%s: out of memory"), myname);
2062*3048Samaguire 		goto error;
2063*3048Samaguire 	}
2064*3048Samaguire 	if (scf_pg_get_property(instpg, propname, prop) != 0) {
2065*3048Samaguire 		/* New property? */
2066*3048Samaguire 		if (scf_error() == SCF_ERROR_NOT_FOUND)
2067*3048Samaguire 			new = B_TRUE;
2068*3048Samaguire 		else
2069*3048Samaguire 			goto error;
2070*3048Samaguire 	}
2071*3048Samaguire 	if ((tx = scf_transaction_create(h)) == NULL ||
2072*3048Samaguire 	    (ent = scf_entry_create(h)) == NULL)
2073*3048Samaguire 		goto error;
2074*3048Samaguire retry:
2075*3048Samaguire 	if (scf_transaction_start(tx, instpg) == -1)
2076*3048Samaguire 		goto error;
2077*3048Samaguire 	if (new) {
2078*3048Samaguire 		if (scf_transaction_property_new(tx, ent, propname,
2079*3048Samaguire 		    newproptype) == -1)
2080*3048Samaguire 			goto error;
2081*3048Samaguire 	} else if (scf_transaction_property_change(tx, ent, propname,
2082*3048Samaguire 	    newproptype) == -1)
2083*3048Samaguire 		goto error;
2084*3048Samaguire 	for (i = 0; i < numpropvals; i++) {
2085*3048Samaguire 		if ((values[i] = scf_value_create(h)) == NULL ||
2086*3048Samaguire 		    scf_value_set_from_string(values[i], newproptype,
2087*3048Samaguire 		    propvals[i] == NULL ? "": propvals[i]) == -1 ||
2088*3048Samaguire 		    scf_entry_add_value(ent, values[i]) != 0)
2089*3048Samaguire 			goto error;
2090*3048Samaguire 	}
2091*3048Samaguire 	retval = scf_transaction_commit(tx);
2092*3048Samaguire 	if (retval == 0) {
2093*3048Samaguire 		scf_transaction_reset(tx);
2094*3048Samaguire 		if (scf_pg_update(instpg) == -1)
2095*3048Samaguire 			goto error;
2096*3048Samaguire 		goto retry;
2097*3048Samaguire 	}
2098*3048Samaguire 	if (retval == -1)
2099*3048Samaguire 		goto error;
2100*3048Samaguire 	goto out;
2101*3048Samaguire error:
2102*3048Samaguire 	switch (scf_error()) {
2103*3048Samaguire 	case SCF_ERROR_INVALID_ARGUMENT:
2104*3048Samaguire 		(void) fprintf(stderr, gettext(
2105*3048Samaguire 		    "%s: invalid value for property %s/%s\n"), myname,
2106*3048Samaguire 		    pgname, propname);
2107*3048Samaguire 		break;
2108*3048Samaguire 	case SCF_ERROR_NOT_FOUND:
2109*3048Samaguire 		(void) fprintf(stderr, gettext(
2110*3048Samaguire 		    "%s: no such property %s/%s\n"), myname,
2111*3048Samaguire 		    pgname, propname);
2112*3048Samaguire 		break;
2113*3048Samaguire 	default:
2114*3048Samaguire 		(void) fprintf(stderr, gettext(
2115*3048Samaguire 		    "%s: unexpected libscf error: %s\n"), myname,
2116*3048Samaguire 		    scf_strerror(scf_error()));
2117*3048Samaguire 		break;
2118*3048Samaguire 	}
2119*3048Samaguire 	ret = -1;
2120*3048Samaguire out:
2121*3048Samaguire 	if (tx != NULL)
2122*3048Samaguire 		scf_transaction_destroy(tx);
2123*3048Samaguire 	if (ent != NULL)
2124*3048Samaguire 		scf_entry_destroy(ent);
2125*3048Samaguire 	if (values != NULL) {
2126*3048Samaguire 		for (i = 0; i < numpropvals; i++) {
2127*3048Samaguire 			if (values[i] != NULL)
2128*3048Samaguire 				scf_value_destroy(values[i]);
2129*3048Samaguire 		}
2130*3048Samaguire 		free(values);
2131*3048Samaguire 	}
2132*3048Samaguire 	if (prop != NULL)
2133*3048Samaguire 		scf_property_destroy(prop);
2134*3048Samaguire 	if (cpg != NULL)
2135*3048Samaguire 		scf_pg_destroy(cpg);
2136*3048Samaguire 	if (instpg != NULL)
2137*3048Samaguire 		scf_pg_destroy(instpg);
2138*3048Samaguire 	if (pgtype != NULL)
2139*3048Samaguire 		free(pgtype);
2140*3048Samaguire 	return (ret);
2141*3048Samaguire }
2142*3048Samaguire 
2143*3048Samaguire /*
2144*3048Samaguire  * This function gathers configuration from the legacy /etc/inet/routing.conf,
2145*3048Samaguire  * if any, and sets the appropriate variable values accordingly.  Once
2146*3048Samaguire  * these are set,  the legacy daemons are checked to see if they have
2147*3048Samaguire  * SMF counterparts (ra_check_legacy_daemons()).  If they do, the
2148*3048Samaguire  * configuration is upgraded.  Finally,  the legacy option settings are
2149*3048Samaguire  * applied,  enabling/disabling the routing/forwarding services as
2150*3048Samaguire  * appropriate.
2151*3048Samaguire  */
2152*3048Samaguire static int
2153*3048Samaguire ra_upgrade_from_legacy_conf(void)
2154*3048Samaguire {
2155*3048Samaguire 	scf_handle_t	*h = NULL;
2156*3048Samaguire 	scf_instance_t	*inst = NULL;
2157*3048Samaguire 	int		ret = 0, i, r;
2158*3048Samaguire 	boolean_t	old_conf_read;
2159*3048Samaguire 	ravar_t		*routing_svcs = ra_str2var(RA_VAR_ROUTING_SVCS);
2160*3048Samaguire 
2161*3048Samaguire 	/*
2162*3048Samaguire 	 * First, determine if we have already upgraded - if "routing-conf-read"
2163*3048Samaguire 	 * is true, we bail.  The use of a boolean property indicating if
2164*3048Samaguire 	 * routing.conf has been read and applied might seem a lot more
2165*3048Samaguire 	 * work than simply copying routing.conf aside,  but leaving the
2166*3048Samaguire 	 * file in place allows users to downgrade and have their old
2167*3048Samaguire 	 * routing configuration still in place.
2168*3048Samaguire 	 */
2169*3048Samaguire 	if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
2170*3048Samaguire 	    scf_handle_bind(h) == -1) {
2171*3048Samaguire 		(void) fprintf(stderr, gettext(
2172*3048Samaguire 		    "%s: cannot connect to SMF repository\n"), myname);
2173*3048Samaguire 		ret = -1;
2174*3048Samaguire 		goto out;
2175*3048Samaguire 	}
2176*3048Samaguire 	if ((inst = scf_instance_create(h)) == NULL ||
2177*3048Samaguire 	    scf_handle_decode_fmri(h, RA_INSTANCE_ROUTING_SETUP,
2178*3048Samaguire 	    NULL, NULL, inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
2179*3048Samaguire 		(void) fprintf(stderr, gettext(
2180*3048Samaguire 		    "%s: unexpected libscf error: %s\n"), myname,
2181*3048Samaguire 		    scf_strerror(scf_error()));
2182*3048Samaguire 		ret = -1;
2183*3048Samaguire 		goto out;
2184*3048Samaguire 	}
2185*3048Samaguire 	if (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
2186*3048Samaguire 	    RA_PROP_ROUTING_CONF_READ, B_TRUE, B_TRUE, &old_conf_read) == -1) {
2187*3048Samaguire 		ret = -1;
2188*3048Samaguire 		goto out;
2189*3048Samaguire 	}
2190*3048Samaguire 
2191*3048Samaguire 	if (old_conf_read)
2192*3048Samaguire 		goto out;
2193*3048Samaguire 
2194*3048Samaguire 	/*
2195*3048Samaguire 	 * Now set "routing-conf-read" to true so we don`t reimport legacy
2196*3048Samaguire 	 * configuration again.
2197*3048Samaguire 	 */
2198*3048Samaguire 	if (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
2199*3048Samaguire 	    RA_PROP_ROUTING_CONF_READ, B_FALSE, B_TRUE) == -1)
2200*3048Samaguire 		return (-1);
2201*3048Samaguire 	(void) smf_refresh_instance(RA_INSTANCE_ROUTING_SETUP);
2202*3048Samaguire 
2203*3048Samaguire 	ra_resetvars(NULL);
2204*3048Samaguire 
2205*3048Samaguire 	/* First, gather values from routing.conf */
2206*3048Samaguire 	if ((r = ra_parseconf()) == -1) {
2207*3048Samaguire 		ret = -1;
2208*3048Samaguire 		goto out;
2209*3048Samaguire 	}
2210*3048Samaguire 	/* No routing.conf file found */
2211*3048Samaguire 	if (r == 0)
2212*3048Samaguire 		goto out;
2213*3048Samaguire 	/*
2214*3048Samaguire 	 * Now, set the options/variables gathered.  We set variables first,
2215*3048Samaguire 	 * as we cannot enable routing before we determine the daemons
2216*3048Samaguire 	 * to enable.
2217*3048Samaguire 	 */
2218*3048Samaguire 
2219*3048Samaguire 	for (i = 0; ra_vars[i].var_name != NULL; i++) {
2220*3048Samaguire 		/* Skip routing-svcs var, not featured in legacy config */
2221*3048Samaguire 		if (strcmp(ra_vars[i].var_name, RA_VAR_ROUTING_SVCS) == 0)
2222*3048Samaguire 			continue;
2223*3048Samaguire 		if (ra_smf_cb(ra_set_persistent_var_cb, ra_vars[i].var_fmri,
2224*3048Samaguire 		    &(ra_vars[i])) == -1) {
2225*3048Samaguire 			ret = -1;
2226*3048Samaguire 			goto out;
2227*3048Samaguire 		}
2228*3048Samaguire 	}
2229*3048Samaguire 	/* Clear routing-svcs value */
2230*3048Samaguire 	if (ra_smf_cb(ra_set_persistent_var_cb, routing_svcs->var_fmri,
2231*3048Samaguire 	    routing_svcs) == -1) {
2232*3048Samaguire 		ret = -1;
2233*3048Samaguire 		goto out;
2234*3048Samaguire 	}
2235*3048Samaguire 
2236*3048Samaguire 	if (ra_check_legacy_daemons() == -1) {
2237*3048Samaguire 		ret = -1;
2238*3048Samaguire 		goto out;
2239*3048Samaguire 	}
2240*3048Samaguire 
2241*3048Samaguire 	for (i = 0; ra_opts[i].opt_name != NULL; i++) {
2242*3048Samaguire 		if (ra_smf_cb(ra_set_persistent_opt_cb, ra_opts[i].opt_fmri,
2243*3048Samaguire 		    &(ra_opts[i])) == -1 ||
2244*3048Samaguire 		    ra_smf_cb(ra_set_default_opt_cb,
2245*3048Samaguire 		    ra_opts[i].opt_default_fmri, &(ra_opts[i])) == -1) {
2246*3048Samaguire 			ret = -1;
2247*3048Samaguire 			break;
2248*3048Samaguire 		}
2249*3048Samaguire 	}
2250*3048Samaguire out:
2251*3048Samaguire 	if (inst != NULL)
2252*3048Samaguire 		scf_instance_destroy(inst);
2253*3048Samaguire 	if (h != NULL)
2254*3048Samaguire 		scf_handle_destroy(h);
2255*3048Samaguire 
2256*3048Samaguire 	return (ret);
2257*3048Samaguire }
2258*3048Samaguire 
2259*3048Samaguire /*
2260*3048Samaguire  * Parse the configuration file and fill the ra_opts array with opt_value
2261*3048Samaguire  * and opt_default_value values, and the ra_vars array with var_value and
2262*3048Samaguire  * var_default_value values.  Then copy aside routing.conf so it will not
2263*3048Samaguire  * be read by future invokations of routeadm.
2264*3048Samaguire  */
2265*3048Samaguire static int
2266*3048Samaguire ra_parseconf(void)
2267*3048Samaguire {
2268*3048Samaguire 	FILE	*fp;
2269*3048Samaguire 	uint_t	lineno;
2270*3048Samaguire 	char	line[RA_MAX_CONF_LINE];
2271*3048Samaguire 	char	*cp, *confstr;
2272*3048Samaguire 	raopt_t	*raopt;
2273*3048Samaguire 	ravar_t *ravar;
2274*3048Samaguire 
2275*3048Samaguire 	if ((fp = fopen(RA_CONF_FILE, "r")) == NULL) {
2276*3048Samaguire 		/*
2277*3048Samaguire 		 * There's no config file, so we simply return as there
2278*3048Samaguire 		 * is no work to do.
2279*3048Samaguire 		 */
2280*3048Samaguire 		return (0);
2281*3048Samaguire 	}
2282*3048Samaguire 
2283*3048Samaguire 	for (lineno = 1; fgets(line, sizeof (line), fp) != NULL; lineno++) {
2284*3048Samaguire 		if (line[strlen(line) - 1] == '\n')
2285*3048Samaguire 			line[strlen(line) - 1] = '\0';
2286*3048Samaguire 
2287*3048Samaguire 		cp = line;
2288*3048Samaguire 
2289*3048Samaguire 		/* Skip leading whitespace */
2290*3048Samaguire 		while (isspace(*cp))
2291*3048Samaguire 			cp++;
2292*3048Samaguire 
2293*3048Samaguire 		/* Skip comment lines and empty lines */
2294*3048Samaguire 		if (*cp == '#' || *cp == '\0')
2295*3048Samaguire 			continue;
2296*3048Samaguire 
2297*3048Samaguire 		/*
2298*3048Samaguire 		 * Anything else must be of the form:
2299*3048Samaguire 		 * <option> <value> <default_value>
2300*3048Samaguire 		 */
2301*3048Samaguire 		if ((confstr = strtok(cp, " ")) == NULL) {
2302*3048Samaguire 			(void) fprintf(stderr,
2303*3048Samaguire 			    gettext("%1$s: %2$s: invalid entry on line %3$d\n"),
2304*3048Samaguire 			    myname, RA_CONF_FILE, lineno);
2305*3048Samaguire 			continue;
2306*3048Samaguire 		}
2307*3048Samaguire 
2308*3048Samaguire 		if ((raopt = ra_str2opt(confstr)) != NULL) {
2309*3048Samaguire 			if (ra_parseopt(confstr, lineno, raopt) != 0) {
2310*3048Samaguire 				(void) fclose(fp);
2311*3048Samaguire 				return (-1);
2312*3048Samaguire 			}
2313*3048Samaguire 		} else if ((ravar = ra_str2var(confstr)) != NULL) {
2314*3048Samaguire 			if (ra_parsevar(confstr, ravar) != 0) {
2315*3048Samaguire 				(void) fclose(fp);
2316*3048Samaguire 				return (-1);
2317*3048Samaguire 			}
2318*3048Samaguire 		} else {
2319*3048Samaguire 			(void) fprintf(stderr,
2320*3048Samaguire 			    gettext("%1$s: %2$s: invalid option name on "
2321*3048Samaguire 				"line %3$d\n"),
2322*3048Samaguire 			    myname, RA_CONF_FILE, lineno);
2323*3048Samaguire 			continue;
2324*3048Samaguire 		}
2325*3048Samaguire 	}
2326*3048Samaguire 
2327*3048Samaguire 	(void) fclose(fp);
2328*3048Samaguire 
2329*3048Samaguire 	return (1);
2330*3048Samaguire }
2331*3048Samaguire 
2332*3048Samaguire static int
2333*3048Samaguire ra_parseopt(char *confstr, int lineno, raopt_t *raopt)
2334*3048Samaguire {
2335*3048Samaguire 	oval_t oval, d_oval;
2336*3048Samaguire 
2337*3048Samaguire 	if ((confstr = strtok(NULL, " ")) == NULL) {
2338*3048Samaguire 		(void) fprintf(stderr,
2339*3048Samaguire 		    gettext("%1$s: %2$s: missing value on line %3$d\n"),
2340*3048Samaguire 		    myname, RA_CONF_FILE, lineno);
2341*3048Samaguire 		return (0);
2342*3048Samaguire 	}
2343*3048Samaguire 	if ((oval = ra_str2oval(confstr)) == OPT_INVALID) {
2344*3048Samaguire 		(void) fprintf(stderr,
2345*3048Samaguire 		    gettext("%1$s: %2$s: invalid option "
2346*3048Samaguire 			"value on line %3$d\n"),
2347*3048Samaguire 		    myname, RA_CONF_FILE, lineno);
2348*3048Samaguire 		return (0);
2349*3048Samaguire 	}
2350*3048Samaguire 	if (oval != OPT_DEFAULT)
2351*3048Samaguire 		raopt->opt_enabled = oval == OPT_ENABLED;
2352*3048Samaguire 
2353*3048Samaguire 	if ((confstr = strtok(NULL, " ")) == NULL) {
2354*3048Samaguire 		(void) fprintf(stderr,
2355*3048Samaguire 		    gettext("%1$s: %2$s: missing revert "
2356*3048Samaguire 			"value on line %3$d\n"),
2357*3048Samaguire 		    myname, RA_CONF_FILE, lineno);
2358*3048Samaguire 		return (0);
2359*3048Samaguire 	}
2360*3048Samaguire 	if ((d_oval = ra_str2oval(confstr)) == OPT_INVALID) {
2361*3048Samaguire 		(void) fprintf(stderr,
2362*3048Samaguire 		    gettext("%1$s: %2$s: invalid revert "
2363*3048Samaguire 			"value on line %3$d\n"),
2364*3048Samaguire 		    myname, RA_CONF_FILE, lineno, confstr);
2365*3048Samaguire 		return (0);
2366*3048Samaguire 	}
2367*3048Samaguire 	raopt->opt_default_enabled = d_oval == OPT_ENABLED;
2368*3048Samaguire 	if (oval == OPT_DEFAULT)
2369*3048Samaguire 		raopt->opt_enabled = d_oval == OPT_ENABLED;
2370*3048Samaguire 	return (0);
2371*3048Samaguire }
2372*3048Samaguire 
2373*3048Samaguire static int
2374*3048Samaguire ra_parsevar(char *confstr, ravar_t *ravar)
2375*3048Samaguire {
2376*3048Samaguire 	confstr = strtok(NULL, "=");
2377*3048Samaguire 	if (confstr == NULL) {
2378*3048Samaguire 		/*
2379*3048Samaguire 		 * This isn't an error condition, it simply means that the
2380*3048Samaguire 		 * variable has no value.
2381*3048Samaguire 		 */
2382*3048Samaguire 		ravar->var_value = NULL;
2383*3048Samaguire 		return (0);
2384*3048Samaguire 	}
2385*3048Samaguire 
2386*3048Samaguire 	if ((ravar->var_value = strdup(confstr)) == NULL) {
2387*3048Samaguire 		(void) fprintf(stderr, gettext("%s: "
2388*3048Samaguire 		    "unable to allocate memory\n"), myname);
2389*3048Samaguire 		return (-1);
2390*3048Samaguire 	}
2391*3048Samaguire 	return (0);
2392*3048Samaguire }
2393*3048Samaguire 
2394*3048Samaguire /* Convert a string to an option value. */
2395*3048Samaguire static oval_t
2396*3048Samaguire ra_str2oval(const char *valstr)
2397*3048Samaguire {
2398*3048Samaguire 	if (strcmp(valstr, "enabled") == 0)
2399*3048Samaguire 		return (OPT_ENABLED);
2400*3048Samaguire 	else if (strcmp(valstr, "disabled") == 0)
2401*3048Samaguire 		return (OPT_DISABLED);
2402*3048Samaguire 	else if (strcmp(valstr, "default") == 0)
2403*3048Samaguire 		return (OPT_DEFAULT);
2404*3048Samaguire 	return (OPT_INVALID);
2405*3048Samaguire }
2406*3048Samaguire 
2407*3048Samaguire static raopt_t *
2408*3048Samaguire ra_str2opt(const char *optnamestr)
2409*3048Samaguire {
2410*3048Samaguire 	int	i;
2411*3048Samaguire 
2412*3048Samaguire 	for (i = 0; ra_opts[i].opt_name != NULL; i++) {
2413*3048Samaguire 		if (strcmp(optnamestr, ra_opts[i].opt_name) == 0)
2414*3048Samaguire 			break;
2415*3048Samaguire 	}
2416*3048Samaguire 	if (ra_opts[i].opt_name == NULL)
2417*3048Samaguire 		return (NULL);
2418*3048Samaguire 	return (&ra_opts[i]);
2419*3048Samaguire }
2420*3048Samaguire 
2421*3048Samaguire /*
2422*3048Samaguire  * Reset all option values previously gathered to B_FALSE.
2423*3048Samaguire  */
2424*3048Samaguire static void
2425*3048Samaguire ra_resetopts(void)
2426*3048Samaguire {
2427*3048Samaguire 	int	i;
2428*3048Samaguire 
2429*3048Samaguire 	for (i = 0; ra_opts[i].opt_name != NULL; i++) {
2430*3048Samaguire 		ra_opts[i].opt_enabled = B_FALSE;
2431*3048Samaguire 		ra_opts[i].opt_default_enabled = B_FALSE;
2432*3048Samaguire 	}
2433*3048Samaguire }
2434*3048Samaguire 
2435*3048Samaguire static ravar_t *
2436*3048Samaguire ra_str2var(const char *varnamestr)
2437*3048Samaguire {
2438*3048Samaguire 	int	i;
2439*3048Samaguire 	for (i = 0; ra_vars[i].var_name != NULL; i++) {
2440*3048Samaguire 		if (strcmp(varnamestr, ra_vars[i].var_name) == 0)
2441*3048Samaguire 			break;
2442*3048Samaguire 	}
2443*3048Samaguire 	if (ra_vars[i].var_name == NULL)
2444*3048Samaguire 		return (NULL);
2445*3048Samaguire 	return (&ra_vars[i]);
2446*3048Samaguire }
2447*3048Samaguire 
2448*3048Samaguire /*
2449*3048Samaguire  * Reset variable values previously gathered to NULL.
2450*3048Samaguire  */
2451*3048Samaguire static void
2452*3048Samaguire ra_resetvars(const char *proto)
2453*3048Samaguire {
2454*3048Samaguire 	int	i;
2455*3048Samaguire 	for (i = 0; ra_vars[i].var_name != NULL; i++) {
2456*3048Samaguire 		if (proto != NULL &&
2457*3048Samaguire 		    !VAR_PROTO_MATCH(ra_vars[i].var_name, proto))
2458*3048Samaguire 			continue;
2459*3048Samaguire 		if (ra_vars[i].var_value != NULL)
2460*3048Samaguire 			free(ra_vars[i].var_value);
2461*3048Samaguire 		ra_vars[i].var_value = NULL;
2462*3048Samaguire 		if (ra_vars[i].var_default_value != NULL)
2463*3048Samaguire 			free(ra_vars[i].var_default_value);
2464*3048Samaguire 		ra_vars[i].var_default_value = NULL;
2465*3048Samaguire 	}
2466*3048Samaguire }
2467*3048Samaguire 
2468*3048Samaguire /*
2469*3048Samaguire  * Given an option name, this function provides an internationalized, human
2470*3048Samaguire  * readable version of the option name.
2471*3048Samaguire  */
2472*3048Samaguire static char *
2473*3048Samaguire ra_intloptname(const char *optname)
2474*3048Samaguire {
2475*3048Samaguire 	if (strcmp(optname, RA_OPT_IPV4_FORWARDING) == 0)
2476*3048Samaguire 		return (gettext("IPv4 forwarding"));
2477*3048Samaguire 	else if (strcmp(optname, RA_OPT_IPV4_ROUTING) == 0)
2478*3048Samaguire 		return (gettext("IPv4 routing"));
2479*3048Samaguire 	else if (strcmp(optname, RA_OPT_IPV6_FORWARDING) == 0)
2480*3048Samaguire 		return (gettext("IPv6 forwarding"));
2481*3048Samaguire 	else if (strcmp(optname, RA_OPT_IPV6_ROUTING) == 0)
2482*3048Samaguire 		return (gettext("IPv6 routing"));
2483*3048Samaguire 	else if (strcmp(optname, RA_VAR_IPV4_ROUTING_DAEMON) == 0)
2484*3048Samaguire 		return (gettext("IPv4 routing daemon"));
2485*3048Samaguire 	else if (strcmp(optname, RA_VAR_IPV4_ROUTING_DAEMON_ARGS) == 0)
2486*3048Samaguire 		return (gettext("IPv4 routing daemon args"));
2487*3048Samaguire 	else if (strcmp(optname, RA_VAR_IPV4_ROUTING_STOP_CMD) == 0)
2488*3048Samaguire 		return (gettext("IPv4 routing daemon stop"));
2489*3048Samaguire 	else if (strcmp(optname, RA_VAR_IPV6_ROUTING_DAEMON) == 0)
2490*3048Samaguire 		return (gettext("IPv6 routing daemon"));
2491*3048Samaguire 	else if (strcmp(optname, RA_VAR_IPV6_ROUTING_DAEMON_ARGS) == 0)
2492*3048Samaguire 		return (gettext("IPv6 routing daemon args"));
2493*3048Samaguire 	else if (strcmp(optname, RA_VAR_IPV6_ROUTING_STOP_CMD) == 0)
2494*3048Samaguire 		return (gettext("IPv6 routing daemon stop"));
2495*3048Samaguire 	else if (strcmp(optname, RA_VAR_ROUTING_SVCS) == 0)
2496*3048Samaguire 		return (gettext("Routing services"));
2497*3048Samaguire 	/*
2498*3048Samaguire 	 * If we get here, there's a bug and someone should trip over this
2499*3048Samaguire 	 * NULL pointer.
2500*3048Samaguire 	 */
2501*3048Samaguire 	return (NULL);
2502*3048Samaguire }
2503