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