#include <sys/types.h>
#include <sys/systm.h>
#include <sys/cpr.h>
#include <sys/kmem.h>
#include <sys/errno.h>
static cdef_t *new_def_info;
static cdef_t orig_def_info = {
0, 0,
0, "boot-file", "",
0, "boot-device", "",
0, "auto-boot?", "",
0, "diag-file", "",
0, "diag-device", "",
};
#define CPR_BF_IDX 0
#define CPR_BD_IDX 1
#define CPR_AB_IDX 2
#define CPR_DF_IDX 3
#define CPR_DD_IDX 4
#define CPR_PROP_PTR(dfp, idx) &(dfp)->props[idx]
static char *cpr_next_component(char **);
static char *cpr_get_prefix(char *);
static char *cpr_build_nodename(pnode_t);
static void cpr_abbreviate_devpath(char *, char *);
static int cpr_show_props = 0;
static int
cpr_get_options_node(pnode_t *nodep)
{
*nodep = prom_optionsnode();
if (*nodep == OBP_NONODE || *nodep == OBP_BADNODE) {
cpr_err(CE_WARN, "cannot get \"options\" node");
return (ENOENT);
}
return (0);
}
static int
cpr_get_bool_prop(char *name, int *result)
{
char value[PROP_BOOL_LEN];
pnode_t node;
int len, err;
if (err = cpr_get_options_node(&node))
return (err);
len = prom_getproplen(node, name);
if (len < 0 || len >= sizeof (value))
return (ENXIO);
bzero(value, sizeof (value));
if (prom_getprop(node, name, value) != len)
return (ENOENT);
*result = (strcmp(value, "true") == 0);
return (0);
}
int
cpr_update_nvram(cprop_t *props)
{
cprop_t *tail;
pnode_t node;
int len, rc;
if (rc = cpr_get_options_node(&node))
return (rc);
if (cpr_show_props)
prom_printf("\ncpr_show_props:\n");
for (tail = props + CPR_MAXPROP; props < tail; props++) {
if (cpr_show_props) {
prom_printf("mod=%c, name \"%s\",\tvalue \"%s\"\n",
props->mod, props->name, props->value);
}
if (props->mod == PROP_NOMOD)
continue;
len = strlen(props->value);
rc = prom_setprop(node, props->name, props->value, len + 1);
if (rc < 0 || prom_getproplen(node, props->name) != len) {
cpr_err(CE_WARN, "cannot set nvram \"%s\" to \"%s\"",
props->name, props->value);
return (ENXIO);
}
}
return (0);
}
int
cpr_set_properties(int new)
{
cprop_t *props;
props = new ? new_def_info->props : orig_def_info.props;
return (cpr_update_nvram(props));
}
static void
cpr_prop_update(int index, char *str)
{
cprop_t *prop;
prop = CPR_PROP_PTR(&orig_def_info, index);
prop->mod = PROP_MOD;
prop = CPR_PROP_PTR(new_def_info, index);
prop->mod = PROP_MOD;
(void) strcpy(prop->value, str);
}
static int
cpr_prop_setup(void)
{
int len, err, ds_ival, dev_idx, file_idx;
char bootdev[OBP_MAXPATHLEN], bootfile[OBP_MAXPATHLEN];
char *cp, *sp;
cpr_abbreviate_devpath(prom_bootpath(), bootdev);
(void) strcpy(bootfile, CPRBOOT);
if (!cpr_reusable_mode && cpr_statefile_is_spec())
sp = " -S ";
else
sp = NULL;
if (sp) {
(void) strcat(bootfile, sp);
len = strlen(bootfile);
sp = cpr_get_statefile_prom_path();
cpr_abbreviate_devpath(sp, &bootfile[len]);
}
if (err = cpr_get_bool_prop("diag-switch?", &ds_ival))
return (err);
else if (ds_ival == 0) {
dev_idx = CPR_BD_IDX;
file_idx = CPR_BF_IDX;
} else {
dev_idx = CPR_DD_IDX;
file_idx = CPR_DF_IDX;
}
cpr_prop_update(dev_idx, bootdev);
if (!cpr_reusable_mode)
cpr_prop_update(file_idx, bootfile);
sp = orig_def_info.props[CPR_AB_IDX].value;
cp = "true";
if (strcmp(sp, cp))
cpr_prop_update(CPR_AB_IDX, cp);
return (0);
}
int
cpr_default_setup(int alloc)
{
cprop_t *orig, *new, *tail;
int len, err = 0;
pnode_t node;
char *fmt;
if (alloc == 0) {
ASSERT(new_def_info);
kmem_free(new_def_info, sizeof (*new_def_info));
new_def_info = NULL;
return (0);
}
if (err = cpr_get_options_node(&node))
return (err);
ASSERT(new_def_info == NULL);
new_def_info = kmem_zalloc(sizeof (*new_def_info), KM_SLEEP);
new = new_def_info->props;
for (orig = orig_def_info.props, tail = orig + CPR_MAXPROP;
orig < tail; orig++, new++) {
len = prom_getproplen(node, orig->name);
if (len < 0 || len >= (int)sizeof (orig->value)) {
fmt = "invalid property or length for \"%s\"";
err = ENXIO;
break;
}
bzero(orig->value, sizeof (orig->value));
if (prom_getprop(node, orig->name, orig->value) < 0) {
fmt = "cannot get \"%s\" value";
err = ENXIO;
break;
}
new->mod = orig->mod = PROP_NOMOD;
(void) strcpy(new->name, orig->name);
}
if (err) {
kmem_free(new_def_info, sizeof (*new_def_info));
new_def_info = NULL;
cpr_err(CE_WARN, fmt, orig->name);
} else
err = cpr_prop_setup();
return (err);
}
int
cpr_validate_definfo(int reusable)
{
orig_def_info.mini.magic = CPR->c_cprboot_magic = CPR_DEFAULT_MAGIC;
orig_def_info.mini.reusable = reusable;
return (cpr_write_deffile(&orig_def_info));
}
void
cpr_send_notice(void)
{
static char cstr[] = "\014" "\033[1P" "\033[18;21H";
prom_printf(cstr);
prom_printf("Saving System State. Please Wait... ");
}
void
cpr_spinning_bar(void)
{
static char *spin_strings[] = { "|\b", "/\b", "-\b", "\\\b" };
static int idx;
prom_printf(spin_strings[idx]);
if (++idx == 4)
idx = 0;
}
void
cpr_resume_notice(void)
{
static char cstr[] = "\014" "\033[1P" "\033[18;21H";
prom_printf(cstr);
prom_printf("Restoring System State. Please Wait... ");
}
static void
cpr_abbreviate_devpath(char *in_path, char *out_path)
{
static pnode_t cur_node;
char *position = in_path + 1;
char *cmpt;
cur_node = prom_nextnode(0);
*out_path = '\0';
while ((cmpt = cpr_next_component(&position)) != NULL) {
pnode_t long_match = 0;
pnode_t short_match = 0;
int short_hits = 0;
char *name;
char *prefix = cpr_get_prefix(cmpt);
if ((cur_node = prom_childnode(cur_node)) == 0) {
(void) strcpy(out_path, in_path);
return;
}
do {
name = cpr_build_nodename(cur_node);
if (strcmp(name, cmpt) == 0)
long_match = cur_node;
if (strncmp(prefix, name, strlen(prefix)) == 0) {
short_match = cur_node;
short_hits++;
}
} while ((cur_node = prom_nextnode(cur_node)) != 0);
(void) strcat(out_path, "/");
if (short_hits == 1) {
(void) strcat(out_path, prefix);
cur_node = short_match;
}
else
if (long_match) {
(void) strcat(out_path, cmpt);
cur_node = long_match;
} else {
(void) strcpy(out_path, in_path);
return;
}
}
(void) strcat(out_path, strrchr(in_path, '@'));
}
static char *
cpr_next_component(char **path)
{
static char obuf[64];
char *slash;
int len = strlen(*path);
if (len == 0)
return (NULL);
if ((slash = strchr(*path, '/'))) {
len = slash - *path;
(void) strncpy(obuf, *path, len);
obuf[len] = '\0';
*path += len + 1;
} else {
(void) strcpy(obuf, *path);
*path += len;
}
return (obuf);
}
static char *
cpr_get_prefix(char *cmpt)
{
static char prefix[OBP_MAXDRVNAME];
char *at_sign = strchr(cmpt, '@');
int len = at_sign ? at_sign - cmpt : strlen(cmpt);
(void) strncpy(prefix, cmpt, len);
prefix[len] = '\0';
return (prefix);
}
static char *
cpr_build_nodename(pnode_t node)
{
static char name[OBP_MAXPATHLEN];
int reg[512];
char buf[32];
int prop_len = prom_getproplen(node, OBP_NAME);
if (prop_len < 0 || prop_len >= sizeof (name) ||
prom_getprop(node, OBP_NAME, name) < 0)
return ("");
name[prop_len] = '\0';
if ((prop_len = prom_getproplen(node, OBP_REG)) <
2 * sizeof (int) || prop_len >= sizeof (reg))
return (name);
if (prom_getprop(node, OBP_REG, (caddr_t)reg) < 0)
return (name);
(void) sprintf(buf, "@%x,%x", reg[0], reg[1]);
(void) strcat(name, buf);
return (name);
}
char *
cpr_enumerate_promprops(char **bufp, size_t *len)
{
cprop_t *prop, *tail;
size_t size = 2;
char *buf;
tail = &orig_def_info.props[CPR_MAXPROP];
for (prop = orig_def_info.props; prop < tail; prop++)
size += strlen(prop->name) + 2;
buf = kmem_alloc(size, KM_SLEEP);
*buf = '\0';
for (prop = orig_def_info.props; prop < tail; prop++) {
if (strlen(buf))
(void) strcat(buf, ", ");
(void) strcat(buf, prop->name);
}
(void) strcat(buf, ".");
*bufp = buf;
*len = size;
return (buf);
}