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