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