#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <ctype.h>
#include <stropts.h>
#include <errno.h>
#include <libintl.h>
#include <locale.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <inet/ip.h>
#include <inet/nd.h>
#include <net/if.h>
#include <libscf.h>
#include <libscf_priv.h>
#include <libuutil.h>
#define RA_OPT_IPV4_ROUTING "ipv4-routing"
#define RA_OPT_IPV6_ROUTING "ipv6-routing"
#define RA_OPT_IPV4_FORWARDING "ipv4-forwarding"
#define RA_OPT_IPV6_FORWARDING "ipv6-forwarding"
#define IS_ROUTING_OPT(opt) (strcmp(opt, RA_OPT_IPV4_ROUTING) == 0 || \
strcmp(opt, RA_OPT_IPV6_ROUTING) == 0)
#define RA_VAR_IPV4_ROUTING_DAEMON "ipv4-routing-daemon"
#define RA_VAR_IPV4_ROUTING_DAEMON_ARGS "ipv4-routing-daemon-args"
#define RA_VAR_IPV4_ROUTING_STOP_CMD "ipv4-routing-stop-cmd"
#define RA_VAR_IPV6_ROUTING_DAEMON "ipv6-routing-daemon"
#define RA_VAR_IPV6_ROUTING_DAEMON_ARGS "ipv6-routing-daemon-args"
#define RA_VAR_IPV6_ROUTING_STOP_CMD "ipv6-routing-stop-cmd"
#define RA_VAR_ROUTING_SVCS "routing-svcs"
#define RA_INSTANCE_ALL NULL
#define RA_INSTANCE_ROUTING_SETUP "svc:/network/routing-setup:default"
#define RA_INSTANCE_IPV4_FORWARDING "svc:/network/ipv4-forwarding:default"
#define RA_INSTANCE_IPV6_FORWARDING "svc:/network/ipv6-forwarding:default"
#define RA_INSTANCE_LEGACY_ROUTING_IPV4 \
"svc:/network/routing/legacy-routing:ipv4"
#define RA_INSTANCE_LEGACY_ROUTING_IPV6 \
"svc:/network/routing/legacy-routing:ipv6"
#define RA_INSTANCE_NDP "svc:/network/routing/ndp:default"
#define RA_PG_ROUTEADM "routeadm"
#define RA_PROP_CURR_ROUTING_SVC "current-routing-svc"
#define RA_PROP_ROUTING_SVCS "routing-svcs"
#define RA_PROP_DEFAULT_ROUTING_SVCS "default-routing-svcs"
#define RA_PROP_PROTO "protocol"
#define RA_PROP_DAEMON "daemon"
#define RA_PROP_DEFAULT_DAEMON "default-daemon"
#define RA_PROP_DAEMON_ARGS "daemon-args"
#define RA_PROP_DEFAULT_DAEMON_ARGS "default-daemon-args"
#define RA_PROP_DAEMON_STOP_CMD "daemon-stop-cmd"
#define RA_PROP_DEFAULT_STOP_CMD "default-daemon"
#define RA_PROP_LEGACY_DAEMON "legacy-daemon"
#define RA_PROP_DEFAULT_IPV4_ROUTING "default-ipv4-routing"
#define RA_PROP_DEFAULT_IPV6_ROUTING "default-ipv6-routing"
#define RA_PROP_DEFAULT_IPV4_FORWARDING "default-ipv4-forwarding"
#define RA_PROP_DEFAULT_IPV6_FORWARDING "default-ipv6-forwarding"
#define RA_PROP_IPV4_ROUTING_SET "ipv4-routing-set"
#define RA_PROP_IPV6_ROUTING_SET "ipv6-routing-set"
#define RA_PROP_ROUTING_CONF_READ "routing-conf-read"
#define RA_PG_ROUTING "routing"
#define RA_PROPVAL_BOOLEAN_TRUE "true"
#define RA_PROPVAL_BOOLEAN_FALSE "false"
#define RA_PROPVAL_PROTO_IPV4 "ipv4"
#define RA_PROPVAL_PROTO_IPV6 "ipv6"
#define RA_SVC_FLAG_NONE 0x0
#define RA_SVC_FLAG_IPV4_ROUTING 0x1
#define RA_SVC_FLAG_IPV6_ROUTING 0x2
#define RA_SMF_UPGRADE_FILE "/var/svc/profile/upgrade"
#define RA_SMF_UPGRADE_MSG " # added by routeadm(8)"
#define RA_CONF_FILE "/etc/inet/routing.conf"
#define RA_CONF_FILE_OLD "/etc/inet/routing.conf.old"
#define RA_MAX_CONF_LINE 256
typedef struct raopt {
const char *opt_name;
const char *opt_fmri;
int opt_flags;
boolean_t opt_enabled;
const char *opt_default_fmri;
const char *opt_default_prop;
boolean_t opt_default_enabled;
} raopt_t;
raopt_t ra_opts[] = {
{ RA_OPT_IPV4_ROUTING, RA_INSTANCE_ALL, RA_SVC_FLAG_IPV4_ROUTING,
B_FALSE, RA_INSTANCE_ROUTING_SETUP, RA_PROP_DEFAULT_IPV4_ROUTING,
B_FALSE },
{ RA_OPT_IPV6_ROUTING, RA_INSTANCE_ALL, RA_SVC_FLAG_IPV6_ROUTING,
B_FALSE, RA_INSTANCE_ROUTING_SETUP, RA_PROP_DEFAULT_IPV6_ROUTING,
B_FALSE },
{ RA_OPT_IPV4_FORWARDING, RA_INSTANCE_IPV4_FORWARDING, RA_SVC_FLAG_NONE,
B_FALSE, RA_INSTANCE_IPV4_FORWARDING, RA_PROP_DEFAULT_IPV4_FORWARDING,
B_FALSE },
{ RA_OPT_IPV6_FORWARDING, RA_INSTANCE_IPV6_FORWARDING, RA_SVC_FLAG_NONE,
B_FALSE, RA_INSTANCE_IPV6_FORWARDING, RA_PROP_DEFAULT_IPV6_FORWARDING,
B_FALSE },
{ NULL, NULL, RA_SVC_FLAG_NONE, B_FALSE, NULL, NULL, B_FALSE }
};
typedef enum option_values {
OPT_INVALID, OPT_ENABLED, OPT_DISABLED, OPT_DEFAULT, OPT_UNKNOWN
} oval_t;
typedef struct ra_var {
const char *var_name;
const char *var_fmri;
const char *var_prop;
char *var_value;
const char *var_default_fmri;
const char *var_default_prop;
char *var_default_value;
} ravar_t;
ravar_t ra_vars[] = {
{ RA_VAR_IPV4_ROUTING_DAEMON, RA_INSTANCE_LEGACY_ROUTING_IPV4,
RA_PROP_DAEMON, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV4,
RA_PROP_DEFAULT_DAEMON, NULL},
{ RA_VAR_IPV4_ROUTING_DAEMON_ARGS, RA_INSTANCE_LEGACY_ROUTING_IPV4,
RA_PROP_DAEMON_ARGS, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV4,
RA_PROP_DEFAULT_DAEMON_ARGS, NULL },
{ RA_VAR_IPV4_ROUTING_STOP_CMD, RA_INSTANCE_LEGACY_ROUTING_IPV4,
RA_PROP_DAEMON_STOP_CMD, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV4,
RA_PROP_DEFAULT_STOP_CMD, NULL },
{ RA_VAR_IPV6_ROUTING_DAEMON, RA_INSTANCE_LEGACY_ROUTING_IPV6,
RA_PROP_DAEMON, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV6,
RA_PROP_DEFAULT_DAEMON, NULL },
{ RA_VAR_IPV6_ROUTING_DAEMON_ARGS, RA_INSTANCE_LEGACY_ROUTING_IPV6,
RA_PROP_DAEMON_ARGS, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV6,
RA_PROP_DEFAULT_DAEMON_ARGS, NULL },
{ RA_VAR_IPV6_ROUTING_STOP_CMD, RA_INSTANCE_LEGACY_ROUTING_IPV6,
RA_PROP_DAEMON_STOP_CMD, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV6,
RA_PROP_DEFAULT_STOP_CMD, NULL },
{ RA_VAR_ROUTING_SVCS, RA_INSTANCE_ROUTING_SETUP,
RA_PROP_ROUTING_SVCS, NULL, RA_INSTANCE_ROUTING_SETUP,
RA_PROP_DEFAULT_ROUTING_SVCS, NULL },
{ NULL, NULL, NULL, NULL, NULL, NULL, NULL }
};
char *v_opt[] = {
#define IPV4_ROUTING_DAEMON 0
RA_VAR_IPV4_ROUTING_DAEMON,
#define IPV4_ROUTING_DAEMON_ARGS 1
RA_VAR_IPV4_ROUTING_DAEMON_ARGS,
#define IPV4_ROUTING_STOP_CMD 2
RA_VAR_IPV4_ROUTING_STOP_CMD,
#define IPV6_ROUTING_DAEMON 3
RA_VAR_IPV6_ROUTING_DAEMON,
#define IPV6_ROUTING_DAEMON_ARGS 4
RA_VAR_IPV6_ROUTING_DAEMON_ARGS,
#define IPV6_ROUTING_STOP_CMD 5
RA_VAR_IPV6_ROUTING_STOP_CMD,
#define ROUTING_SVCS 6
RA_VAR_ROUTING_SVCS,
NULL
};
#define IS_IPV4_VAR(varname) (strncmp(varname, "ipv4", 4) == 0)
#define IS_IPV6_VAR(varname) (strncmp(varname, "ipv6", 4) == 0)
#define VAR_PROTO_MATCH(varname, proto) (strncmp(varname, proto, 4) == 0)
#define IPV4_VARS_UNSET \
(strtok(ra_vars[IPV4_ROUTING_DAEMON].var_value, " \t") == NULL && \
strtok(ra_vars[IPV4_ROUTING_DAEMON_ARGS].var_value, " \t") == NULL && \
strtok(ra_vars[IPV4_ROUTING_STOP_CMD].var_value, " \t") == NULL)
#define IPV6_VARS_UNSET \
(strtok(ra_vars[IPV6_ROUTING_DAEMON].var_value, " \t") == NULL && \
strtok(ra_vars[IPV6_ROUTING_DAEMON_ARGS].var_value, " \t") == NULL && \
strtok(ra_vars[IPV6_ROUTING_STOP_CMD].var_value, " \t") == NULL)
typedef struct ra_prop {
char *prop_name;
char **prop_values;
int prop_numvalues;
} ra_prop_t;
typedef int (*ra_smf_cb_t)(void *, scf_walkinfo_t *);
static const char *myname;
static void usage(void);
static int ra_check_legacy_daemons(void);
static int ra_upgrade_legacy_daemons(void);
static int ra_upgrade_cmd(char, int, char **);
static int ra_update(void);
static int ra_update_routing_svcs(char *);
static int ra_report(boolean_t, const char *);
static int ra_smf_cb(ra_smf_cb_t, const char *, void *);
static int ra_upgrade_from_legacy_conf(void);
static int ra_numv6intfs(void);
static int ra_parseconf(void);
static int ra_parseopt(char *, int, raopt_t *);
static int ra_parsevar(char *, ravar_t *);
static oval_t ra_str2oval(const char *);
static raopt_t *ra_str2opt(const char *);
static void ra_resetopts(void);
static ravar_t *ra_str2var(const char *);
static void ra_resetvars(const char *);
static char *ra_intloptname(const char *);
static int ra_upgrade_legacy_daemons_cb(void *, scf_walkinfo_t *);
static int ra_set_current_opt_cb(void *, scf_walkinfo_t *);
static int ra_set_persistent_opt_cb(void *, scf_walkinfo_t *);
static int ra_set_default_opt_cb(void *, scf_walkinfo_t *);
static int ra_get_current_opt_cb(void *, scf_walkinfo_t *);
static int ra_get_persistent_opt_cb(void *, scf_walkinfo_t *);
static int ra_get_default_opt_cb(void *, scf_walkinfo_t *);
static int ra_get_set_opt_common_cb(raopt_t *, scf_walkinfo_t *, boolean_t,
boolean_t);
static int ra_routing_opt_set_cb(void *, scf_walkinfo_t *);
static int ra_routing_opt_unset_cb(void *, scf_walkinfo_t *);
static int ra_routing_opt_set_unset_cb(raopt_t *, scf_walkinfo_t *, boolean_t);
static int ra_set_persistent_var_cb(void *, scf_walkinfo_t *);
static int ra_get_persistent_var_cb(void *, scf_walkinfo_t *);
static int ra_get_default_var_cb(void *, scf_walkinfo_t *);
static int ra_mark_routing_svcs_cb(void *, scf_walkinfo_t *);
static int ra_list_props_cb(void *, scf_walkinfo_t *);
static int ra_modify_props_cb(void *, scf_walkinfo_t *);
static int ra_print_state_cb(void *, scf_walkinfo_t *);
static int ra_get_pg(scf_handle_t *, scf_instance_t *, const char *,
boolean_t, boolean_t, scf_propertygroup_t **);
static int ra_get_boolean_prop(scf_handle_t *, scf_instance_t *,
const char *, const char *, boolean_t, boolean_t, boolean_t *);
static int ra_get_single_prop_as_string(scf_handle_t *, scf_instance_t *,
const char *, const char *, boolean_t, boolean_t, scf_type_t *, char **);
static int ra_get_prop_as_string(scf_handle_t *, scf_instance_t *,
const char *, const char *, boolean_t, boolean_t, scf_type_t *, int *,
char ***);
static void ra_free_prop_values(int, char **);
static int ra_set_boolean_prop(scf_handle_t *, scf_instance_t *,
const char *, const char *, boolean_t, boolean_t);
static int ra_set_prop_from_string(scf_handle_t *, scf_instance_t *,
const char *, const char *, scf_type_t, boolean_t, int,
const char **);
static void
usage(void)
{
(void) fprintf(stderr, gettext(
"usage: %1$s [-p] [-R <root-dir>]\n"
" %1$s [-e <option>] [-d <option>] [-r <option>]\n"
" [-l <FMRI>] [-m <FMRI> key=value [...]]\n"
" [-s <var>=<val>] [-R <root-dir>]\n"
" %1$s -u\n\n"
" <option> is one of:\n"
" ipv4-forwarding\n"
" ipv4-routing\n"
" ipv6-forwarding\n"
" ipv6-routing\n\n"
" <var> is one of:\n"
" ipv4-routing-daemon\n"
" ipv4-routing-daemon-args\n"
" ipv4-routing-stop-cmd\n"
" ipv6-routing-daemon\n"
" ipv6-routing-daemon-args\n"
" ipv6-routing-stop-cmd\n"
" routing-svcs\n"), myname);
}
int
main(int argc, char *argv[])
{
int opt, opt_index, numargs, status = 0;
int numvalues, i;
ssize_t keylen;
boolean_t modify = B_FALSE, report = B_TRUE, update = B_FALSE;
boolean_t booting = B_FALSE, alt_root_set = B_FALSE;
boolean_t parseable = B_FALSE;
char *key, *nk, *keyend, *val, **vals, *options, *fmri;
char *parseopt = NULL;
raopt_t *raopt;
ravar_t *ravar;
ra_prop_t raprop;
myname = argv[0];
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
if (ra_upgrade_from_legacy_conf() == -1)
exit(EXIT_FAILURE);
while ((opt = getopt(argc, argv, ":bd:e:l:m:p:R:r:s:u")) != EOF) {
switch (opt) {
case 'b':
booting = B_TRUE;
break;
case 'd':
case 'e':
case 'r':
if (alt_root_set) {
if (ra_upgrade_cmd(opt, 1, &optarg) != 0)
exit(EXIT_FAILURE);
modify = B_TRUE;
break;
}
if ((raopt = ra_str2opt(optarg)) != NULL) {
switch (opt) {
case 'd':
raopt->opt_enabled = B_FALSE;
break;
case 'e':
if (IS_ROUTING_OPT(optarg) &&
ra_check_legacy_daemons() == -1)
exit(EXIT_FAILURE);
raopt->opt_enabled = B_TRUE;
break;
case 'r':
ra_resetopts();
if (ra_smf_cb(ra_get_default_opt_cb,
raopt->opt_default_fmri, raopt)
== -1)
exit(EXIT_FAILURE);
if (raopt->opt_enabled &&
IS_ROUTING_OPT(optarg) &&
ra_check_legacy_daemons() == -1)
exit(EXIT_FAILURE);
raopt->opt_enabled =
raopt->opt_default_enabled;
break;
}
if (ra_smf_cb(ra_set_persistent_opt_cb,
raopt->opt_fmri, raopt) == -1)
exit(EXIT_FAILURE);
if (!booting && (raopt->opt_flags &
(RA_SVC_FLAG_IPV4_ROUTING |
RA_SVC_FLAG_IPV6_ROUTING))) {
if (ra_smf_cb(opt == 'r' ?
ra_routing_opt_unset_cb :
ra_routing_opt_set_cb,
raopt->opt_default_fmri, raopt)
== -1)
exit(EXIT_FAILURE);
}
} else if ((ravar = ra_str2var(optarg)) != NULL) {
if (opt != 'r') {
usage();
exit(EXIT_FAILURE);
}
ra_resetopts();
if (ra_smf_cb(ra_get_default_var_cb,
ravar->var_default_fmri, ravar) == -1)
exit(EXIT_FAILURE);
if (strcmp(ravar->var_name, RA_VAR_ROUTING_SVCS)
== 0) {
if (ra_update_routing_svcs(
ravar->var_default_value) == -1)
exit(EXIT_FAILURE);
} else if (ra_smf_cb(ra_set_persistent_var_cb,
ravar->var_fmri, ravar) == -1)
exit(EXIT_FAILURE);
} else {
(void) fprintf(stderr, gettext(
"%1$s: invalid option: %2$s\n"), myname,
optarg);
usage();
exit(EXIT_FAILURE);
}
modify = B_TRUE;
break;
case 'l':
if (ra_smf_cb(ra_list_props_cb, optarg, NULL) == -1)
exit(EXIT_FAILURE);
report = B_FALSE;
break;
case 'm':
fmri = optarg;
modify = B_TRUE;
numargs = 1;
i = optind;
for (numargs = 1; argv[i] != NULL && argv[i][0] != '-';
numargs++)
i++;
if (numargs == 1) {
(void) fprintf(stderr, gettext(
"%s: key=value required for "
"property change\n"), myname);
usage();
exit(EXIT_FAILURE);
}
if (alt_root_set) {
if (ra_upgrade_cmd(opt, numargs,
&argv[optind - 1]) == -1)
exit(EXIT_FAILURE);
optind += numargs - 1;
break;
}
for (key = argv[optind]; key != NULL && key[0] != '-';
key = argv[++optind]) {
if (key[0] == '\0')
continue;
vals = malloc(sizeof (char *));
if ((vals[0] = strchr(key, '=')) == NULL) {
(void) fprintf(stderr, gettext(
"%s: Malformed name=value "
"pair %s\n"), myname, key);
exit(EXIT_FAILURE);
}
numvalues = 1;
*(vals[0]) = '\0';
(vals[0])++;
i = optind + 1;
for (nk = argv[i];
nk != NULL && nk[0] != '-';
nk = argv[++i]) {
if (nk[0] == '\0')
continue;
if ((keyend = strchr(nk, '='))
== NULL) {
(void) fprintf(stderr, gettext(
"%s: Malformed name=value "
" pair %s\n"), myname, nk);
exit(EXIT_FAILURE);
}
if ((keylen = keyend - nk) !=
strlen(key))
continue;
if (strncmp(key, nk, keylen) == 0) {
vals = realloc(vals, ++numvalues
* sizeof (char *));
vals[numvalues - 1] = ++keyend;
nk[0] = '\0';
optind++;
}
}
raprop.prop_name = key;
raprop.prop_values = vals;
raprop.prop_numvalues = numvalues;
if (ra_smf_cb(ra_modify_props_cb, fmri,
&raprop) == -1)
exit(EXIT_FAILURE);
}
break;
case 'p':
parseable = B_TRUE;
parseopt = optarg;
break;
case 'R':
if (chroot(optarg) == -1) {
(void) fprintf(stderr, gettext(
"%1$s: failed to chroot to %2$s: %3$s\n"),
myname, optarg, strerror(errno));
exit(EXIT_FAILURE);
}
alt_root_set = B_TRUE;
report = B_FALSE;
break;
case 's':
if (alt_root_set) {
if (ra_upgrade_cmd(opt, 1, &optarg) == -1)
exit(EXIT_FAILURE);
modify = B_TRUE;
break;
}
options = optarg;
while (*options != '\0') {
opt_index = getsubopt(&options, v_opt, &val);
if (val == NULL) {
usage();
exit(EXIT_FAILURE);
}
if (opt_index == -1) {
(void) fprintf(stderr, gettext(
"%1$s: invalid variable: %2$s\n"),
myname, optarg);
usage();
exit(EXIT_FAILURE);
}
ravar = &ra_vars[opt_index];
if (strcmp(ravar->var_name, RA_VAR_ROUTING_SVCS)
== 0) {
if (ra_update_routing_svcs(val) == -1)
return (-1);
} else {
ravar->var_value = strdup(val);
if (ra_smf_cb(ra_set_persistent_var_cb,
ravar->var_fmri, ravar) == -1)
exit(EXIT_FAILURE);
}
}
modify = B_TRUE;
break;
case 'u':
update = B_TRUE;
break;
case ':':
if (strcmp(argv[optind - 1], "-p") != 0) {
(void) fprintf(stderr, gettext(
"%s: option requires an argument -%s\n"),
myname, argv[optind - 1]);
usage();
exit(EXIT_FAILURE);
}
parseable = B_TRUE;
break;
case '?':
usage();
exit(EXIT_FAILURE);
}
}
if (argc > optind) {
usage();
exit(EXIT_FAILURE);
}
if (parseable && (update || modify)) {
(void) fprintf(stderr, gettext("%s: the -p option cannot be "
"used with any of -demrsu\n"), myname);
usage();
exit(EXIT_FAILURE);
}
if (update && ! alt_root_set)
status = ra_update();
if (report && !modify && !update)
status = ra_report(parseable, parseopt);
return (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
static int
ra_check_legacy_daemons(void)
{
ravar_t *routing_svcs = ra_str2var(RA_VAR_ROUTING_SVCS);
ravar_t *v4d = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON);
ravar_t *v6d = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON);
char *fmri, *nextfmri;
boolean_t mark = B_FALSE;
if (ra_smf_cb(ra_get_persistent_var_cb, routing_svcs->var_fmri,
routing_svcs) == -1)
return (-1);
if (ra_smf_cb(ra_mark_routing_svcs_cb, NULL, &mark) == -1)
return (-1);
mark = B_TRUE;
if (routing_svcs->var_value != NULL) {
if ((fmri = strdup(routing_svcs->var_value)) == NULL) {
(void) fprintf(stderr, gettext(
"%s: out of memory\n"), myname);
return (-1);
}
for (nextfmri = strtok(fmri, " \t");
nextfmri != NULL;
nextfmri = strtok(NULL, " \t")) {
if (ra_smf_cb(ra_mark_routing_svcs_cb, nextfmri,
&mark) == -1) {
free(fmri);
return (-1);
}
}
free(fmri);
}
if (ra_upgrade_legacy_daemons() == -1)
return (-1);
ra_resetvars(NULL);
if (ra_smf_cb(ra_get_persistent_var_cb, v4d->var_fmri, v4d) == -1 ||
ra_smf_cb(ra_get_persistent_var_cb, v6d->var_fmri, v6d) == -1)
return (-1);
if (v4d->var_value != NULL && strtok(v4d->var_value, " \t") != NULL &&
ra_smf_cb(ra_mark_routing_svcs_cb, RA_INSTANCE_LEGACY_ROUTING_IPV4,
&mark) == -1)
return (-1);
if (v6d->var_value != NULL && strtok(v6d->var_value, " \t") != NULL &&
ra_smf_cb(ra_mark_routing_svcs_cb, RA_INSTANCE_LEGACY_ROUTING_IPV6,
&mark) == -1)
return (-1);
return (0);
}
static int
ra_upgrade_legacy_daemons(void)
{
ravar_t *v4d = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON);
ravar_t *v6d = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON);
ravar_t *v4args = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON_ARGS);
ravar_t *v6args = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON_ARGS);
ravar_t *v4stop = ra_str2var(RA_VAR_IPV4_ROUTING_STOP_CMD);
ravar_t *v6stop = ra_str2var(RA_VAR_IPV6_ROUTING_STOP_CMD);
if (ra_smf_cb(ra_get_persistent_var_cb, v4d->var_fmri, v4d) == -1 ||
ra_smf_cb(ra_get_persistent_var_cb, v6d->var_fmri, v6d) == -1 ||
ra_smf_cb(ra_get_persistent_var_cb, v4args->var_fmri, v4args)
== -1 ||
ra_smf_cb(ra_get_persistent_var_cb, v6args->var_fmri, v6args)
== -1 ||
ra_smf_cb(ra_get_persistent_var_cb, v4stop->var_fmri, v4stop)
== -1 ||
ra_smf_cb(ra_get_persistent_var_cb, v6stop->var_fmri, v6stop)
== -1)
return (-1);
return (ra_smf_cb(ra_upgrade_legacy_daemons_cb, NULL, NULL));
}
static int
ra_upgrade_legacy_daemons_cb(void *data, scf_walkinfo_t *wip)
{
const char *inst_fmri = wip->fmri;
scf_instance_t *inst = wip->inst;
scf_handle_t *h = scf_instance_handle(inst);
char *daemon, *l_daemon = NULL;
ravar_t *v4d = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON);
ravar_t *v6d = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON);
ravar_t *v4args = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON_ARGS);
ravar_t *v6args = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON_ARGS);
ravar_t *v4stop = ra_str2var(RA_VAR_IPV4_ROUTING_STOP_CMD);
ravar_t *v6stop = ra_str2var(RA_VAR_IPV6_ROUTING_STOP_CMD);
ravar_t *routing_svcs = ra_str2var(RA_VAR_ROUTING_SVCS);
boolean_t mark, marked;
char *new_routing_svcs;
if (ra_get_single_prop_as_string(h, inst, RA_PG_ROUTEADM,
RA_PROP_DAEMON, B_TRUE, B_FALSE, NULL, &daemon) == -1 ||
strcmp(RA_INSTANCE_LEGACY_ROUTING_IPV4, inst_fmri) == 0 ||
strcmp(RA_INSTANCE_LEGACY_ROUTING_IPV6, inst_fmri) == 0)
return (0);
(void) ra_get_single_prop_as_string(h, inst, RA_PG_ROUTEADM,
RA_PROP_LEGACY_DAEMON, B_TRUE, B_FALSE, NULL, &l_daemon);
if (v4d->var_value != NULL && (strcmp(v4d->var_value, daemon) == 0 ||
(l_daemon != NULL && strcmp(v4d->var_value, l_daemon) == 0))) {
(void) printf(gettext("%s: migrating daemon configuration "
"for %s to %s\n"), myname, l_daemon != NULL ?
l_daemon : daemon, inst_fmri);
if (ra_set_prop_from_string(h, inst, RA_PG_ROUTEADM,
RA_PROP_DAEMON_ARGS, SCF_TYPE_ASTRING, B_TRUE, 1,
(const char **)&(v4args->var_value)) == -1)
return (-1);
ra_resetvars(RA_PROPVAL_PROTO_IPV4);
if (ra_smf_cb(ra_set_persistent_var_cb,
RA_INSTANCE_LEGACY_ROUTING_IPV4, v4d) == -1 ||
ra_smf_cb(ra_set_persistent_var_cb,
RA_INSTANCE_LEGACY_ROUTING_IPV4, v4args) == -1 ||
ra_smf_cb(ra_set_persistent_var_cb,
RA_INSTANCE_LEGACY_ROUTING_IPV4, v4stop) == -1)
return (-1);
} else if (v6d->var_value != NULL && (strcmp(v6d->var_value, daemon)
== 0 ||
(l_daemon != NULL && strcmp(v6d->var_value, l_daemon) == 0))) {
(void) printf(gettext("%s: migrating daemon configuration "
"for %s to %s\n"), myname, l_daemon != NULL ?
l_daemon : daemon, inst_fmri);
if (ra_set_prop_from_string(h, inst, RA_PG_ROUTEADM,
RA_PROP_DAEMON_ARGS, SCF_TYPE_ASTRING, B_TRUE, 1,
(const char **)&(v6args->var_value)) == -1)
return (-1);
ra_resetvars(RA_PROPVAL_PROTO_IPV6);
if (ra_smf_cb(ra_set_persistent_var_cb,
RA_INSTANCE_LEGACY_ROUTING_IPV6, v6d) == -1 ||
ra_smf_cb(ra_set_persistent_var_cb,
RA_INSTANCE_LEGACY_ROUTING_IPV6, v6args) == -1 ||
ra_smf_cb(ra_set_persistent_var_cb,
RA_INSTANCE_LEGACY_ROUTING_IPV6, v6stop) == -1)
return (-1);
} else
return (0);
if (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
RA_PROP_CURR_ROUTING_SVC, B_FALSE, B_FALSE, &marked) == -1 ||
marked == B_FALSE) {
mark = B_TRUE;
if (ra_smf_cb(ra_mark_routing_svcs_cb, inst_fmri, &mark)
== -1 ||
ra_smf_cb(ra_get_persistent_var_cb, routing_svcs->var_fmri,
routing_svcs) == -1)
return (-1);
if ((new_routing_svcs =
malloc(strlen(routing_svcs->var_value) +
strlen(inst_fmri) + 2)) == NULL) {
(void) fprintf(stderr, gettext(
"%s: out of memory"), myname);
return (-1);
}
if (strlen(routing_svcs->var_value) == 0)
(void) snprintf(new_routing_svcs,
strlen(inst_fmri) + 1, "%s", inst_fmri);
else
(void) snprintf(new_routing_svcs,
strlen(routing_svcs->var_value) +
strlen(inst_fmri) + 2, "%s %s",
routing_svcs->var_value, inst_fmri);
free(routing_svcs->var_value);
routing_svcs->var_value = new_routing_svcs;
(void) smf_refresh_instance(inst_fmri);
return (ra_smf_cb(ra_set_persistent_var_cb,
routing_svcs->var_fmri, routing_svcs));
}
(void) smf_refresh_instance(inst_fmri);
return (0);
}
static int
ra_upgrade_cmd(char opt, int argc, char **argv)
{
FILE *fp;
int i;
if ((fp = fopen(RA_SMF_UPGRADE_FILE, "a+")) == NULL) {
(void) fprintf(stderr, gettext(
"%1$s: failed to open %2$s: %3$s\n"),
myname, RA_SMF_UPGRADE_FILE, strerror(errno));
return (-1);
}
(void) fprintf(fp, "/sbin/routeadm -%c ", opt);
if (argv != NULL) {
for (i = 0; i < argc; i++)
(void) fprintf(fp, "%s ", argv[i]);
}
(void) fprintf(fp, "%s\n", RA_SMF_UPGRADE_MSG);
(void) fclose(fp);
return (0);
}
static int
ra_update(void)
{
int i;
if (ra_check_legacy_daemons() == -1)
return (-1);
for (i = 0; ra_opts[i].opt_name != NULL; i++) {
if (ra_smf_cb(ra_set_current_opt_cb, ra_opts[i].opt_fmri,
&ra_opts[i]) == -1) {
return (-1);
}
}
if (ra_numv6intfs() > 0)
return (smf_enable_instance(RA_INSTANCE_NDP, SMF_TEMPORARY));
return (0);
}
static int
ra_update_routing_svcs(char *routing_svcs_new)
{
raopt_t *v4opt = ra_str2opt(RA_OPT_IPV4_ROUTING);
raopt_t *v6opt = ra_str2opt(RA_OPT_IPV6_ROUTING);
ravar_t *routing_svcs = ra_str2var(RA_VAR_ROUTING_SVCS);
char *routing_svcs_old, *fmri;
boolean_t v4_old, v6_old, mark = B_FALSE;
ra_resetopts();
if (ra_smf_cb(ra_get_persistent_opt_cb, v4opt->opt_fmri, v4opt) == -1 ||
ra_smf_cb(ra_get_persistent_opt_cb, v6opt->opt_fmri, v6opt) == -1 ||
ra_smf_cb(ra_get_persistent_var_cb, routing_svcs->var_fmri,
routing_svcs) == -1)
return (-1);
v4_old = v4opt->opt_enabled;
v6_old = v6opt->opt_enabled;
routing_svcs_old = routing_svcs->var_value;
routing_svcs->var_value = routing_svcs_new;
if (ra_smf_cb(ra_set_persistent_var_cb, routing_svcs->var_fmri,
routing_svcs) == -1) {
free(routing_svcs_old);
return (-1);
}
if (!v4_old && !v6_old) {
free(routing_svcs_old);
return (0);
}
v4opt->opt_enabled = B_FALSE;
v6opt->opt_enabled = B_FALSE;
for (fmri = strtok(routing_svcs_old, " \t"); fmri != NULL;
fmri = strtok(NULL, " \t")) {
if (ra_smf_cb(ra_mark_routing_svcs_cb, fmri, &mark) == -1) {
free(routing_svcs_old);
return (-1);
}
if (v4_old &&
ra_smf_cb(ra_set_persistent_opt_cb, fmri, v4opt) == -1) {
free(routing_svcs_old);
return (-1);
}
if (v6_old &&
ra_smf_cb(ra_set_persistent_opt_cb, fmri, v6opt) == -1) {
free(routing_svcs_old);
return (-1);
}
}
free(routing_svcs_old);
v4opt->opt_enabled = v4_old;
v6opt->opt_enabled = v6_old;
mark = B_TRUE;
for (fmri = strtok(routing_svcs_new, " \t"); fmri != NULL;
fmri = strtok(NULL, " \t")) {
if (ra_smf_cb(ra_mark_routing_svcs_cb, fmri, &mark) == -1)
return (-1);
if (v4_old &&
ra_smf_cb(ra_set_persistent_opt_cb, fmri, v4opt) == -1)
return (-1);
if (v6_old &&
ra_smf_cb(ra_set_persistent_opt_cb, fmri, v6opt) == -1)
return (-1);
}
return (0);
}
static int
ra_report(boolean_t parseable, const char *param)
{
int i;
char *c_state, *d_state, *p_state, *p_var, *d_var;
char *enabled = "enabled";
char *disabled = "disabled";
boolean_t param_found = B_FALSE;
if (!parseable) {
(void) printf(gettext(
" Configuration Current "
"Current\n"
" Option Configuration "
"System State\n"
"---------------------------------------------------"
"------------\n"));
}
for (i = 0; ra_opts[i].opt_name != NULL; i++) {
if (param != NULL) {
if (strcmp(ra_opts[i].opt_name, param) == 0)
param_found = B_TRUE;
else
continue;
}
if (ra_smf_cb(ra_get_current_opt_cb,
ra_opts[i].opt_fmri, &ra_opts[i]) == -1)
return (-1);
c_state = ra_opts[i].opt_enabled ? enabled : disabled;
ra_resetopts();
if (ra_smf_cb(ra_get_persistent_opt_cb,
ra_opts[i].opt_fmri, &ra_opts[i]) == -1)
return (-1);
p_state = ra_opts[i].opt_enabled ? enabled : disabled;
ra_resetopts();
if (ra_smf_cb(ra_get_default_opt_cb,
ra_opts[i].opt_default_fmri, &ra_opts[i]) == -1)
return (-1);
d_state = ra_opts[i].opt_default_enabled ? enabled : disabled;
ra_resetopts();
if (parseable) {
if (param == NULL)
(void) printf("%s ", ra_opts[i].opt_name);
(void) printf("persistent=%s default=%s "
"current=%s\n", p_state, d_state, c_state);
} else {
(void) printf(gettext("%1$27s %2$-21s%3$s\n"),
ra_intloptname(ra_opts[i].opt_name),
p_state, c_state);
}
}
if (!parseable)
(void) printf("\n");
ra_resetvars(NULL);
for (i = 0; ra_vars[i].var_name != NULL; i++) {
if (ra_smf_cb(ra_get_persistent_var_cb,
ra_vars[i].var_fmri, &ra_vars[i]) == -1 ||
ra_smf_cb(ra_get_default_var_cb,
ra_vars[i].var_default_fmri, &ra_vars[i]) == -1)
return (-1);
}
for (i = 0; ra_vars[i].var_name != NULL; i++) {
if (param != NULL) {
if (strcmp(ra_vars[i].var_name, param) == 0)
param_found = B_TRUE;
else
continue;
}
p_var = ra_vars[i].var_value == NULL ? "":
ra_vars[i].var_value;
d_var = ra_vars[i].var_default_value == NULL ?
"": ra_vars[i].var_default_value;
if (parseable) {
if (param == NULL)
(void) printf("%s ", ra_vars[i].var_name);
(void) printf("persistent=\"%s\" "
"default=\"%s\" \n", p_var, d_var);
} else {
if ((IS_IPV4_VAR(ra_vars[i].var_name) &&
IPV4_VARS_UNSET) ||
(IS_IPV6_VAR(ra_vars[i].var_name) &&
IPV6_VARS_UNSET))
continue;
(void) printf(gettext("%1$27s \"%2$s\"\n"),
ra_intloptname(ra_vars[i].var_name), p_var);
}
}
if (param != NULL && !param_found) {
(void) fprintf(stderr, gettext(
"%s: no such option/variable %s\n"), myname, param);
return (-1);
}
if (parseable)
return (0);
(void) printf(gettext("\nRouting daemons:\n"));
(void) printf("\n %s %s\n", "STATE", "FMRI");
if (ra_smf_cb(ra_print_state_cb, NULL, NULL) == -1)
return (-1);
return (0);
}
static int
ra_smf_cb(ra_smf_cb_t cbfunc, const char *fmri, void *data)
{
scf_handle_t *h;
int exit_status = 0;
if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
scf_handle_bind(h) == -1) {
(void) fprintf(stderr, gettext(
"%s: cannot connect to SMF repository\n"), myname);
return (-1);
}
return (scf_walk_fmri(h, fmri == NULL ? 0 : 1,
fmri == NULL ? NULL : (char **)&fmri, 0,
cbfunc, data, &exit_status, uu_die));
}
static int
ra_set_current_opt_cb(void *data, scf_walkinfo_t *wip)
{
return (ra_get_set_opt_common_cb(data, wip, B_FALSE, B_FALSE));
}
static int
ra_set_persistent_opt_cb(void *data, scf_walkinfo_t *wip)
{
return (ra_get_set_opt_common_cb(data, wip, B_TRUE, B_FALSE));
}
static int
ra_get_current_opt_cb(void *data, scf_walkinfo_t *wip)
{
return (ra_get_set_opt_common_cb(data, wip, B_FALSE, B_TRUE));
}
static int
ra_get_persistent_opt_cb(void *data, scf_walkinfo_t *wip)
{
return (ra_get_set_opt_common_cb(data, wip, B_TRUE, B_TRUE));
}
static int
ra_routing_opt_set_cb(void *data, scf_walkinfo_t *wip)
{
return (ra_routing_opt_set_unset_cb(data, wip, B_TRUE));
}
static int
ra_routing_opt_unset_cb(void *data, scf_walkinfo_t *wip)
{
return (ra_routing_opt_set_unset_cb(data, wip, B_FALSE));
}
static int
ra_routing_opt_set_unset_cb(raopt_t *raopt, scf_walkinfo_t *wip, boolean_t set)
{
scf_instance_t *inst = wip->inst;
scf_handle_t *h = scf_instance_handle(inst);
return (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
raopt->opt_flags & RA_SVC_FLAG_IPV4_ROUTING ?
RA_PROP_IPV4_ROUTING_SET : RA_PROP_IPV6_ROUTING_SET,
B_FALSE, set));
}
static int
ra_get_set_opt_common_cb(raopt_t *raopt, scf_walkinfo_t *wip,
boolean_t persistent, boolean_t get)
{
const char *inst_fmri = wip->fmri;
scf_instance_t *inst = wip->inst;
scf_handle_t *h = scf_instance_handle(inst);
scf_propertygroup_t *routeadm_pg;
boolean_t persistent_state_enabled;
boolean_t temporary_state_enabled;
boolean_t current_state_enabled;
boolean_t curr_svc = B_TRUE;
boolean_t found_proto;
char **protolist = NULL;
int i, ret, numvalues = 0;
if (ra_get_pg(h, inst, RA_PG_ROUTEADM, B_TRUE, raopt->opt_fmri != NULL,
&routeadm_pg) == -1) {
if (scf_error() == SCF_ERROR_NOT_FOUND &&
raopt->opt_fmri == NULL)
return (0);
return (-1);
}
scf_pg_destroy(routeadm_pg);
if (raopt->opt_fmri == NULL && ra_get_prop_as_string(h, inst,
RA_PG_ROUTEADM, RA_PROP_PROTO, B_TRUE, B_FALSE, NULL, &numvalues,
&protolist) == -1) {
if (scf_error() == SCF_ERROR_NOT_FOUND)
return (0);
return (-1);
}
if (raopt->opt_flags & RA_SVC_FLAG_IPV4_ROUTING) {
found_proto = B_FALSE;
if (protolist != NULL) {
for (i = 0; i < numvalues; i++) {
if (protolist[i] != NULL && strcmp(
protolist[i], RA_PROPVAL_PROTO_IPV4) == 0)
found_proto = B_TRUE;
}
}
if (protolist == NULL || !found_proto) {
ra_free_prop_values(numvalues, protolist);
return (0);
}
}
if (raopt->opt_flags & RA_SVC_FLAG_IPV6_ROUTING) {
found_proto = B_FALSE;
if (protolist != NULL) {
for (i = 0; i < numvalues; i++) {
if (protolist[i] != NULL && strcmp(
protolist[i], RA_PROPVAL_PROTO_IPV6) == 0)
found_proto = B_TRUE;
}
}
if (protolist == NULL || !found_proto) {
ra_free_prop_values(numvalues, protolist);
return (0);
}
if (raopt->opt_enabled && ra_numv6intfs() < 1)
return (0);
}
ra_free_prop_values(numvalues, protolist);
if (raopt->opt_fmri == NULL && !get && raopt->opt_enabled) {
if (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
RA_PROP_CURR_ROUTING_SVC, B_FALSE, B_FALSE,
&curr_svc) == -1)
return (0);
else if (!curr_svc && persistent) {
return (0);
}
}
if (ra_get_boolean_prop(h, inst, SCF_PG_GENERAL, SCF_PROPERTY_ENABLED,
B_FALSE, B_TRUE, &persistent_state_enabled) == -1)
return (-1);
current_state_enabled = persistent_state_enabled;
if (ra_get_boolean_prop(h, inst, SCF_PG_GENERAL_OVR,
SCF_PROPERTY_ENABLED, B_FALSE, B_FALSE, &temporary_state_enabled)
== 0)
current_state_enabled = temporary_state_enabled;
if (get) {
if (persistent)
raopt->opt_enabled = raopt->opt_enabled ||
persistent_state_enabled;
else
raopt->opt_enabled = raopt->opt_enabled ||
current_state_enabled;
} else {
if (persistent) {
ret = current_state_enabled ?
smf_enable_instance(inst_fmri, SMF_TEMPORARY) :
smf_disable_instance(inst_fmri, SMF_TEMPORARY);
if (ret != 0) {
(void) fprintf(stderr, gettext(
"%s: unexpected libscf error: %s\n"),
myname, scf_strerror(scf_error()));
return (-1);
}
(void) smf_refresh_instance(inst_fmri);
ret = ra_set_boolean_prop(h, inst, SCF_PG_GENERAL,
SCF_PROPERTY_ENABLED, B_FALSE, raopt->opt_enabled);
if (ret != 0)
return (-1);
(void) smf_refresh_instance(inst_fmri);
if (raopt->opt_fmri != NULL)
return (0);
(void) smf_refresh_instance(RA_INSTANCE_ROUTING_SETUP);
} else {
(void) smf_refresh_instance(inst_fmri);
ret = persistent_state_enabled && curr_svc ?
smf_enable_instance(inst_fmri, 0) :
smf_disable_instance(inst_fmri, 0);
if (ret != 0) {
(void) fprintf(stderr, gettext(
"%s: unexpected libscf error: %s\n"),
myname, scf_strerror(scf_error()));
return (-1);
}
if (current_state_enabled && persistent_state_enabled) {
(void) smf_restart_instance(inst_fmri);
}
}
}
return (0);
}
static int
ra_set_default_opt_cb(void *data, scf_walkinfo_t *wip)
{
scf_instance_t *inst = wip->inst;
scf_handle_t *h = scf_instance_handle(inst);
raopt_t *raopt = data;
return (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
raopt->opt_default_prop, B_FALSE, raopt->opt_default_enabled));
}
static int
ra_get_default_opt_cb(void *data, scf_walkinfo_t *wip)
{
scf_instance_t *inst = wip->inst;
scf_handle_t *h = scf_instance_handle(inst);
raopt_t *raopt = data;
return (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
raopt->opt_default_prop, B_TRUE, B_TRUE,
&(raopt->opt_default_enabled)));
}
static int
ra_get_persistent_var_cb(void *data, scf_walkinfo_t *wip)
{
scf_instance_t *inst = wip->inst;
scf_handle_t *h = scf_instance_handle(inst);
ravar_t *ravar = data;
return (ra_get_single_prop_as_string(h, inst, RA_PG_ROUTEADM,
ravar->var_prop, B_TRUE, B_TRUE, NULL, &ravar->var_value));
}
static int
ra_set_persistent_var_cb(void *data, scf_walkinfo_t *wip)
{
scf_instance_t *inst = wip->inst;
scf_handle_t *h = scf_instance_handle(inst);
ravar_t *ravar = data;
return (ra_set_prop_from_string(h, inst, RA_PG_ROUTEADM,
ravar->var_prop, SCF_TYPE_INVALID, B_FALSE, 1,
(const char **)&ravar->var_value));
}
static int
ra_get_default_var_cb(void *data, scf_walkinfo_t *wip)
{
scf_instance_t *inst = wip->inst;
scf_handle_t *h = scf_instance_handle(inst);
ravar_t *ravar = data;
return (ra_get_single_prop_as_string(h, inst, RA_PG_ROUTEADM,
ravar->var_default_prop, B_TRUE, B_TRUE, NULL,
&ravar->var_default_value));
}
static int
ra_mark_routing_svcs_cb(void *data, scf_walkinfo_t *wip)
{
scf_instance_t *inst = wip->inst;
scf_handle_t *h = scf_instance_handle(inst);
boolean_t *mark = data;
boolean_t marked;
int numvalues = 0;
char **protolist = NULL;
if (ra_get_prop_as_string(h, inst, RA_PG_ROUTEADM, RA_PROP_PROTO,
B_TRUE, B_FALSE, NULL, &numvalues, &protolist) == -1)
return (0);
ra_free_prop_values(numvalues, protolist);
if (*mark)
return (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
RA_PROP_CURR_ROUTING_SVC, B_TRUE, B_TRUE));
if (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
RA_PROP_CURR_ROUTING_SVC, B_TRUE, B_FALSE, &marked) == 0 && marked)
return (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
RA_PROP_CURR_ROUTING_SVC, B_TRUE, B_FALSE));
return (0);
}
static int
ra_list_props_cb(void *data, scf_walkinfo_t *wip)
{
const char *inst_fmri = wip->fmri;
scf_instance_t *inst = wip->inst;
scf_handle_t *h = scf_instance_handle(inst);
scf_iter_t *propiter, *valiter;
scf_propertygroup_t *pg;
scf_property_t *prop;
scf_value_t *val;
char **protolist = NULL, *pnamebuf, *valbuf;
ssize_t pnamelen, vallen;
int numvalues = 0;
int propiterret, valiterret, retval = 0;
if (ra_get_prop_as_string(h, inst, RA_PG_ROUTEADM, RA_PROP_PROTO,
B_TRUE, B_FALSE, NULL, &numvalues, &protolist) == -1) {
if (scf_error() == SCF_ERROR_NOT_FOUND)
(void) fprintf(stderr,
gettext("%s: %s is not a routing daemon service\n"),
myname, inst_fmri);
else
(void) fprintf(stderr,
gettext("%s: unexpected libscf error: %s\n"),
myname, scf_strerror(scf_error()));
ra_free_prop_values(numvalues, protolist);
return (-1);
}
ra_free_prop_values(numvalues, protolist);
if (ra_get_pg(h, inst, RA_PG_ROUTING, B_TRUE, B_FALSE, &pg) == -1) {
if (scf_error() == SCF_ERROR_NOT_FOUND) {
(void) printf("%s: no %s property group for %s\n",
myname, RA_PG_ROUTING, inst_fmri);
return (0);
}
(void) fprintf(stderr,
gettext("%s: unexpected libscf error: %s\n"),
myname, scf_strerror(scf_error()));
return (-1);
}
(void) printf("%s:\n", inst_fmri);
if ((propiter = scf_iter_create(h)) == NULL ||
(prop = scf_property_create(h)) == NULL ||
scf_iter_pg_properties(propiter, pg) != 0) {
(void) fprintf(stderr, gettext
("%s: could not iterate through properties for %s: %s\n"),
myname, inst_fmri, scf_strerror(scf_error()));
}
while ((propiterret = scf_iter_next_property(propiter, prop)) == 1) {
if ((pnamelen = scf_property_get_name(prop, NULL, 0) + 1)
== 0) {
(void) fprintf(stderr, gettext("%s: could not retrieve "
"property name for instance %s: %s\n"), myname,
inst_fmri, scf_strerror(scf_error()));
retval = -1;
break;
}
if ((pnamebuf = malloc(pnamelen)) == NULL) {
(void) fprintf(stderr,
gettext("%s: out of memory\n"), myname);
retval = -1;
break;
}
(void) scf_property_get_name(prop, pnamebuf,
pnamelen);
(void) printf("\t%s = ", pnamebuf);
if ((valiter = scf_iter_create(h)) == NULL ||
(val = scf_value_create(h)) == NULL ||
scf_iter_property_values(valiter, prop)
!= 0) {
(void) fprintf(stderr, gettext
("%s: could not iterate through "
"properties for %s: %s\n"), myname, inst_fmri,
scf_strerror(scf_error()));
scf_value_destroy(val);
scf_iter_destroy(valiter);
free(pnamebuf);
retval = -1;
break;
}
while ((valiterret = scf_iter_next_value(valiter, val)) == 1) {
if ((vallen = scf_value_get_as_string
(val, NULL, 0) + 1) == 0) {
(void) fprintf(stderr, gettext
("%s: could not retrieve "
"property value for instance %s, "
"property %s: %s\n"), myname, inst_fmri,
pnamebuf, scf_strerror(scf_error()));
retval = -1;
} else if ((valbuf = malloc(vallen)) == NULL) {
(void) fprintf(stderr,
gettext("%s: out of memory\n"), myname);
retval = -1;
}
if (retval == -1) {
scf_iter_destroy(valiter);
scf_value_destroy(val);
free(pnamebuf);
goto out;
}
(void) scf_value_get_as_string(val, valbuf, vallen);
(void) printf("%s ", valbuf);
free(valbuf);
}
(void) printf("\n");
scf_iter_destroy(valiter);
scf_value_destroy(val);
free(pnamebuf);
if (valiterret == -1) {
(void) fprintf(stderr,
gettext("%s: could not iterate through"
"properties for %s: %s\n"), myname, inst_fmri,
scf_strerror(scf_error()));
retval = -1;
break;
}
}
out:
scf_iter_destroy(propiter);
scf_property_destroy(prop);
scf_pg_destroy(pg);
if (propiterret == -1)
(void) fprintf(stderr, gettext
("%s: could not iterate through properties for %s: %s\n"),
myname, inst_fmri, scf_strerror(scf_error()));
return (retval);
}
static int
ra_modify_props_cb(void *data, scf_walkinfo_t *wip)
{
const char *inst_fmri = wip->fmri;
scf_instance_t *inst = wip->inst;
scf_handle_t *h = scf_instance_handle(inst);
ra_prop_t *raprop = data;
int numvalues = 0;
char **protolist = NULL;
if (ra_get_prop_as_string(h, inst, RA_PG_ROUTEADM, RA_PROP_PROTO,
B_TRUE, B_FALSE, NULL, &numvalues, &protolist) == -1) {
if (scf_error() == SCF_ERROR_NOT_FOUND)
(void) fprintf(stderr,
gettext("%s: %s is not a routing daemon service\n"),
myname, inst_fmri);
else
(void) fprintf(stderr,
gettext("%s: unexpected libscf error: %s\n"),
myname, scf_strerror(scf_error()));
ra_free_prop_values(numvalues, protolist);
return (-1);
}
ra_free_prop_values(numvalues, protolist);
if (ra_set_prop_from_string(h, inst, RA_PG_ROUTING, raprop->prop_name,
SCF_TYPE_INVALID, B_FALSE, raprop->prop_numvalues,
(const char **)raprop->prop_values) == -1)
return (-1);
(void) smf_refresh_instance(inst_fmri);
return (0);
}
static int
ra_print_state_cb(void *data, scf_walkinfo_t *wip)
{
const char *inst_fmri = wip->fmri;
scf_instance_t *inst = wip->inst;
scf_handle_t *h = scf_instance_handle(inst);
char *inst_state, **protolist = NULL;
int numvalues = 0;
if (ra_get_prop_as_string(h, inst, RA_PG_ROUTEADM, RA_PROP_PROTO,
B_TRUE, B_FALSE, NULL, &numvalues, &protolist) == -1)
return (0);
ra_free_prop_values(numvalues, protolist);
if ((inst_state = smf_get_state(inst_fmri)) == NULL) {
(void) fprintf(stderr,
gettext("%s: could not retrieve state for %s: %s\n"),
myname, inst_fmri, scf_strerror(scf_error()));
return (-1);
}
(void) printf("%27s %2s\n", inst_state, inst_fmri);
free(inst_state);
return (0);
}
static int
ra_get_pg(scf_handle_t *h, scf_instance_t *inst, const char *pgname,
boolean_t composed, boolean_t required, scf_propertygroup_t **pg)
{
if ((*pg = scf_pg_create(h)) == NULL || (composed &&
scf_instance_get_pg_composed(inst, NULL, pgname, *pg) != 0) ||
(!composed && scf_instance_get_pg(inst, pgname, *pg) != 0)) {
if (scf_error() == SCF_ERROR_NOT_FOUND) {
if (required)
(void) fprintf(stderr, gettext(
"%s: no such property group %s\n"),
myname, pgname);
return (-1);
}
if (required)
(void) fprintf(stderr, gettext(
"%s: unexpected libscf error: %s\n"), myname,
scf_strerror(scf_error()));
return (-1);
}
return (0);
}
static int
ra_get_boolean_prop(scf_handle_t *h, scf_instance_t *inst,
const char *pgname, const char *propname, boolean_t composed,
boolean_t required, boolean_t *val)
{
char *valstr;
if (ra_get_single_prop_as_string(h, inst, pgname, propname,
composed, required, NULL, &valstr) != 0)
return (-1);
*val = strcmp(valstr, RA_PROPVAL_BOOLEAN_TRUE) == 0;
free(valstr);
return (0);
}
static int
ra_get_single_prop_as_string(scf_handle_t *h, scf_instance_t *inst,
const char *pgname, const char *propname, boolean_t composed,
boolean_t required, scf_type_t *type, char **value)
{
char **values;
int numvalues = 1;
if (ra_get_prop_as_string(h, inst, pgname, propname, composed, required,
type, &numvalues, &values) == -1)
return (-1);
*value = values[0];
free(values);
return (0);
}
static int
ra_get_prop_as_string(scf_handle_t *h, scf_instance_t *inst,
const char *pgname, const char *propname, boolean_t composed,
boolean_t required, scf_type_t *type, int *numvalues, char ***values)
{
scf_propertygroup_t *pg = NULL;
scf_property_t *prop = NULL;
scf_iter_t *valiter = NULL;
scf_value_t *val = NULL;
ssize_t vallen = 0;
int valiterret, i, numvalues_retrieved, ret = 0;
if (ra_get_pg(h, inst, pgname, composed, required, &pg) == -1)
return (-1);
*values = NULL;
if ((prop = scf_property_create(h)) == NULL)
goto error;
if (scf_pg_get_property(pg, propname, prop) != 0) {
*numvalues = 0;
if (scf_error() == SCF_ERROR_NOT_FOUND) {
if (required)
(void) fprintf(stderr, gettext(
"%s: property %s/%s not found\n"),
myname, pgname, propname);
ret = -1;
goto out;
}
goto error;
}
if ((val = scf_value_create(h)) == NULL &&
scf_property_get_value(prop, val) != 0 ||
(valiter = scf_iter_create(h)) == NULL ||
scf_iter_property_values(valiter, prop) != 0)
goto error;
for (numvalues_retrieved = 0;
(valiterret = scf_iter_next_value(valiter, val)) == 1;
numvalues_retrieved++) {
if ((vallen = scf_value_get_as_string
(val, NULL, 0) + 1) == 0)
goto error;
if ((*values = realloc(*values,
sizeof (*values) + sizeof (char *))) == NULL ||
((*values)[numvalues_retrieved] = malloc(vallen)) == NULL) {
(void) fprintf(stderr, gettext(
"%s: out of memory\n"), myname);
ret = -1;
goto out;
}
(void) scf_value_get_as_string(val,
(*values)[numvalues_retrieved], vallen);
}
if (valiterret == -1)
goto error;
if (*numvalues != 0 && *numvalues != numvalues_retrieved) {
(void) fprintf(stderr, gettext(
"%s: got %d values for property %s/%s, expected %d\n"),
myname, numvalues_retrieved, pgname, propname, *numvalues);
ret = -1;
goto out;
}
*numvalues = numvalues_retrieved;
if (type != NULL)
(void) scf_property_type(prop, type);
goto out;
error:
if (scf_error() == SCF_ERROR_NOT_FOUND) {
(void) fprintf(stderr, gettext(
"%s: property %s not found"), myname, propname);
} else {
(void) fprintf(stderr, gettext(
"%s: unexpected libscf error: %s, "), myname);
}
for (i = 0; i < numvalues_retrieved; i++)
free((*values)[i]);
if (*values != NULL)
free(*values);
ret = -1;
out:
if (val != NULL)
scf_value_destroy(val);
if (valiter != NULL)
scf_iter_destroy(valiter);
if (prop != NULL)
scf_property_destroy(prop);
if (pg != NULL)
scf_pg_destroy(pg);
return (ret);
}
static void
ra_free_prop_values(int numvalues, char **values)
{
int i;
if (values != NULL) {
for (i = 0; i < numvalues; i++)
free(values[i]);
free(values);
}
}
static int
ra_set_boolean_prop(scf_handle_t *h, scf_instance_t *inst, const char *pgname,
const char *prop, boolean_t create, boolean_t propval)
{
const char *val = propval ? RA_PROPVAL_BOOLEAN_TRUE :
RA_PROPVAL_BOOLEAN_FALSE;
return (ra_set_prop_from_string(h, inst, pgname, prop, SCF_TYPE_BOOLEAN,
create, 1, &val));
}
static int
ra_set_prop_from_string(scf_handle_t *h, scf_instance_t *inst,
const char *pgname, const char *propname, scf_type_t proptype,
boolean_t create, int numpropvals, const char **propvals)
{
scf_propertygroup_t *instpg = NULL, *cpg = NULL;
scf_type_t oldproptype, newproptype = proptype;
scf_property_t *prop = NULL;
scf_value_t **values = NULL;
scf_transaction_t *tx = NULL;
scf_transaction_entry_t *ent = NULL;
boolean_t new = B_FALSE;
int i, retval, numvalues = 0, ret = 0;
char *pgtype = NULL, **ovalues;
ssize_t typelen;
if (ra_get_prop_as_string(h, inst, pgname, propname, B_TRUE,
B_FALSE, &oldproptype, &numvalues, &ovalues) == -1) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
goto error;
if (!create) {
(void) fprintf(stderr, gettext(
"%s: no such property %s/%s\n"), myname, pgname,
propname);
return (-1);
}
} else
ra_free_prop_values(numvalues, ovalues);
if (proptype == SCF_TYPE_INVALID)
newproptype = oldproptype;
if (ra_get_pg(h, inst, pgname, B_FALSE, B_FALSE, &instpg) == -1) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
goto error;
if (ra_get_pg(h, inst, pgname, B_TRUE, B_FALSE, &cpg) == -1)
goto error;
if ((typelen = scf_pg_get_type(cpg, NULL, 0) + 1) == 0)
goto error;
if ((pgtype = malloc(typelen)) == NULL) {
(void) fprintf(stderr, gettext(
"%s: out of memory\n"), myname);
goto error;
}
(void) scf_pg_get_type(cpg, pgtype, typelen);
if ((instpg = scf_pg_create(h)) == NULL ||
scf_instance_add_pg(inst, pgname, pgtype, 0, instpg)
== -1) {
(void) fprintf(stderr, gettext(
"%s: could not create property group %s\n"),
myname, pgname);
goto error;
}
}
if ((prop = scf_property_create(h)) == NULL)
goto error;
if ((values = calloc(numpropvals, sizeof (scf_value_t *))) == NULL) {
(void) fprintf(stderr, gettext("%s: out of memory"), myname);
goto error;
}
if (scf_pg_get_property(instpg, propname, prop) != 0) {
if (scf_error() == SCF_ERROR_NOT_FOUND)
new = B_TRUE;
else
goto error;
}
if ((tx = scf_transaction_create(h)) == NULL ||
(ent = scf_entry_create(h)) == NULL)
goto error;
retry:
if (scf_transaction_start(tx, instpg) == -1)
goto error;
if (new) {
if (scf_transaction_property_new(tx, ent, propname,
newproptype) == -1)
goto error;
} else if (scf_transaction_property_change(tx, ent, propname,
newproptype) == -1)
goto error;
for (i = 0; i < numpropvals; i++) {
if ((values[i] = scf_value_create(h)) == NULL ||
scf_value_set_from_string(values[i], newproptype,
propvals[i] == NULL ? "": propvals[i]) == -1 ||
scf_entry_add_value(ent, values[i]) != 0)
goto error;
}
retval = scf_transaction_commit(tx);
if (retval == 0) {
scf_transaction_reset(tx);
if (scf_pg_update(instpg) == -1)
goto error;
goto retry;
}
if (retval == -1)
goto error;
goto out;
error:
switch (scf_error()) {
case SCF_ERROR_INVALID_ARGUMENT:
(void) fprintf(stderr, gettext(
"%s: invalid value for property %s/%s\n"), myname,
pgname, propname);
break;
case SCF_ERROR_NOT_FOUND:
(void) fprintf(stderr, gettext(
"%s: no such property %s/%s\n"), myname,
pgname, propname);
break;
default:
(void) fprintf(stderr, gettext(
"%s: unexpected libscf error: %s\n"), myname,
scf_strerror(scf_error()));
break;
}
ret = -1;
out:
if (tx != NULL)
scf_transaction_destroy(tx);
if (ent != NULL)
scf_entry_destroy(ent);
if (values != NULL) {
for (i = 0; i < numpropvals; i++) {
if (values[i] != NULL)
scf_value_destroy(values[i]);
}
free(values);
}
if (prop != NULL)
scf_property_destroy(prop);
if (cpg != NULL)
scf_pg_destroy(cpg);
if (instpg != NULL)
scf_pg_destroy(instpg);
if (pgtype != NULL)
free(pgtype);
return (ret);
}
static int
ra_upgrade_from_legacy_conf(void)
{
scf_handle_t *h = NULL;
scf_instance_t *inst = NULL;
int ret = 0, i, r;
boolean_t old_conf_read;
ravar_t *routing_svcs = ra_str2var(RA_VAR_ROUTING_SVCS);
if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
scf_handle_bind(h) == -1) {
(void) fprintf(stderr, gettext(
"%s: cannot connect to SMF repository\n"), myname);
ret = -1;
goto out;
}
if ((inst = scf_instance_create(h)) == NULL ||
scf_handle_decode_fmri(h, RA_INSTANCE_ROUTING_SETUP,
NULL, NULL, inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
(void) fprintf(stderr, gettext(
"%s: unexpected libscf error: %s\n"), myname,
scf_strerror(scf_error()));
ret = -1;
goto out;
}
if (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
RA_PROP_ROUTING_CONF_READ, B_TRUE, B_TRUE, &old_conf_read) == -1) {
ret = -1;
goto out;
}
if (old_conf_read)
goto out;
if (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
RA_PROP_ROUTING_CONF_READ, B_FALSE, B_TRUE) == -1)
return (-1);
(void) smf_refresh_instance(RA_INSTANCE_ROUTING_SETUP);
ra_resetvars(NULL);
if ((r = ra_parseconf()) == -1) {
ret = -1;
goto out;
}
if (r == 0)
goto out;
for (i = 0; ra_vars[i].var_name != NULL; i++) {
if (strcmp(ra_vars[i].var_name, RA_VAR_ROUTING_SVCS) == 0)
continue;
if (ra_smf_cb(ra_set_persistent_var_cb, ra_vars[i].var_fmri,
&(ra_vars[i])) == -1) {
ret = -1;
goto out;
}
}
if (ra_smf_cb(ra_set_persistent_var_cb, routing_svcs->var_fmri,
routing_svcs) == -1) {
ret = -1;
goto out;
}
if (ra_check_legacy_daemons() == -1) {
ret = -1;
goto out;
}
for (i = 0; ra_opts[i].opt_name != NULL; i++) {
if (ra_smf_cb(ra_set_persistent_opt_cb, ra_opts[i].opt_fmri,
&(ra_opts[i])) == -1 ||
ra_smf_cb(ra_set_default_opt_cb,
ra_opts[i].opt_default_fmri, &(ra_opts[i])) == -1) {
ret = -1;
break;
}
}
out:
if (inst != NULL)
scf_instance_destroy(inst);
if (h != NULL)
scf_handle_destroy(h);
return (ret);
}
static int
ra_numv6intfs(void)
{
static int num = -1;
int ipsock;
struct lifnum lifn;
if (num != -1)
return (num);
if ((ipsock = socket(PF_INET6, SOCK_DGRAM, 0)) == -1) {
(void) fprintf(stderr,
gettext("%1$s: unable to open %2$s: %3$s\n"),
myname, IP_DEV_NAME, strerror(errno));
return (0);
}
lifn.lifn_family = AF_INET6;
lifn.lifn_flags = 0;
if (ioctl(ipsock, SIOCGLIFNUM, &lifn) == -1) {
(void) close(ipsock);
return (0);
}
(void) close(ipsock);
return (num = lifn.lifn_count);
}
static int
ra_parseconf(void)
{
FILE *fp;
uint_t lineno;
char line[RA_MAX_CONF_LINE];
char *cp, *confstr;
raopt_t *raopt;
ravar_t *ravar;
if ((fp = fopen(RA_CONF_FILE, "r")) == NULL) {
return (0);
}
for (lineno = 1; fgets(line, sizeof (line), fp) != NULL; lineno++) {
if (line[strlen(line) - 1] == '\n')
line[strlen(line) - 1] = '\0';
cp = line;
while (isspace(*cp))
cp++;
if (*cp == '#' || *cp == '\0')
continue;
if ((confstr = strtok(cp, " ")) == NULL) {
(void) fprintf(stderr,
gettext("%1$s: %2$s: invalid entry on line %3$d\n"),
myname, RA_CONF_FILE, lineno);
continue;
}
if ((raopt = ra_str2opt(confstr)) != NULL) {
if (ra_parseopt(confstr, lineno, raopt) != 0) {
(void) fclose(fp);
return (-1);
}
} else if ((ravar = ra_str2var(confstr)) != NULL) {
if (ra_parsevar(confstr, ravar) != 0) {
(void) fclose(fp);
return (-1);
}
} else {
(void) fprintf(stderr,
gettext("%1$s: %2$s: invalid option name on "
"line %3$d\n"),
myname, RA_CONF_FILE, lineno);
continue;
}
}
(void) fclose(fp);
return (1);
}
static int
ra_parseopt(char *confstr, int lineno, raopt_t *raopt)
{
oval_t oval, d_oval;
if ((confstr = strtok(NULL, " ")) == NULL) {
(void) fprintf(stderr,
gettext("%1$s: %2$s: missing value on line %3$d\n"),
myname, RA_CONF_FILE, lineno);
return (0);
}
if ((oval = ra_str2oval(confstr)) == OPT_INVALID) {
(void) fprintf(stderr,
gettext("%1$s: %2$s: invalid option "
"value on line %3$d\n"),
myname, RA_CONF_FILE, lineno);
return (0);
}
if (oval != OPT_DEFAULT)
raopt->opt_enabled = oval == OPT_ENABLED;
if ((confstr = strtok(NULL, " ")) == NULL) {
(void) fprintf(stderr,
gettext("%1$s: %2$s: missing revert "
"value on line %3$d\n"),
myname, RA_CONF_FILE, lineno);
return (0);
}
if ((d_oval = ra_str2oval(confstr)) == OPT_INVALID) {
(void) fprintf(stderr,
gettext("%1$s: %2$s: invalid revert "
"value on line %3$d\n"),
myname, RA_CONF_FILE, lineno, confstr);
return (0);
}
raopt->opt_default_enabled = d_oval == OPT_ENABLED;
if (oval == OPT_DEFAULT)
raopt->opt_enabled = d_oval == OPT_ENABLED;
if (raopt->opt_flags & (RA_SVC_FLAG_IPV4_ROUTING |
RA_SVC_FLAG_IPV6_ROUTING)) {
if (ra_smf_cb(oval == OPT_DEFAULT ? ra_routing_opt_unset_cb :
ra_routing_opt_set_cb, raopt->opt_default_fmri, raopt)
== -1)
return (-1);
}
return (0);
}
static int
ra_parsevar(char *confstr, ravar_t *ravar)
{
confstr = strtok(NULL, "=");
if (confstr == NULL) {
ravar->var_value = NULL;
return (0);
}
if ((ravar->var_value = strdup(confstr)) == NULL) {
(void) fprintf(stderr, gettext("%s: "
"unable to allocate memory\n"), myname);
return (-1);
}
return (0);
}
static oval_t
ra_str2oval(const char *valstr)
{
if (strcmp(valstr, "enabled") == 0)
return (OPT_ENABLED);
else if (strcmp(valstr, "disabled") == 0)
return (OPT_DISABLED);
else if (strcmp(valstr, "default") == 0)
return (OPT_DEFAULT);
return (OPT_INVALID);
}
static raopt_t *
ra_str2opt(const char *optnamestr)
{
int i;
for (i = 0; ra_opts[i].opt_name != NULL; i++) {
if (strcmp(optnamestr, ra_opts[i].opt_name) == 0)
break;
}
if (ra_opts[i].opt_name == NULL)
return (NULL);
return (&ra_opts[i]);
}
static void
ra_resetopts(void)
{
int i;
for (i = 0; ra_opts[i].opt_name != NULL; i++) {
ra_opts[i].opt_enabled = B_FALSE;
ra_opts[i].opt_default_enabled = B_FALSE;
}
}
static ravar_t *
ra_str2var(const char *varnamestr)
{
int i;
for (i = 0; ra_vars[i].var_name != NULL; i++) {
if (strcmp(varnamestr, ra_vars[i].var_name) == 0)
break;
}
if (ra_vars[i].var_name == NULL)
return (NULL);
return (&ra_vars[i]);
}
static void
ra_resetvars(const char *proto)
{
int i;
for (i = 0; ra_vars[i].var_name != NULL; i++) {
if (proto != NULL &&
!VAR_PROTO_MATCH(ra_vars[i].var_name, proto))
continue;
if (ra_vars[i].var_value != NULL)
free(ra_vars[i].var_value);
ra_vars[i].var_value = NULL;
if (ra_vars[i].var_default_value != NULL)
free(ra_vars[i].var_default_value);
ra_vars[i].var_default_value = NULL;
}
}
static char *
ra_intloptname(const char *optname)
{
if (strcmp(optname, RA_OPT_IPV4_FORWARDING) == 0)
return (gettext("IPv4 forwarding"));
else if (strcmp(optname, RA_OPT_IPV4_ROUTING) == 0)
return (gettext("IPv4 routing"));
else if (strcmp(optname, RA_OPT_IPV6_FORWARDING) == 0)
return (gettext("IPv6 forwarding"));
else if (strcmp(optname, RA_OPT_IPV6_ROUTING) == 0)
return (gettext("IPv6 routing"));
else if (strcmp(optname, RA_VAR_IPV4_ROUTING_DAEMON) == 0)
return (gettext("IPv4 routing daemon"));
else if (strcmp(optname, RA_VAR_IPV4_ROUTING_DAEMON_ARGS) == 0)
return (gettext("IPv4 routing daemon args"));
else if (strcmp(optname, RA_VAR_IPV4_ROUTING_STOP_CMD) == 0)
return (gettext("IPv4 routing daemon stop"));
else if (strcmp(optname, RA_VAR_IPV6_ROUTING_DAEMON) == 0)
return (gettext("IPv6 routing daemon"));
else if (strcmp(optname, RA_VAR_IPV6_ROUTING_DAEMON_ARGS) == 0)
return (gettext("IPv6 routing daemon args"));
else if (strcmp(optname, RA_VAR_IPV6_ROUTING_STOP_CMD) == 0)
return (gettext("IPv6 routing daemon stop"));
else if (strcmp(optname, RA_VAR_ROUTING_SVCS) == 0)
return (gettext("Routing services"));
return (NULL);
}