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 * Refresh here to get latest property values prior 1495 * to starting daemon. 1496 */ 1497 (void) smf_refresh_instance(inst_fmri); 1498 /* 1499 * For current changes (result of -u), we 1500 * enable/disable depending on persistent value 1501 * stored in general/enabled. Here we disable 1502 * old routing-svcs (identified by a current-routing-svc 1503 * value of false) also. 1504 */ 1505 ret = persistent_state_enabled && curr_svc ? 1506 smf_enable_instance(inst_fmri, 0) : 1507 smf_disable_instance(inst_fmri, 0); 1508 if (ret != 0) { 1509 (void) fprintf(stderr, gettext( 1510 "%s: unexpected libscf error: %s\n"), 1511 myname, scf_strerror(scf_error())); 1512 return (-1); 1513 } 1514 if (current_state_enabled && persistent_state_enabled) { 1515 /* 1516 * Instance was already enabled, so we restart 1517 * to get latest property values. This covers 1518 * the case where users update properties 1519 * via routeadm -m, and issue an update. The 1520 * daemon should be running with the latest 1521 * property values. 1522 */ 1523 (void) smf_restart_instance(inst_fmri); 1524 } 1525 } 1526 } 1527 return (0); 1528 } 1529 1530 static int 1531 ra_set_default_opt_cb(void *data, scf_walkinfo_t *wip) 1532 { 1533 scf_instance_t *inst = wip->inst; 1534 scf_handle_t *h = scf_instance_handle(inst); 1535 raopt_t *raopt = data; 1536 1537 return (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM, 1538 raopt->opt_default_prop, B_FALSE, raopt->opt_default_enabled)); 1539 } 1540 1541 static int 1542 ra_get_default_opt_cb(void *data, scf_walkinfo_t *wip) 1543 { 1544 scf_instance_t *inst = wip->inst; 1545 scf_handle_t *h = scf_instance_handle(inst); 1546 raopt_t *raopt = data; 1547 1548 return (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM, 1549 raopt->opt_default_prop, B_TRUE, B_TRUE, 1550 &(raopt->opt_default_enabled))); 1551 } 1552 1553 /* 1554 * Callbacks to set/retrieve persistent/default routing variable values. 1555 * The set functions use the value stored in the var_value/var_default_value 1556 * field of the associated ra_var_t, while the retrieval functions store 1557 * the value retrieved in that field. 1558 */ 1559 static int 1560 ra_get_persistent_var_cb(void *data, scf_walkinfo_t *wip) 1561 { 1562 scf_instance_t *inst = wip->inst; 1563 scf_handle_t *h = scf_instance_handle(inst); 1564 ravar_t *ravar = data; 1565 1566 return (ra_get_single_prop_as_string(h, inst, RA_PG_ROUTEADM, 1567 ravar->var_prop, B_TRUE, B_TRUE, NULL, &ravar->var_value)); 1568 } 1569 1570 static int 1571 ra_set_persistent_var_cb(void *data, scf_walkinfo_t *wip) 1572 { 1573 scf_instance_t *inst = wip->inst; 1574 scf_handle_t *h = scf_instance_handle(inst); 1575 ravar_t *ravar = data; 1576 1577 return (ra_set_prop_from_string(h, inst, RA_PG_ROUTEADM, 1578 ravar->var_prop, SCF_TYPE_INVALID, B_FALSE, 1, 1579 (const char **)&ravar->var_value)); 1580 } 1581 1582 static int 1583 ra_get_default_var_cb(void *data, scf_walkinfo_t *wip) 1584 { 1585 scf_instance_t *inst = wip->inst; 1586 scf_handle_t *h = scf_instance_handle(inst); 1587 ravar_t *ravar = data; 1588 1589 return (ra_get_single_prop_as_string(h, inst, RA_PG_ROUTEADM, 1590 ravar->var_default_prop, B_TRUE, B_TRUE, NULL, 1591 &ravar->var_default_value)); 1592 } 1593 1594 /* 1595 * Depending on the value of the boolean_t * passed in, this callback 1596 * either marks the relevant service(s) as current-routing-svcs (or unmarking) 1597 * by setting that property to true or false. When routing services 1598 * are to be enabled, the a current-routing-svc value of true flags the 1599 * service as one to be enabled. 1600 */ 1601 static int 1602 ra_mark_routing_svcs_cb(void *data, scf_walkinfo_t *wip) 1603 { 1604 scf_instance_t *inst = wip->inst; 1605 scf_handle_t *h = scf_instance_handle(inst); 1606 boolean_t *mark = data; 1607 boolean_t marked; 1608 int numvalues = 0; 1609 char **protolist = NULL; 1610 1611 /* Check we are dealing with a routing daemon service */ 1612 if (ra_get_prop_as_string(h, inst, RA_PG_ROUTEADM, RA_PROP_PROTO, 1613 B_TRUE, B_FALSE, NULL, &numvalues, &protolist) == -1) 1614 return (0); 1615 ra_free_prop_values(numvalues, protolist); 1616 if (*mark) 1617 return (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM, 1618 RA_PROP_CURR_ROUTING_SVC, B_TRUE, B_TRUE)); 1619 /* Unmark service. */ 1620 if (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM, 1621 RA_PROP_CURR_ROUTING_SVC, B_TRUE, B_FALSE, &marked) == 0 && marked) 1622 return (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM, 1623 RA_PROP_CURR_ROUTING_SVC, B_TRUE, B_FALSE)); 1624 return (0); 1625 } 1626 1627 /* 1628 * List property values for all properties in the "routing" property 1629 * group of the routing service instance. 1630 */ 1631 1632 /* ARGSUSED0 */ 1633 static int 1634 ra_list_props_cb(void *data, scf_walkinfo_t *wip) 1635 { 1636 const char *inst_fmri = wip->fmri; 1637 scf_instance_t *inst = wip->inst; 1638 scf_handle_t *h = scf_instance_handle(inst); 1639 scf_iter_t *propiter, *valiter; 1640 scf_propertygroup_t *pg; 1641 scf_property_t *prop; 1642 scf_value_t *val; 1643 char **protolist = NULL, *pnamebuf, *valbuf; 1644 ssize_t pnamelen, vallen; 1645 int numvalues = 0; 1646 int propiterret, valiterret, retval = 0; 1647 1648 /* Services with no "protocol" property are not routing daemons */ 1649 if (ra_get_prop_as_string(h, inst, RA_PG_ROUTEADM, RA_PROP_PROTO, 1650 B_TRUE, B_FALSE, NULL, &numvalues, &protolist) == -1) { 1651 if (scf_error() == SCF_ERROR_NOT_FOUND) 1652 (void) fprintf(stderr, 1653 gettext("%s: %s is not a routing daemon service\n"), 1654 myname, inst_fmri); 1655 else 1656 (void) fprintf(stderr, 1657 gettext("%s: unexpected libscf error: %s\n"), 1658 myname, scf_strerror(scf_error())); 1659 ra_free_prop_values(numvalues, protolist); 1660 return (-1); 1661 } 1662 ra_free_prop_values(numvalues, protolist); 1663 1664 if (ra_get_pg(h, inst, RA_PG_ROUTING, B_TRUE, B_FALSE, &pg) == -1) { 1665 if (scf_error() == SCF_ERROR_NOT_FOUND) { 1666 (void) printf("%s: no %s property group for %s\n", 1667 myname, RA_PG_ROUTING, inst_fmri); 1668 return (0); 1669 } 1670 (void) fprintf(stderr, 1671 gettext("%s: unexpected libscf error: %s\n"), 1672 myname, scf_strerror(scf_error())); 1673 return (-1); 1674 } 1675 1676 (void) printf("%s:\n", inst_fmri); 1677 1678 /* Create an iterator to walk through all properties */ 1679 if ((propiter = scf_iter_create(h)) == NULL || 1680 (prop = scf_property_create(h)) == NULL || 1681 scf_iter_pg_properties(propiter, pg) != 0) { 1682 (void) fprintf(stderr, gettext 1683 ("%s: could not iterate through properties for %s: %s\n"), 1684 myname, inst_fmri, scf_strerror(scf_error())); 1685 } 1686 while ((propiterret = scf_iter_next_property(propiter, prop)) == 1) { 1687 if ((pnamelen = scf_property_get_name(prop, NULL, 0) + 1) 1688 == 0) { 1689 (void) fprintf(stderr, gettext("%s: could not retrieve " 1690 "property name for instance %s: %s\n"), myname, 1691 inst_fmri, scf_strerror(scf_error())); 1692 retval = -1; 1693 break; 1694 } 1695 if ((pnamebuf = malloc(pnamelen)) == NULL) { 1696 (void) fprintf(stderr, 1697 gettext("%s: out of memory\n"), myname); 1698 retval = -1; 1699 break; 1700 } 1701 (void) scf_property_get_name(prop, pnamebuf, 1702 pnamelen); 1703 (void) printf("\t%s = ", pnamebuf); 1704 if ((valiter = scf_iter_create(h)) == NULL || 1705 (val = scf_value_create(h)) == NULL || 1706 scf_iter_property_values(valiter, prop) 1707 != 0) { 1708 (void) fprintf(stderr, gettext 1709 ("%s: could not iterate through " 1710 "properties for %s: %s\n"), myname, inst_fmri, 1711 scf_strerror(scf_error())); 1712 scf_value_destroy(val); 1713 scf_iter_destroy(valiter); 1714 free(pnamebuf); 1715 retval = -1; 1716 break; 1717 } 1718 while ((valiterret = scf_iter_next_value(valiter, val)) == 1) { 1719 if ((vallen = scf_value_get_as_string 1720 (val, NULL, 0) + 1) == 0) { 1721 (void) fprintf(stderr, gettext 1722 ("%s: could not retrieve " 1723 "property value for instance %s, " 1724 "property %s: %s\n"), myname, inst_fmri, 1725 pnamebuf, scf_strerror(scf_error())); 1726 retval = -1; 1727 } else if ((valbuf = malloc(vallen)) == NULL) { 1728 (void) fprintf(stderr, 1729 gettext("%s: out of memory\n"), myname); 1730 retval = -1; 1731 } 1732 if (retval == -1) { 1733 scf_iter_destroy(valiter); 1734 scf_value_destroy(val); 1735 free(pnamebuf); 1736 goto out; 1737 } 1738 (void) scf_value_get_as_string(val, valbuf, vallen); 1739 (void) printf("%s ", valbuf); 1740 free(valbuf); 1741 } 1742 (void) printf("\n"); 1743 scf_iter_destroy(valiter); 1744 scf_value_destroy(val); 1745 free(pnamebuf); 1746 if (valiterret == -1) { 1747 (void) fprintf(stderr, 1748 gettext("%s: could not iterate through" 1749 "properties for %s: %s\n"), myname, inst_fmri, 1750 scf_strerror(scf_error())); 1751 retval = -1; 1752 break; 1753 } 1754 } 1755 out: 1756 scf_iter_destroy(propiter); 1757 scf_property_destroy(prop); 1758 scf_pg_destroy(pg); 1759 if (propiterret == -1) 1760 (void) fprintf(stderr, gettext 1761 ("%s: could not iterate through properties for %s: %s\n"), 1762 myname, inst_fmri, scf_strerror(scf_error())); 1763 return (retval); 1764 } 1765 1766 /* 1767 * Modify property with name stored in passed-in ra_prop_t to have 1768 * the assocatied values. Only works for existing properties in 1769 * the "routing" property group for routing daemon services, so all 1770 * routing daemons should place configurable options in that group. 1771 */ 1772 static int 1773 ra_modify_props_cb(void *data, scf_walkinfo_t *wip) 1774 { 1775 const char *inst_fmri = wip->fmri; 1776 scf_instance_t *inst = wip->inst; 1777 scf_handle_t *h = scf_instance_handle(inst); 1778 ra_prop_t *raprop = data; 1779 int numvalues = 0; 1780 char **protolist = NULL; 1781 1782 /* Services with no "protocol" property are not routing daemons */ 1783 if (ra_get_prop_as_string(h, inst, RA_PG_ROUTEADM, RA_PROP_PROTO, 1784 B_TRUE, B_FALSE, NULL, &numvalues, &protolist) == -1) { 1785 if (scf_error() == SCF_ERROR_NOT_FOUND) 1786 (void) fprintf(stderr, 1787 gettext("%s: %s is not a routing daemon service\n"), 1788 myname, inst_fmri); 1789 else 1790 (void) fprintf(stderr, 1791 gettext("%s: unexpected libscf error: %s\n"), 1792 myname, scf_strerror(scf_error())); 1793 ra_free_prop_values(numvalues, protolist); 1794 return (-1); 1795 } 1796 ra_free_prop_values(numvalues, protolist); 1797 1798 if (ra_set_prop_from_string(h, inst, RA_PG_ROUTING, raprop->prop_name, 1799 SCF_TYPE_INVALID, B_FALSE, raprop->prop_numvalues, 1800 (const char **)raprop->prop_values) == -1) 1801 return (-1); 1802 1803 (void) smf_refresh_instance(inst_fmri); 1804 return (0); 1805 } 1806 1807 /* 1808 * Display FMRI, state for each routing daemon service. 1809 */ 1810 1811 /* ARGSUSED0 */ 1812 static int 1813 ra_print_state_cb(void *data, scf_walkinfo_t *wip) 1814 { 1815 const char *inst_fmri = wip->fmri; 1816 scf_instance_t *inst = wip->inst; 1817 scf_handle_t *h = scf_instance_handle(inst); 1818 char *inst_state, **protolist = NULL; 1819 int numvalues = 0; 1820 1821 /* Ensure service is a routing daemon */ 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 return (0); 1825 ra_free_prop_values(numvalues, protolist); 1826 1827 if ((inst_state = smf_get_state(inst_fmri)) == NULL) { 1828 (void) fprintf(stderr, 1829 gettext("%s: could not retrieve state for %s: %s\n"), 1830 myname, inst_fmri, scf_strerror(scf_error())); 1831 return (-1); 1832 } 1833 (void) printf("%27s %2s\n", inst_state, inst_fmri); 1834 free(inst_state); 1835 1836 return (0); 1837 } 1838 1839 static int 1840 ra_get_pg(scf_handle_t *h, scf_instance_t *inst, const char *pgname, 1841 boolean_t composed, boolean_t required, scf_propertygroup_t **pg) 1842 { 1843 /* Retrieve (possibly composed) property group for instance */ 1844 if ((*pg = scf_pg_create(h)) == NULL || (composed && 1845 scf_instance_get_pg_composed(inst, NULL, pgname, *pg) != 0) || 1846 (!composed && scf_instance_get_pg(inst, pgname, *pg) != 0)) { 1847 if (scf_error() == SCF_ERROR_NOT_FOUND) { 1848 if (required) 1849 (void) fprintf(stderr, gettext( 1850 "%s: no such property group %s\n"), 1851 myname, pgname); 1852 return (-1); 1853 } 1854 if (required) 1855 (void) fprintf(stderr, gettext( 1856 "%s: unexpected libscf error: %s\n"), myname, 1857 scf_strerror(scf_error())); 1858 return (-1); 1859 } 1860 return (0); 1861 } 1862 1863 static int 1864 ra_get_boolean_prop(scf_handle_t *h, scf_instance_t *inst, 1865 const char *pgname, const char *propname, boolean_t composed, 1866 boolean_t required, boolean_t *val) 1867 { 1868 char *valstr; 1869 1870 if (ra_get_single_prop_as_string(h, inst, pgname, propname, 1871 composed, required, NULL, &valstr) != 0) 1872 return (-1); 1873 *val = strcmp(valstr, RA_PROPVAL_BOOLEAN_TRUE) == 0; 1874 free(valstr); 1875 return (0); 1876 } 1877 1878 static int 1879 ra_get_single_prop_as_string(scf_handle_t *h, scf_instance_t *inst, 1880 const char *pgname, const char *propname, boolean_t composed, 1881 boolean_t required, scf_type_t *type, char **value) 1882 { 1883 char **values; 1884 int numvalues = 1; 1885 1886 if (ra_get_prop_as_string(h, inst, pgname, propname, composed, required, 1887 type, &numvalues, &values) == -1) 1888 return (-1); 1889 *value = values[0]; 1890 free(values); 1891 return (0); 1892 } 1893 1894 /* 1895 * Retrieve property named in propname, possibly using the composed 1896 * property group view (union of instance and service-level properties, 1897 * where instance-level properties override service-level values). 1898 */ 1899 static int 1900 ra_get_prop_as_string(scf_handle_t *h, scf_instance_t *inst, 1901 const char *pgname, const char *propname, boolean_t composed, 1902 boolean_t required, scf_type_t *type, int *numvalues, char ***values) 1903 { 1904 scf_propertygroup_t *pg = NULL; 1905 scf_property_t *prop = NULL; 1906 scf_iter_t *valiter = NULL; 1907 scf_value_t *val = NULL; 1908 ssize_t vallen = 0; 1909 int valiterret, i, numvalues_retrieved, ret = 0; 1910 1911 if (ra_get_pg(h, inst, pgname, composed, required, &pg) == -1) 1912 return (-1); 1913 1914 *values = NULL; 1915 /* 1916 * Retrieve values. All values routeadm needs to retrieve 1917 * (bar those gathered by routeadm -l), are known to be single-valued. 1918 */ 1919 if ((prop = scf_property_create(h)) == NULL) 1920 goto error; 1921 if (scf_pg_get_property(pg, propname, prop) != 0) { 1922 *numvalues = 0; 1923 if (scf_error() == SCF_ERROR_NOT_FOUND) { 1924 if (required) 1925 (void) fprintf(stderr, gettext( 1926 "%s: property %s/%s not found\n"), 1927 myname, pgname, propname); 1928 ret = -1; 1929 goto out; 1930 } 1931 goto error; 1932 } 1933 if ((val = scf_value_create(h)) == NULL && 1934 scf_property_get_value(prop, val) != 0 || 1935 (valiter = scf_iter_create(h)) == NULL || 1936 scf_iter_property_values(valiter, prop) != 0) 1937 goto error; 1938 /* retrieve each value */ 1939 for (numvalues_retrieved = 0; 1940 (valiterret = scf_iter_next_value(valiter, val)) == 1; 1941 numvalues_retrieved++) { 1942 if ((vallen = scf_value_get_as_string 1943 (val, NULL, 0) + 1) == 0) 1944 goto error; 1945 if ((*values = realloc(*values, 1946 sizeof (*values) + sizeof (char *))) == NULL || 1947 ((*values)[numvalues_retrieved] = malloc(vallen)) == NULL) { 1948 (void) fprintf(stderr, gettext( 1949 "%s: out of memory\n"), myname); 1950 ret = -1; 1951 goto out; 1952 } 1953 (void) scf_value_get_as_string(val, 1954 (*values)[numvalues_retrieved], vallen); 1955 } 1956 if (valiterret == -1) 1957 goto error; 1958 /* 1959 * if *numvalues != 0, it holds expected number of values. If a 1960 * different number are found, it is an error. 1961 */ 1962 if (*numvalues != 0 && *numvalues != numvalues_retrieved) { 1963 (void) fprintf(stderr, gettext( 1964 "%s: got %d values for property %s/%s, expected %d\n"), 1965 myname, numvalues_retrieved, pgname, propname, *numvalues); 1966 ret = -1; 1967 goto out; 1968 } 1969 *numvalues = numvalues_retrieved; 1970 1971 /* Retrieve property type if required. */ 1972 if (type != NULL) 1973 (void) scf_property_type(prop, type); 1974 1975 goto out; 1976 error: 1977 if (scf_error() == SCF_ERROR_NOT_FOUND) { 1978 (void) fprintf(stderr, gettext( 1979 "%s: property %s not found"), myname, propname); 1980 } else { 1981 (void) fprintf(stderr, gettext( 1982 "%s: unexpected libscf error: %s, "), myname); 1983 } 1984 for (i = 0; i < numvalues_retrieved; i++) 1985 free((*values)[i]); 1986 if (*values != NULL) 1987 free(*values); 1988 1989 ret = -1; 1990 out: 1991 if (val != NULL) 1992 scf_value_destroy(val); 1993 if (valiter != NULL) 1994 scf_iter_destroy(valiter); 1995 if (prop != NULL) 1996 scf_property_destroy(prop); 1997 if (pg != NULL) 1998 scf_pg_destroy(pg); 1999 return (ret); 2000 } 2001 2002 static void 2003 ra_free_prop_values(int numvalues, char **values) 2004 { 2005 int i; 2006 if (values != NULL) { 2007 for (i = 0; i < numvalues; i++) 2008 free(values[i]); 2009 free(values); 2010 } 2011 } 2012 2013 static int 2014 ra_set_boolean_prop(scf_handle_t *h, scf_instance_t *inst, const char *pgname, 2015 const char *prop, boolean_t create, boolean_t propval) 2016 { 2017 const char *val = propval ? RA_PROPVAL_BOOLEAN_TRUE : 2018 RA_PROPVAL_BOOLEAN_FALSE; 2019 2020 return (ra_set_prop_from_string(h, inst, pgname, prop, SCF_TYPE_BOOLEAN, 2021 create, 1, &val)); 2022 } 2023 2024 /* 2025 * Set the property named in propname to the values passed in in the propvals 2026 * array. Only create a new property if "create" is true. 2027 */ 2028 static int 2029 ra_set_prop_from_string(scf_handle_t *h, scf_instance_t *inst, 2030 const char *pgname, const char *propname, scf_type_t proptype, 2031 boolean_t create, int numpropvals, const char **propvals) 2032 { 2033 scf_propertygroup_t *instpg = NULL, *cpg = NULL; 2034 scf_type_t oldproptype, newproptype = proptype; 2035 scf_property_t *prop = NULL; 2036 scf_value_t **values = NULL; 2037 scf_transaction_t *tx = NULL; 2038 scf_transaction_entry_t *ent = NULL; 2039 boolean_t new = B_FALSE; 2040 int i, retval, numvalues = 0, ret = 0; 2041 char *pgtype = NULL, **ovalues; 2042 ssize_t typelen; 2043 2044 /* Firstly, does property exist? If not, and create is false, bail */ 2045 if (ra_get_prop_as_string(h, inst, pgname, propname, B_TRUE, 2046 B_FALSE, &oldproptype, &numvalues, &ovalues) == -1) { 2047 if (scf_error() != SCF_ERROR_NOT_FOUND) 2048 goto error; 2049 if (!create) { 2050 (void) fprintf(stderr, gettext( 2051 "%s: no such property %s/%s\n"), myname, pgname, 2052 propname); 2053 return (-1); 2054 } 2055 } else 2056 ra_free_prop_values(numvalues, ovalues); 2057 2058 /* Use old property type */ 2059 if (proptype == SCF_TYPE_INVALID) 2060 newproptype = oldproptype; 2061 2062 /* 2063 * Does property group exist at instance level? If not, we need to 2064 * create it, since the composed view of the property group did 2065 * contain the property. We never modify properties at the service 2066 * level, as it`s possible that multiple instances will inherit those 2067 * settings. 2068 */ 2069 if (ra_get_pg(h, inst, pgname, B_FALSE, B_FALSE, &instpg) == -1) { 2070 if (scf_error() != SCF_ERROR_NOT_FOUND) 2071 goto error; 2072 /* Ensure pg exists at service level, get composed pg */ 2073 if (ra_get_pg(h, inst, pgname, B_TRUE, B_FALSE, &cpg) == -1) 2074 goto error; 2075 2076 /* Create instance-level property group */ 2077 if ((typelen = scf_pg_get_type(cpg, NULL, 0) + 1) == 0) 2078 goto error; 2079 if ((pgtype = malloc(typelen)) == NULL) { 2080 (void) fprintf(stderr, gettext( 2081 "%s: out of memory\n"), myname); 2082 goto error; 2083 } 2084 (void) scf_pg_get_type(cpg, pgtype, typelen); 2085 if ((instpg = scf_pg_create(h)) == NULL || 2086 scf_instance_add_pg(inst, pgname, pgtype, 0, instpg) 2087 == -1) { 2088 (void) fprintf(stderr, gettext( 2089 "%s: could not create property group %s\n"), 2090 myname, pgname); 2091 goto error; 2092 } 2093 } 2094 if ((prop = scf_property_create(h)) == NULL) 2095 goto error; 2096 if ((values = calloc(numpropvals, sizeof (scf_value_t *))) == NULL) { 2097 (void) fprintf(stderr, gettext("%s: out of memory"), myname); 2098 goto error; 2099 } 2100 if (scf_pg_get_property(instpg, propname, prop) != 0) { 2101 /* New property? */ 2102 if (scf_error() == SCF_ERROR_NOT_FOUND) 2103 new = B_TRUE; 2104 else 2105 goto error; 2106 } 2107 if ((tx = scf_transaction_create(h)) == NULL || 2108 (ent = scf_entry_create(h)) == NULL) 2109 goto error; 2110 retry: 2111 if (scf_transaction_start(tx, instpg) == -1) 2112 goto error; 2113 if (new) { 2114 if (scf_transaction_property_new(tx, ent, propname, 2115 newproptype) == -1) 2116 goto error; 2117 } else if (scf_transaction_property_change(tx, ent, propname, 2118 newproptype) == -1) 2119 goto error; 2120 for (i = 0; i < numpropvals; i++) { 2121 if ((values[i] = scf_value_create(h)) == NULL || 2122 scf_value_set_from_string(values[i], newproptype, 2123 propvals[i] == NULL ? "": propvals[i]) == -1 || 2124 scf_entry_add_value(ent, values[i]) != 0) 2125 goto error; 2126 } 2127 retval = scf_transaction_commit(tx); 2128 if (retval == 0) { 2129 scf_transaction_reset(tx); 2130 if (scf_pg_update(instpg) == -1) 2131 goto error; 2132 goto retry; 2133 } 2134 if (retval == -1) 2135 goto error; 2136 goto out; 2137 error: 2138 switch (scf_error()) { 2139 case SCF_ERROR_INVALID_ARGUMENT: 2140 (void) fprintf(stderr, gettext( 2141 "%s: invalid value for property %s/%s\n"), myname, 2142 pgname, propname); 2143 break; 2144 case SCF_ERROR_NOT_FOUND: 2145 (void) fprintf(stderr, gettext( 2146 "%s: no such property %s/%s\n"), myname, 2147 pgname, propname); 2148 break; 2149 default: 2150 (void) fprintf(stderr, gettext( 2151 "%s: unexpected libscf error: %s\n"), myname, 2152 scf_strerror(scf_error())); 2153 break; 2154 } 2155 ret = -1; 2156 out: 2157 if (tx != NULL) 2158 scf_transaction_destroy(tx); 2159 if (ent != NULL) 2160 scf_entry_destroy(ent); 2161 if (values != NULL) { 2162 for (i = 0; i < numpropvals; i++) { 2163 if (values[i] != NULL) 2164 scf_value_destroy(values[i]); 2165 } 2166 free(values); 2167 } 2168 if (prop != NULL) 2169 scf_property_destroy(prop); 2170 if (cpg != NULL) 2171 scf_pg_destroy(cpg); 2172 if (instpg != NULL) 2173 scf_pg_destroy(instpg); 2174 if (pgtype != NULL) 2175 free(pgtype); 2176 return (ret); 2177 } 2178 2179 /* 2180 * This function gathers configuration from the legacy /etc/inet/routing.conf, 2181 * if any, and sets the appropriate variable values accordingly. Once 2182 * these are set, the legacy daemons are checked to see if they have 2183 * SMF counterparts (ra_check_legacy_daemons()). If they do, the 2184 * configuration is upgraded. Finally, the legacy option settings are 2185 * applied, enabling/disabling the routing/forwarding services as 2186 * appropriate. 2187 */ 2188 static int 2189 ra_upgrade_from_legacy_conf(void) 2190 { 2191 scf_handle_t *h = NULL; 2192 scf_instance_t *inst = NULL; 2193 int ret = 0, i, r; 2194 boolean_t old_conf_read; 2195 ravar_t *routing_svcs = ra_str2var(RA_VAR_ROUTING_SVCS); 2196 2197 /* 2198 * First, determine if we have already upgraded - if "routing-conf-read" 2199 * is true, we bail. The use of a boolean property indicating if 2200 * routing.conf has been read and applied might seem a lot more 2201 * work than simply copying routing.conf aside, but leaving the 2202 * file in place allows users to downgrade and have their old 2203 * routing configuration still in place. 2204 */ 2205 if ((h = scf_handle_create(SCF_VERSION)) == NULL || 2206 scf_handle_bind(h) == -1) { 2207 (void) fprintf(stderr, gettext( 2208 "%s: cannot connect to SMF repository\n"), myname); 2209 ret = -1; 2210 goto out; 2211 } 2212 if ((inst = scf_instance_create(h)) == NULL || 2213 scf_handle_decode_fmri(h, RA_INSTANCE_ROUTING_SETUP, 2214 NULL, NULL, inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) { 2215 (void) fprintf(stderr, gettext( 2216 "%s: unexpected libscf error: %s\n"), myname, 2217 scf_strerror(scf_error())); 2218 ret = -1; 2219 goto out; 2220 } 2221 if (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM, 2222 RA_PROP_ROUTING_CONF_READ, B_TRUE, B_TRUE, &old_conf_read) == -1) { 2223 ret = -1; 2224 goto out; 2225 } 2226 2227 if (old_conf_read) 2228 goto out; 2229 2230 /* 2231 * Now set "routing-conf-read" to true so we don`t reimport legacy 2232 * configuration again. 2233 */ 2234 if (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM, 2235 RA_PROP_ROUTING_CONF_READ, B_FALSE, B_TRUE) == -1) 2236 return (-1); 2237 (void) smf_refresh_instance(RA_INSTANCE_ROUTING_SETUP); 2238 2239 ra_resetvars(NULL); 2240 2241 /* First, gather values from routing.conf */ 2242 if ((r = ra_parseconf()) == -1) { 2243 ret = -1; 2244 goto out; 2245 } 2246 /* No routing.conf file found */ 2247 if (r == 0) 2248 goto out; 2249 /* 2250 * Now, set the options/variables gathered. We set variables first, 2251 * as we cannot enable routing before we determine the daemons 2252 * to enable. 2253 */ 2254 2255 for (i = 0; ra_vars[i].var_name != NULL; i++) { 2256 /* Skip routing-svcs var, not featured in legacy config */ 2257 if (strcmp(ra_vars[i].var_name, RA_VAR_ROUTING_SVCS) == 0) 2258 continue; 2259 if (ra_smf_cb(ra_set_persistent_var_cb, ra_vars[i].var_fmri, 2260 &(ra_vars[i])) == -1) { 2261 ret = -1; 2262 goto out; 2263 } 2264 } 2265 /* Clear routing-svcs value */ 2266 if (ra_smf_cb(ra_set_persistent_var_cb, routing_svcs->var_fmri, 2267 routing_svcs) == -1) { 2268 ret = -1; 2269 goto out; 2270 } 2271 2272 if (ra_check_legacy_daemons() == -1) { 2273 ret = -1; 2274 goto out; 2275 } 2276 2277 for (i = 0; ra_opts[i].opt_name != NULL; i++) { 2278 if (ra_smf_cb(ra_set_persistent_opt_cb, ra_opts[i].opt_fmri, 2279 &(ra_opts[i])) == -1 || 2280 ra_smf_cb(ra_set_default_opt_cb, 2281 ra_opts[i].opt_default_fmri, &(ra_opts[i])) == -1) { 2282 ret = -1; 2283 break; 2284 } 2285 } 2286 out: 2287 if (inst != NULL) 2288 scf_instance_destroy(inst); 2289 if (h != NULL) 2290 scf_handle_destroy(h); 2291 2292 return (ret); 2293 } 2294 2295 /* 2296 * 2297 * Return the number of IPv6 addresses configured. This answers the 2298 * generic question, "is IPv6 configured?". We only start in.ndpd if IPv6 2299 * is configured, and we also only enable IPv6 routing daemons if IPv6 is 2300 * enabled. 2301 */ 2302 static int 2303 ra_numv6intfs(void) 2304 { 2305 static int num = -1; 2306 int ipsock; 2307 struct lifnum lifn; 2308 2309 if (num != -1) 2310 return (num); 2311 2312 if ((ipsock = socket(PF_INET6, SOCK_DGRAM, 0)) == -1) { 2313 (void) fprintf(stderr, 2314 gettext("%1$s: unable to open %2$s: %3$s\n"), 2315 myname, IP_DEV_NAME, strerror(errno)); 2316 return (0); 2317 } 2318 lifn.lifn_family = AF_INET6; 2319 lifn.lifn_flags = 0; 2320 2321 if (ioctl(ipsock, SIOCGLIFNUM, &lifn) == -1) { 2322 (void) close(ipsock); 2323 return (0); 2324 } 2325 (void) close(ipsock); 2326 2327 return (num = lifn.lifn_count); 2328 } 2329 2330 /* 2331 * Parse the configuration file and fill the ra_opts array with opt_value 2332 * and opt_default_value values, and the ra_vars array with var_value and 2333 * var_default_value values. Then copy aside routing.conf so it will not 2334 * be read by future invokations of routeadm. 2335 */ 2336 static int 2337 ra_parseconf(void) 2338 { 2339 FILE *fp; 2340 uint_t lineno; 2341 char line[RA_MAX_CONF_LINE]; 2342 char *cp, *confstr; 2343 raopt_t *raopt; 2344 ravar_t *ravar; 2345 2346 if ((fp = fopen(RA_CONF_FILE, "r")) == NULL) { 2347 /* 2348 * There's no config file, so we simply return as there 2349 * is no work to do. 2350 */ 2351 return (0); 2352 } 2353 2354 for (lineno = 1; fgets(line, sizeof (line), fp) != NULL; lineno++) { 2355 if (line[strlen(line) - 1] == '\n') 2356 line[strlen(line) - 1] = '\0'; 2357 2358 cp = line; 2359 2360 /* Skip leading whitespace */ 2361 while (isspace(*cp)) 2362 cp++; 2363 2364 /* Skip comment lines and empty lines */ 2365 if (*cp == '#' || *cp == '\0') 2366 continue; 2367 2368 /* 2369 * Anything else must be of the form: 2370 * <option> <value> <default_value> 2371 */ 2372 if ((confstr = strtok(cp, " ")) == NULL) { 2373 (void) fprintf(stderr, 2374 gettext("%1$s: %2$s: invalid entry on line %3$d\n"), 2375 myname, RA_CONF_FILE, lineno); 2376 continue; 2377 } 2378 2379 if ((raopt = ra_str2opt(confstr)) != NULL) { 2380 if (ra_parseopt(confstr, lineno, raopt) != 0) { 2381 (void) fclose(fp); 2382 return (-1); 2383 } 2384 } else if ((ravar = ra_str2var(confstr)) != NULL) { 2385 if (ra_parsevar(confstr, ravar) != 0) { 2386 (void) fclose(fp); 2387 return (-1); 2388 } 2389 } else { 2390 (void) fprintf(stderr, 2391 gettext("%1$s: %2$s: invalid option name on " 2392 "line %3$d\n"), 2393 myname, RA_CONF_FILE, lineno); 2394 continue; 2395 } 2396 } 2397 2398 (void) fclose(fp); 2399 2400 return (1); 2401 } 2402 2403 static int 2404 ra_parseopt(char *confstr, int lineno, raopt_t *raopt) 2405 { 2406 oval_t oval, d_oval; 2407 2408 if ((confstr = strtok(NULL, " ")) == NULL) { 2409 (void) fprintf(stderr, 2410 gettext("%1$s: %2$s: missing value on line %3$d\n"), 2411 myname, RA_CONF_FILE, lineno); 2412 return (0); 2413 } 2414 if ((oval = ra_str2oval(confstr)) == OPT_INVALID) { 2415 (void) fprintf(stderr, 2416 gettext("%1$s: %2$s: invalid option " 2417 "value on line %3$d\n"), 2418 myname, RA_CONF_FILE, lineno); 2419 return (0); 2420 } 2421 if (oval != OPT_DEFAULT) 2422 raopt->opt_enabled = oval == OPT_ENABLED; 2423 2424 if ((confstr = strtok(NULL, " ")) == NULL) { 2425 (void) fprintf(stderr, 2426 gettext("%1$s: %2$s: missing revert " 2427 "value on line %3$d\n"), 2428 myname, RA_CONF_FILE, lineno); 2429 return (0); 2430 } 2431 if ((d_oval = ra_str2oval(confstr)) == OPT_INVALID) { 2432 (void) fprintf(stderr, 2433 gettext("%1$s: %2$s: invalid revert " 2434 "value on line %3$d\n"), 2435 myname, RA_CONF_FILE, lineno, confstr); 2436 return (0); 2437 } 2438 raopt->opt_default_enabled = d_oval == OPT_ENABLED; 2439 if (oval == OPT_DEFAULT) 2440 raopt->opt_enabled = d_oval == OPT_ENABLED; 2441 return (0); 2442 } 2443 2444 static int 2445 ra_parsevar(char *confstr, ravar_t *ravar) 2446 { 2447 confstr = strtok(NULL, "="); 2448 if (confstr == NULL) { 2449 /* 2450 * This isn't an error condition, it simply means that the 2451 * variable has no value. 2452 */ 2453 ravar->var_value = NULL; 2454 return (0); 2455 } 2456 2457 if ((ravar->var_value = strdup(confstr)) == NULL) { 2458 (void) fprintf(stderr, gettext("%s: " 2459 "unable to allocate memory\n"), myname); 2460 return (-1); 2461 } 2462 return (0); 2463 } 2464 2465 /* Convert a string to an option value. */ 2466 static oval_t 2467 ra_str2oval(const char *valstr) 2468 { 2469 if (strcmp(valstr, "enabled") == 0) 2470 return (OPT_ENABLED); 2471 else if (strcmp(valstr, "disabled") == 0) 2472 return (OPT_DISABLED); 2473 else if (strcmp(valstr, "default") == 0) 2474 return (OPT_DEFAULT); 2475 return (OPT_INVALID); 2476 } 2477 2478 static raopt_t * 2479 ra_str2opt(const char *optnamestr) 2480 { 2481 int i; 2482 2483 for (i = 0; ra_opts[i].opt_name != NULL; i++) { 2484 if (strcmp(optnamestr, ra_opts[i].opt_name) == 0) 2485 break; 2486 } 2487 if (ra_opts[i].opt_name == NULL) 2488 return (NULL); 2489 return (&ra_opts[i]); 2490 } 2491 2492 /* 2493 * Reset all option values previously gathered to B_FALSE. 2494 */ 2495 static void 2496 ra_resetopts(void) 2497 { 2498 int i; 2499 2500 for (i = 0; ra_opts[i].opt_name != NULL; i++) { 2501 ra_opts[i].opt_enabled = B_FALSE; 2502 ra_opts[i].opt_default_enabled = B_FALSE; 2503 } 2504 } 2505 2506 static ravar_t * 2507 ra_str2var(const char *varnamestr) 2508 { 2509 int i; 2510 for (i = 0; ra_vars[i].var_name != NULL; i++) { 2511 if (strcmp(varnamestr, ra_vars[i].var_name) == 0) 2512 break; 2513 } 2514 if (ra_vars[i].var_name == NULL) 2515 return (NULL); 2516 return (&ra_vars[i]); 2517 } 2518 2519 /* 2520 * Reset variable values previously gathered to NULL. 2521 */ 2522 static void 2523 ra_resetvars(const char *proto) 2524 { 2525 int i; 2526 for (i = 0; ra_vars[i].var_name != NULL; i++) { 2527 if (proto != NULL && 2528 !VAR_PROTO_MATCH(ra_vars[i].var_name, proto)) 2529 continue; 2530 if (ra_vars[i].var_value != NULL) 2531 free(ra_vars[i].var_value); 2532 ra_vars[i].var_value = NULL; 2533 if (ra_vars[i].var_default_value != NULL) 2534 free(ra_vars[i].var_default_value); 2535 ra_vars[i].var_default_value = NULL; 2536 } 2537 } 2538 2539 /* 2540 * Given an option name, this function provides an internationalized, human 2541 * readable version of the option name. 2542 */ 2543 static char * 2544 ra_intloptname(const char *optname) 2545 { 2546 if (strcmp(optname, RA_OPT_IPV4_FORWARDING) == 0) 2547 return (gettext("IPv4 forwarding")); 2548 else if (strcmp(optname, RA_OPT_IPV4_ROUTING) == 0) 2549 return (gettext("IPv4 routing")); 2550 else if (strcmp(optname, RA_OPT_IPV6_FORWARDING) == 0) 2551 return (gettext("IPv6 forwarding")); 2552 else if (strcmp(optname, RA_OPT_IPV6_ROUTING) == 0) 2553 return (gettext("IPv6 routing")); 2554 else if (strcmp(optname, RA_VAR_IPV4_ROUTING_DAEMON) == 0) 2555 return (gettext("IPv4 routing daemon")); 2556 else if (strcmp(optname, RA_VAR_IPV4_ROUTING_DAEMON_ARGS) == 0) 2557 return (gettext("IPv4 routing daemon args")); 2558 else if (strcmp(optname, RA_VAR_IPV4_ROUTING_STOP_CMD) == 0) 2559 return (gettext("IPv4 routing daemon stop")); 2560 else if (strcmp(optname, RA_VAR_IPV6_ROUTING_DAEMON) == 0) 2561 return (gettext("IPv6 routing daemon")); 2562 else if (strcmp(optname, RA_VAR_IPV6_ROUTING_DAEMON_ARGS) == 0) 2563 return (gettext("IPv6 routing daemon args")); 2564 else if (strcmp(optname, RA_VAR_IPV6_ROUTING_STOP_CMD) == 0) 2565 return (gettext("IPv6 routing daemon stop")); 2566 else if (strcmp(optname, RA_VAR_ROUTING_SVCS) == 0) 2567 return (gettext("Routing services")); 2568 /* 2569 * If we get here, there's a bug and someone should trip over this 2570 * NULL pointer. 2571 */ 2572 return (NULL); 2573 } 2574