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