#include <sys/types.h>
#include <sys/procset.h>
#include <sys/processor.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <syslog.h>
#include <time.h>
#include <utmpx.h>
#include <assert.h>
#include <stdbool.h>
static char *cmdname;
static char verbose;
static char all_flag;
static char force;
static char log_open;
static struct utmpx ut;
static char *basename(char *);
static void
usage(void)
{
(void) fprintf(stderr, "usage:\n"
"\t%s [-F] -f|-n|-i|-s [-v] processor_id ...\n"
"\t%s -a -f|-n|-i [-v]\n"
"\t%s -aS [-v]\n",
cmdname, cmdname, cmdname);
}
static char *
basename(char *cp)
{
char *sp;
if ((sp = strrchr(cp, '/')) != NULL)
return (sp + 1);
return (cp);
}
typedef struct _psr_action {
int p_op;
char *p_state;
char *p_action;
char *p_wtmp;
} psr_action_t;
static psr_action_t psr_action[] = {
{ P_ONLINE, "on-line", "brought", "on" },
{ P_OFFLINE, "off-line", "taken", "off" },
{ P_NOINTR, "no-intr", "set to", "ni" },
{ P_SPARE, "spare", "marked", "spr" },
{ P_FAULTED, "faulted", "marked", "flt" },
{ P_DISABLED, "disabled", "set as", "dis" },
};
static int psr_actions = sizeof (psr_action) / sizeof (psr_action_t);
static psr_action_t *
psr_action_lookup(int action)
{
int i;
for (i = 0; i < psr_actions; ++i) {
if (psr_action[i].p_op == action) {
return (&psr_action[i]);
}
}
return (NULL);
}
static int
psr_set_state(processorid_t cpu, int action, psr_action_t *pac, int mustexist)
{
int old_state;
int err;
time_t now;
char buf[80];
old_state = p_online(cpu, P_STATUS);
if (old_state < 0) {
if (errno == EINVAL && !mustexist)
return (0);
err = errno;
(void) snprintf(buf, sizeof (buf), "%s: processor %d",
cmdname, cpu);
errno = err;
perror(buf);
return (-1);
}
if (old_state == P_FAULTED && action != P_FAULTED && !force) {
(void) printf("%s: processor %d in faulted state; "
"add -F option to force change\n", cmdname, cpu);
return (-1);
}
old_state = p_online(cpu, force ? action | P_FORCED : action);
if (old_state < 0) {
if (errno == EINVAL && !mustexist)
return (0);
err = errno;
(void) snprintf(buf, sizeof (buf), "%s: processor %d",
cmdname, cpu);
errno = err;
perror(buf);
return (-1);
}
if (old_state == action) {
if (verbose)
(void) printf("processor %d already %s.\n", cpu,
pac->p_state);
return (1);
}
(void) snprintf(buf, sizeof (buf), "processor %d %s %s.",
cpu, pac->p_action, pac->p_state);
if (verbose)
(void) printf("%s\n", buf);
if (!log_open) {
log_open = 1;
openlog(cmdname, LOG_CONS, LOG_USER);
(void) setlogmask(LOG_UPTO(LOG_INFO));
ut.ut_pid = getpid();
ut.ut_type = USER_PROCESS;
(void) strncpy(ut.ut_user, "psradm", sizeof (ut.ut_user) - 1);
}
syslog(LOG_INFO, "%s", buf);
(void) snprintf(ut.ut_line, sizeof (ut.ut_line), PSRADM_MSG,
cpu, pac->p_wtmp);
(void) time(&now);
ut.ut_xtime = now;
updwtmpx(WTMPX_FILE, &ut);
return (1);
}
static int
do_range(processorid_t first, processorid_t last, int action,
psr_action_t *pac)
{
processorid_t cpu;
int error = 0;
int rv;
int found_one = 0;
for (cpu = first; cpu <= last; cpu++) {
if ((rv = psr_set_state(cpu, action, pac, 0)) > 0)
found_one = 1;
else if (rv < 0)
error = 1;
}
if (!found_one && error == 0) {
(void) fprintf(stderr, "%s: no processors in range %d-%d\n",
cmdname, first, last);
error = 1;
}
return (error);
}
int
main(int argc, char *argv[])
{
int c;
int action = 0;
processorid_t cpu;
processorid_t cpuid_max;
char *errptr;
int errors;
psr_action_t *pac;
bool disable_smt = 0;
cmdname = basename(argv[0]);
while ((c = getopt(argc, argv, "afFinsSv")) != EOF) {
switch (c) {
case 'a':
all_flag = 1;
break;
case 'F':
force = 1;
break;
case 'S':
disable_smt = 1;
break;
case 'f':
case 'i':
case 'n':
case 's':
if (action != 0 && action != c) {
(void) fprintf(stderr,
"%s: options -f, -n, -i, and -s are "
"mutually exclusive.\n", cmdname);
usage();
return (2);
}
action = c;
break;
case 'v':
verbose = 1;
break;
default:
usage();
return (2);
}
}
if (disable_smt) {
if (!all_flag) {
fprintf(stderr, "%s: -S must be used with -a.\n",
cmdname);
usage();
return (2);
}
if (force || action != 0 || argc != optind) {
usage();
return (2);
}
if (p_online(P_ALL_SIBLINGS, P_DISABLED) == -1) {
fprintf(stderr, "Failed to disable simultaneous "
"multi-threading: %s\n", strerror(errno));
return (EXIT_FAILURE);
}
return (EXIT_SUCCESS);
}
switch (action) {
case 'f':
action = P_OFFLINE;
break;
case 'i':
action = P_NOINTR;
break;
case 'n':
action = P_ONLINE;
break;
case 's':
action = P_SPARE;
break;
default:
if (force != 0) {
action = P_FAULTED;
break;
}
(void) fprintf(stderr,
"%s: option -f, -n, -s or -i must "
"be specified.\n", cmdname);
usage();
return (2);
}
pac = psr_action_lookup(action);
assert(pac != NULL);
errors = 0;
if (all_flag) {
if (argc != optind) {
usage();
return (2);
}
cpuid_max = (processorid_t)sysconf(_SC_CPUID_MAX);
for (cpu = 0; cpu <= cpuid_max; cpu++) {
if (psr_set_state(cpu, action, pac, 0) < 0)
errors = 1;
}
} else {
argc -= optind;
if (argc <= 0) {
usage();
return (2);
}
for (argv += optind; argc > 0; argv++, argc--) {
if (strchr(*argv, '-') == NULL) {
cpu = (processorid_t)
strtol(*argv, &errptr, 10);
if (errptr != NULL && *errptr != '\0') {
(void) fprintf(stderr,
"%s: invalid processor"
" ID %s\n", cmdname, *argv);
errors = 2;
continue;
}
if (psr_set_state(cpu, action, pac, 1) < 0)
errors = 1;
} else {
processorid_t first, last;
first = (processorid_t)
strtol(*argv, &errptr, 10);
if (*errptr++ != '-') {
(void) fprintf(stderr,
"%s: invalid processor"
" range %s\n", cmdname, *argv);
errors = 2;
continue;
}
last = (processorid_t)
strtol(errptr, &errptr, 10);
if ((errptr != NULL && *errptr != '\0') ||
last < first || first < 0) {
(void) fprintf(stderr,
"%s: invalid processor"
" range %s\n", cmdname, *argv);
errors = 2;
continue;
}
if (do_range(first, last, action, pac))
errors = 1;
}
}
}
if (log_open) {
closelog();
}
return (errors);
}