/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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>
static char *cmdname; /* command name for messages */
static char verbose; /* non-zero if the -v option has been given */
static char all_flag; /* non-zero if the -a option has been given */
static char force; /* non-zero if the -F option has been given */
static char log_open; /* non-zero if openlog() has been called */
static struct utmpx ut; /* structure for logging to /etc/wtmpx. */
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", cmdname, cmdname);
}
/*
* Find base name of filename.
*/
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" },
};
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);
}
/*
* Set processor state.
* Return non-zero if a processor was found.
* Print messages and update wtmp and the system log.
* If mustexist is set, it is an error if a processor isn't there.
*/
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); /* no such processor */
err = errno; /* in case sprintf smashes 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); /* no such processor */
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); /* no change */
}
(void) snprintf(buf, sizeof (buf), "processor %d %s %s.",
cpu, pac->p_action, pac->p_state);
if (verbose)
(void) printf("%s\n", buf);
/*
* Log the change.
*/
if (!log_open) {
log_open = 1;
openlog(cmdname, LOG_CONS, LOG_USER); /* open syslog */
(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);
/*
* Update wtmp.
*/
(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); /* the processor exists and no errors occurred */
}
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;
cmdname = basename(argv[0]);
while ((c = getopt(argc, argv, "afFinsv")) != EOF) {
switch (c) {
case 'a': /* applies to all possible CPUs */
all_flag = 1;
break;
case 'F':
force = 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);
}
}
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) {
/*
* The -F option without other transition options
* puts processor(s) into faulted state.
*/
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(); /* not enough arguments */
return (2);
}
for (argv += optind; argc > 0; argv++, argc--) {
if (strchr(*argv, '-') == NULL) {
/* individual processor id */
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 {
/* range of processors */
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);
}