summaryrefslogtreecommitdiff
path: root/usr/src/cmd/psrset
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/psrset
downloadillumos-gate-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/psrset')
-rw-r--r--usr/src/cmd/psrset/Makefile57
-rw-r--r--usr/src/cmd/psrset/Makefile.com59
-rw-r--r--usr/src/cmd/psrset/amd64/Makefile35
-rw-r--r--usr/src/cmd/psrset/i386/Makefile33
-rw-r--r--usr/src/cmd/psrset/psrset.c1036
-rw-r--r--usr/src/cmd/psrset/sparcv9/Makefile35
6 files changed, 1255 insertions, 0 deletions
diff --git a/usr/src/cmd/psrset/Makefile b/usr/src/cmd/psrset/Makefile
new file mode 100644
index 0000000000..3545e81511
--- /dev/null
+++ b/usr/src/cmd/psrset/Makefile
@@ -0,0 +1,57 @@
+#
+# 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
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/psrset/Makefile
+#
+
+PROG= psrset
+
+include ../Makefile.cmd
+
+$(64ONLY)SUBDIRS= $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+install := TARGET = install
+clean := TARGET = clean
+clobber := TARGET = clobber
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber lint: $(SUBDIRS)
+
+install: $(SUBDIRS)
+ -$(RM) $(ROOTUSRSBINPROG)
+ -$(LN) $(ISAEXEC) $(ROOTUSRSBINPROG)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/psrset/Makefile.com b/usr/src/cmd/psrset/Makefile.com
new file mode 100644
index 0000000000..72d9c2de20
--- /dev/null
+++ b/usr/src/cmd/psrset/Makefile.com
@@ -0,0 +1,59 @@
+#
+# 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 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/psrset/Makefile.com
+#
+
+PROG= psrset
+OBJS= psrset.o
+SRCS= $(OBJS:%.o=../%.c)
+
+include ../../Makefile.cmd
+
+OWNER = root
+GROUP = sys
+CFLAGS += $(CCVERBOSE)
+LDLIBS += -lproc
+
+.KEEP_STATE:
+
+%.o: ../%.c
+ $(COMPILE.c) $<
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+clean:
+ $(RM) $(OBJS)
+
+lint:
+ $(LINT.c) $(SRCS) $(LDLIBS)
+
+include ../../Makefile.targ
diff --git a/usr/src/cmd/psrset/amd64/Makefile b/usr/src/cmd/psrset/amd64/Makefile
new file mode 100644
index 0000000000..76fdb4f6f6
--- /dev/null
+++ b/usr/src/cmd/psrset/amd64/Makefile
@@ -0,0 +1,35 @@
+#
+# 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 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/psrset/amd64/Makefile
+#
+
+include ../Makefile.com
+include ../../Makefile.cmd.64
+
+install: all $(ROOTUSRSBINPROG64)
+
diff --git a/usr/src/cmd/psrset/i386/Makefile b/usr/src/cmd/psrset/i386/Makefile
new file mode 100644
index 0000000000..e53979aa98
--- /dev/null
+++ b/usr/src/cmd/psrset/i386/Makefile
@@ -0,0 +1,33 @@
+#
+# 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 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/psrset/i386/Makefile
+#
+
+include ../Makefile.com
+
+install: all $(ROOTUSRSBINPROG32)
diff --git a/usr/src/cmd/psrset/psrset.c b/usr/src/cmd/psrset/psrset.c
new file mode 100644
index 0000000000..162366553a
--- /dev/null
+++ b/usr/src/cmd/psrset/psrset.c
@@ -0,0 +1,1036 @@
+/*
+ * 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"
+
+/*
+ * psrset - create and manage processor sets
+ */
+
+#include <sys/types.h>
+#include <sys/procset.h>
+#include <sys/processor.h>
+#include <sys/pset.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <dirent.h>
+#include <locale.h>
+#include <string.h>
+#include <limits.h>
+#include <procfs.h>
+#include <libproc.h>
+#include <stdarg.h>
+#include <priv.h>
+
+#if !defined(TEXT_DOMAIN) /* should be defined by cc -D */
+#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
+#endif
+
+#define MAX_PROCFS_PATH 80
+
+#define ERR_OK 0 /* exit status for success */
+#define ERR_FAIL 1 /* exit status for errors */
+#define ERR_USAGE 2 /* exit status for usage errors */
+
+static char *progname;
+static int errors;
+static char cflag;
+static char dflag;
+static char aflag;
+static char rflag;
+static char iflag;
+static char bflag;
+static char uflag;
+static char Uflag;
+static char qflag;
+static char Qflag;
+static char pflag;
+static char nflag;
+static char fflag;
+static char Fflag;
+static char eflag;
+
+extern int pset_assign_forced(psetid_t, processorid_t, psetid_t *);
+
+/*PRINTFLIKE1*/
+static void
+warn(char *format, ...)
+{
+ int err = errno;
+ va_list alist;
+
+ (void) fprintf(stderr, "%s: ", progname);
+ va_start(alist, format);
+ (void) vfprintf(stderr, format, alist);
+ va_end(alist);
+ if (strchr(format, '\n') == NULL)
+ (void) fprintf(stderr, ": %s\n", strerror(err));
+}
+
+/*PRINTFLIKE1*/
+static void
+die(char *format, ...)
+{
+ int err = errno;
+ va_list alist;
+
+ (void) fprintf(stderr, "%s: ", progname);
+ va_start(alist, format);
+ (void) vfprintf(stderr, format, alist);
+ va_end(alist);
+ if (strchr(format, '\n') == NULL)
+ (void) fprintf(stderr, ": %s\n", strerror(err));
+ exit(ERR_FAIL);
+}
+
+static prpriv_t *orig_priv;
+
+static struct ps_prochandle *
+grab_proc(id_t pid)
+{
+ int ret;
+ prpriv_t *new_priv;
+ priv_set_t *eff_set, *perm_set;
+ struct ps_prochandle *Pr;
+
+ if ((Pr = Pgrab(pid, 0, &ret)) == NULL) {
+ warn(gettext("cannot control process %d: %s\n"),
+ (int)pid, Pgrab_error(ret));
+ errors = ERR_FAIL;
+ return (NULL);
+ }
+
+ /*
+ * If target process does not have required PRIV_SYS_RES_CONFIG
+ * privilege, assign it temporarily to that process' effective
+ * and permitted sets so that it can call pset_bind(2).
+ */
+ if ((new_priv = proc_get_priv(pid)) == NULL) {
+ warn(gettext("unable to get privileges for process %d: %s\n"),
+ pid, strerror(errno));
+ errors = ERR_FAIL;
+ Prelease(Pr, 0);
+ return (NULL);
+ }
+
+ if (Pcreate_agent(Pr) != 0) {
+ warn(gettext("cannot control process %d\n"), (int)pid);
+ errors = ERR_FAIL;
+ Prelease(Pr, 0);
+ free(new_priv);
+ return (NULL);
+ }
+
+ eff_set = (priv_set_t *)&new_priv->pr_sets[new_priv->pr_setsize *
+ priv_getsetbyname(PRIV_EFFECTIVE)];
+ perm_set = (priv_set_t *)&new_priv->pr_sets[new_priv->pr_setsize *
+ priv_getsetbyname(PRIV_PERMITTED)];
+ if (!priv_ismember(eff_set, PRIV_SYS_RES_CONFIG)) {
+ /*
+ * Save original privileges
+ */
+ if ((orig_priv = proc_get_priv(pid)) == NULL) {
+ warn(gettext("unable to get privileges for "
+ "process %d: %s\n"), pid, strerror(errno));
+ errors = ERR_FAIL;
+ Pdestroy_agent(Pr);
+ Prelease(Pr, 0);
+ free(new_priv);
+ return (NULL);
+ }
+ (void) priv_addset(eff_set, PRIV_SYS_RES_CONFIG);
+ (void) priv_addset(perm_set, PRIV_SYS_RES_CONFIG);
+ /*
+ * We don't want to leave a process with elevated privileges,
+ * so make sure the process dies if we exit unexpectedly.
+ */
+ if (Psetflags(Pr, PR_KLC) != 0 ||
+ Psetpriv(Pr, new_priv) != 0) {
+ warn(gettext("unable to set process privileges for "
+ "process %d: %s\n"), pid, strerror(errno));
+ (void) Punsetflags(Pr, PR_KLC);
+ free(new_priv);
+ free(orig_priv);
+ Pdestroy_agent(Pr);
+ Prelease(Pr, 0);
+ orig_priv = NULL;
+ errors = ERR_FAIL;
+ return (NULL);
+ }
+ }
+ free(new_priv);
+
+ return (Pr);
+}
+
+static void
+rele_proc(struct ps_prochandle *Pr)
+{
+ if (Pr == NULL)
+ return;
+ if (orig_priv != NULL) {
+ if (Psetpriv(Pr, orig_priv) != 0) {
+ /*
+ * If this fails, we can't leave a process with
+ * elevated privileges, so we have to release the
+ * process from libproc, knowing that it will
+ * be killed (since we set the PR_KLC flag).
+ */
+ Pdestroy_agent(Pr);
+ warn(gettext("cannot relinquish privileges for "
+ "process %d. The process was killed\n"),
+ Ppsinfo(Pr)->pr_pid);
+ errors = ERR_FAIL;
+ } else {
+ (void) Punsetflags(Pr, PR_KLC);
+ Pdestroy_agent(Pr);
+ }
+ free(orig_priv);
+ orig_priv = NULL;
+ } else {
+ Pdestroy_agent(Pr);
+ }
+ Prelease(Pr, 0);
+}
+
+static void
+bind_err(psetid_t pset, id_t pid, id_t lwpid, int err)
+{
+ char *msg;
+
+ switch (pset) {
+ case PS_NONE:
+ msg = gettext("unbind");
+ break;
+ case PS_QUERY:
+ msg = gettext("query");
+ break;
+ default:
+ msg = gettext("bind");
+ break;
+ }
+
+ errno = err;
+ if (lwpid == -1)
+ warn(gettext("cannot %s pid %d"), msg, pid);
+ else
+ warn(gettext("cannot %s lwpid %d/%d"), msg, pid, lwpid);
+}
+
+/*
+ * Output for create.
+ */
+static void
+create_out(psetid_t pset)
+{
+ (void) printf("%s %d\n", gettext("created processor set"), pset);
+}
+
+/*
+ * Output for assign.
+ */
+static void
+assign_out(processorid_t cpu, psetid_t old, psetid_t new)
+{
+ if (old == PS_NONE) {
+ if (new == PS_NONE)
+ (void) printf(gettext("processor %d: was not assigned,"
+ " now not assigned\n"), cpu);
+ else
+ (void) printf(gettext("processor %d: was not assigned,"
+ " now %d\n"), cpu, new);
+ } else {
+ if (new == PS_NONE)
+ (void) printf(gettext("processor %d: was %d, "
+ "now not assigned\n"), cpu, old);
+ else
+ (void) printf(gettext("processor %d: was %d, "
+ "now %d\n"), cpu, old, new);
+ }
+}
+
+/*
+ * Output for query.
+ */
+static void
+query_out(id_t pid, id_t lwpid, psetid_t pset)
+{
+ char *proclwp;
+ char pidstr[21];
+
+ if (lwpid == -1) {
+ (void) snprintf(pidstr, 20, "%d", pid);
+ proclwp = "process";
+ } else {
+ (void) snprintf(pidstr, 20, "%d/%d", pid, lwpid);
+ proclwp = "lwp";
+ }
+
+ if (pset == PS_NONE)
+ (void) printf(gettext("%s id %s: not bound\n"),
+ proclwp, pidstr);
+ else
+ (void) printf(gettext("%s id %s: %d\n"), proclwp, pidstr, pset);
+}
+
+/*
+ * Output for info.
+ */
+static void
+info_out(psetid_t pset, int type, uint_t numcpus, processorid_t *cpus)
+{
+ int i;
+ if (type == PS_SYSTEM)
+ (void) printf(gettext("system processor set %d:"), pset);
+ else
+ (void) printf(gettext("user processor set %d:"), pset);
+ if (numcpus == 0)
+ (void) printf(gettext(" empty"));
+ else if (numcpus > 1)
+ (void) printf(gettext(" processors"));
+ else
+ (void) printf(gettext(" processor"));
+ for (i = 0; i < numcpus; i++)
+ (void) printf(" %d", cpus[i]);
+ (void) printf("\n");
+}
+
+/*
+ * Output for print.
+ */
+static void
+print_out(processorid_t cpu, psetid_t pset)
+{
+ if (pset == PS_NONE)
+ (void) printf(gettext("processor %d: not assigned\n"), cpu);
+ else
+ (void) printf(gettext("processor %d: %d\n"), cpu, pset);
+}
+
+/*
+ * Output for bind.
+ */
+static void
+bind_out(id_t pid, id_t lwpid, psetid_t old, psetid_t new)
+{
+ char *proclwp;
+ char pidstr[21];
+
+ if (lwpid == -1) {
+ (void) snprintf(pidstr, 20, "%d", pid);
+ proclwp = "process";
+ } else {
+ (void) snprintf(pidstr, 20, "%d/%d", pid, lwpid);
+ proclwp = "lwp";
+ }
+
+ if (old == PS_NONE) {
+ if (new == PS_NONE)
+ (void) printf(gettext("%s id %s: was not bound, "
+ "now not bound\n"), proclwp, pidstr);
+ else
+ (void) printf(gettext("%s id %s: was not bound, "
+ "now %d\n"), proclwp, pidstr, new);
+ } else {
+ if (new == PS_NONE)
+ (void) printf(gettext("%s id %s: was %d, "
+ "now not bound\n"), proclwp, pidstr, old);
+ else
+ (void) printf(gettext("%s id %s: was %d, "
+ "now %d\n"), proclwp, pidstr, old, new);
+ }
+}
+
+static void
+bind_lwp(struct ps_prochandle *Pr, id_t pid, id_t lwpid, psetid_t pset)
+{
+ psetid_t old_pset;
+
+ if (pr_pset_bind(Pr, pset, P_LWPID, lwpid, &old_pset) < 0) {
+ bind_err(pset, pid, lwpid, errno);
+ errors = ERR_FAIL;
+ } else {
+ if (qflag)
+ query_out(pid, lwpid, old_pset);
+ else
+ bind_out(pid, lwpid, old_pset, pset);
+ }
+}
+
+static int
+do_cpu(psetid_t pset, processorid_t cpu, int print, int mustexist)
+{
+ psetid_t old_pset;
+ int err;
+
+ if ((!Fflag && pset_assign(pset, cpu, &old_pset) != 0) ||
+ (Fflag && pset_assign_forced(pset, cpu, &old_pset) != 0)) {
+ if (errno == EINVAL && !mustexist)
+ return (EINVAL);
+ err = errno;
+
+ switch (pset) {
+ case PS_NONE:
+ warn(gettext("cannot remove processor %d"), cpu);
+ break;
+ case PS_QUERY:
+ warn(gettext("cannot query processor %d"), cpu);
+ break;
+ default:
+ warn(gettext("cannot assign processor %d"), cpu);
+ break;
+ }
+ return (err);
+ }
+ if (print)
+ print_out(cpu, old_pset);
+ else
+ assign_out(cpu, old_pset, pset);
+ return (0);
+}
+
+static int
+do_range(psetid_t pset, processorid_t first, processorid_t last, int print)
+{
+ processorid_t cpu;
+ int error = ERR_OK;
+ int err;
+ int found_one = 0;
+
+ for (cpu = first; cpu <= last; cpu++) {
+ if ((err = do_cpu(pset, cpu, print, 0)) == 0)
+ found_one = 1;
+ else if (err != EINVAL)
+ error = ERR_FAIL;
+ }
+ if (!found_one && error == ERR_OK) {
+ warn(gettext("no processors in range %d-%d\n"), first, last);
+ error = ERR_FAIL;
+ }
+ return (error);
+}
+
+static int
+do_info(psetid_t pset)
+{
+ int type;
+ uint_t numcpus;
+ processorid_t *cpus;
+
+ numcpus = (uint_t)sysconf(_SC_NPROCESSORS_MAX);
+ cpus = (processorid_t *)
+ malloc(numcpus * sizeof (processorid_t));
+ if (cpus == NULL) {
+ warn(gettext("memory allocation failed"));
+ return (ERR_FAIL);
+ }
+ if (pset_info(pset, &type, &numcpus, cpus) != 0) {
+ warn(gettext("cannot get info for processor set %d"), pset);
+ free(cpus);
+ return (ERR_FAIL);
+ }
+ info_out(pset, type, numcpus, cpus);
+ free(cpus);
+ return (ERR_OK);
+}
+
+static int
+do_destroy(psetid_t pset)
+{
+ if (pset_destroy(pset) != 0) {
+ warn(gettext("could not remove processor set %d"), pset);
+ return (ERR_FAIL);
+ }
+ (void) printf(gettext("removed processor set %d\n"), pset);
+ return (ERR_OK);
+}
+
+static int
+do_intr(psetid_t pset, int flag)
+{
+ uint_t i, numcpus;
+ processorid_t *cpus;
+ int error = ERR_OK;
+
+ numcpus = (uint_t)sysconf(_SC_NPROCESSORS_MAX);
+ cpus = (processorid_t *)
+ malloc(numcpus * sizeof (processorid_t));
+ if (cpus == NULL) {
+ warn(gettext("memory allocation failed"));
+ return (ERR_FAIL);
+ }
+ if (pset_info(pset, NULL, &numcpus, cpus) != 0) {
+ warn(gettext(
+ "cannot set interrupt status for processor set %d"), pset);
+ free(cpus);
+ return (ERR_FAIL);
+ }
+ for (i = 0; i < numcpus; i++) {
+ int status = p_online(cpus[i], P_STATUS);
+ if (status != P_OFFLINE && status != P_POWEROFF &&
+ status != flag) {
+ if (p_online(cpus[i], flag) == -1) {
+ warn(gettext("processor %d"), cpus[i]);
+ error = ERR_FAIL;
+ }
+ }
+ }
+ free(cpus);
+ return (error);
+}
+
+/*
+ * Query the type and CPUs for all active processor sets in the system.
+ */
+static int
+info_all(void)
+{
+ psetid_t *psetlist;
+ uint_t npsets, oldnpsets;
+ int i;
+ int errors = ERR_OK;
+
+ if (pset_list(NULL, &npsets) != 0) {
+ warn(gettext("cannot get number of processor sets"));
+ return (1);
+ }
+ for (;;) {
+ psetlist = malloc(sizeof (psetid_t) * npsets);
+ if (psetlist == NULL) {
+ warn(gettext("memory allocation failed"));
+ return (ERR_FAIL);
+ }
+ oldnpsets = npsets;
+ if (pset_list(psetlist, &npsets) != 0) {
+ warn(gettext("cannot get list of processor sets"));
+ free(psetlist);
+ return (ERR_FAIL);
+ }
+ if (npsets <= oldnpsets)
+ break;
+ free(psetlist);
+ }
+
+ for (i = 0; i < npsets; i++) {
+ if (do_info(psetlist[i]))
+ errors = ERR_FAIL;
+ }
+ free(psetlist);
+ return (errors);
+}
+
+/*
+ * Query the processor set assignments for all CPUs in the system.
+ */
+static int
+print_all(void)
+{
+ psetid_t pset;
+ processorid_t cpuid, max_cpuid;
+ int errors = ERR_OK;
+
+ max_cpuid = (processorid_t)sysconf(_SC_CPUID_MAX);
+ for (cpuid = 0; cpuid <= max_cpuid; cpuid++) {
+ if (pset_assign(PS_QUERY, cpuid, &pset) == 0) {
+ if (pset != PS_NONE)
+ print_out(cpuid, pset);
+ } else if (errno != EINVAL) {
+ warn(gettext("cannot query processor %d"), cpuid);
+ errors = ERR_FAIL;
+ }
+ }
+ return (errors);
+}
+
+/*ARGSUSED*/
+static int
+query_all_proc(psinfo_t *psinfo, lwpsinfo_t *lwpsinfo, void *arg)
+{
+ id_t pid = psinfo->pr_pid;
+ psetid_t binding;
+
+ if (pset_bind(PS_QUERY, P_PID, pid, &binding) < 0) {
+ /*
+ * Ignore search errors. The process may have exited
+ * since we read the directory.
+ */
+ if (errno == ESRCH)
+ return (0);
+ bind_err(PS_QUERY, pid, -1, errno);
+ errors = ERR_FAIL;
+ return (0);
+ }
+ if (binding != PS_NONE)
+ query_out(pid, -1, binding);
+ return (0);
+}
+
+static int
+query_all_lwp(psinfo_t *psinfo, lwpsinfo_t *lwpsinfo, void *arg)
+{
+ id_t pid = psinfo->pr_pid;
+ id_t lwpid = lwpsinfo->pr_lwpid;
+ psetid_t *cpuid = arg;
+ psetid_t binding = lwpsinfo->pr_bindpset;
+
+ if (psinfo->pr_nlwp == 1)
+ lwpid = -1; /* report process bindings if only 1 lwp */
+ if ((cpuid != NULL && *cpuid == binding) ||
+ (cpuid == NULL && binding != PBIND_NONE))
+ query_out(pid, lwpid, binding);
+ return (0);
+}
+
+void
+exec_cmd(psetid_t pset, char **argv)
+{
+ if (pset_bind(pset, P_PID, P_MYID, NULL) != 0) {
+ warn(gettext("cannot exec in processor set %d"), pset);
+ return;
+ }
+
+ (void) execvp(argv[0], argv);
+ warn(gettext("cannot exec command %s"), argv[0]);
+}
+
+int
+usage(void)
+{
+ (void) fprintf(stderr, gettext(
+ "usage: \n"
+ "\t%1$s -c [-F] [processor_id ...]\n"
+ "\t%1$s -d processor_set_id ...\n"
+ "\t%1$s -n processor_set_id\n"
+ "\t%1$s -f processor_set_id\n"
+ "\t%1$s -e processor_set_id command [argument(s)...]\n"
+ "\t%1$s -a [-F] processor_set_id processor_id ...\n"
+ "\t%1$s -r [-F] processor_id ...\n"
+ "\t%1$s -p [processorid ...]\n"
+ "\t%1$s -b processor_set_id pid[/lwpids] ...\n"
+ "\t%1$s -u pid[/lwpids] ...\n"
+ "\t%1$s -q [pid[/lwpids] ...]\n"
+ "\t%1$s -U [processor_set_id] ...\n"
+ "\t%1$s -Q [processor_set_id] ...\n"
+ "\t%1$s [-i] [processor_set_id ...]\n"),
+ progname);
+ return (ERR_USAGE);
+}
+
+/*
+ * Query, set, or clear bindings for the range of LWPs in the given process.
+ */
+static int
+do_lwps(id_t pid, const char *range, psetid_t pset)
+{
+ char procfile[MAX_PROCFS_PATH];
+ struct ps_prochandle *Pr;
+ struct prheader header;
+ struct lwpsinfo *lwp;
+ char *lpsinfo, *ptr;
+ psetid_t binding;
+ int nent, size;
+ int i, fd, found;
+
+ /*
+ * Report bindings for LWPs in process 'pid'.
+ */
+ (void) snprintf(procfile, MAX_PROCFS_PATH,
+ "/proc/%d/lpsinfo", (int)pid);
+ if ((fd = open(procfile, O_RDONLY)) < 0) {
+ if (errno == ENOENT)
+ errno = ESRCH;
+ bind_err(pset, pid, -1, errno);
+ return (ERR_FAIL);
+ }
+ if (pread(fd, &header, sizeof (header), 0) != sizeof (header)) {
+ (void) close(fd);
+ bind_err(pset, pid, -1, errno);
+ return (ERR_FAIL);
+ }
+ nent = header.pr_nent;
+ size = header.pr_entsize * nent;
+ ptr = lpsinfo = malloc(size);
+ if (lpsinfo == NULL) {
+ bind_err(pset, pid, -1, errno);
+ return (ERR_FAIL);
+ }
+ if (pread(fd, lpsinfo, size, sizeof (header)) != size) {
+ bind_err(pset, pid, -1, errno);
+ free(lpsinfo);
+ (void) close(fd);
+ return (ERR_FAIL);
+ }
+
+ if ((bflag || uflag) && (Pr = grab_proc(pid)) == NULL) {
+ free(lpsinfo);
+ (void) close(fd);
+ return (ERR_FAIL);
+ }
+ found = 0;
+ for (i = 0; i < nent; i++, ptr += header.pr_entsize) {
+ /*LINTED ALIGNMENT*/
+ lwp = (lwpsinfo_t *)ptr;
+ binding = lwp->pr_bindpset;
+ if (!proc_lwp_in_set(range, lwp->pr_lwpid))
+ continue;
+ found++;
+ if (bflag || uflag)
+ bind_lwp(Pr, pid, lwp->pr_lwpid, pset);
+ else if (binding != PBIND_NONE)
+ query_out(pid, lwp->pr_lwpid, binding);
+ }
+ if (bflag || uflag)
+ rele_proc(Pr);
+ free(lpsinfo);
+ (void) close(fd);
+ if (found == 0) {
+ warn(gettext("cannot %s lwpid %d/%s: "
+ "No matching LWPs found\n"),
+ bflag ? "bind" : "query", pid, range);
+ return (ERR_FAIL);
+ }
+ return (ERR_OK);
+}
+
+int
+main(int argc, char *argv[])
+{
+ extern int optind;
+ int c;
+ id_t pid;
+ processorid_t cpu;
+ psetid_t pset, old_pset;
+ char *errptr;
+
+ progname = argv[0]; /* put actual command name in messages */
+
+ (void) setlocale(LC_ALL, ""); /* setup localization */
+ (void) textdomain(TEXT_DOMAIN);
+
+ while ((c = getopt(argc, argv, "cdFarpibqQuUnfe")) != EOF) {
+ switch (c) {
+ case 'c':
+ cflag = 1;
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'e':
+ eflag = 1;
+ break;
+ case 'a':
+ aflag = 1;
+ break;
+ case 'r':
+ rflag = 1;
+ pset = PS_NONE;
+ break;
+ case 'p':
+ pflag = 1;
+ pset = PS_QUERY;
+ break;
+ case 'i':
+ iflag = 1;
+ break;
+ case 'b':
+ bflag = 1;
+ break;
+ case 'u':
+ uflag = 1;
+ pset = PS_NONE;
+ break;
+ case 'U':
+ Uflag = 1;
+ break;
+ case 'q':
+ qflag = 1;
+ pset = PS_QUERY;
+ break;
+ case 'Q':
+ Qflag = 1;
+ break;
+ case 'f':
+ fflag = 1;
+ break;
+ case 'F':
+ Fflag = 1;
+ break;
+ case 'n':
+ nflag = 1;
+ break;
+ default:
+ return (usage());
+ }
+ }
+
+ /*
+ * Make sure that at most one of the options was specified.
+ */
+ c = cflag + dflag + aflag + rflag + pflag +
+ iflag + bflag + uflag + Uflag +
+ qflag + Qflag + fflag + nflag + eflag;
+ if (c < 1) { /* nothing specified */
+ iflag = 1; /* default is to get info */
+ } else if (c > 1) {
+ warn(gettext("options are mutually exclusive\n"));
+ return (usage());
+ }
+
+ if (Fflag && (cflag + aflag + rflag == 0))
+ return (usage());
+
+ errors = 0;
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0) {
+ /*
+ * Handle single option cases.
+ */
+ if (qflag) {
+ (void) proc_walk(query_all_proc, NULL, PR_WALK_PROC);
+ return (errors);
+ }
+ if (Qflag) {
+ (void) proc_walk(query_all_lwp, NULL, PR_WALK_LWP);
+ return (errors);
+ }
+ if (Uflag) {
+ if (pset_bind(PS_NONE, P_ALL, 0, &old_pset) != 0)
+ die(gettext("failed to unbind all LWPs"));
+ }
+ if (pflag)
+ return (print_all());
+ if (iflag)
+ return (info_all());
+ }
+
+ /*
+ * Get processor set id.
+ */
+ if (aflag || bflag || fflag || nflag || eflag) {
+ if (argc < 1) {
+ /* must specify processor set */
+ warn(gettext("must specify processor set\n"));
+ return (usage());
+ }
+ pset = strtol(*argv, &errptr, 10);
+ if (errptr != NULL && *errptr != '\0' || pset < 0) {
+ warn(gettext("invalid processor set ID %s\n"), *argv);
+ return (ERR_FAIL);
+ }
+ argv++;
+ argc--;
+ }
+
+ if (cflag) {
+ if (pset_create(&pset) != 0) {
+ warn(gettext("could not create processor set"));
+ return (ERR_FAIL);
+ } else {
+ create_out(pset);
+ if (argc == 0)
+ return (ERR_OK);
+ }
+ } else if (iflag || dflag) {
+ if (argc == 0) {
+ warn(gettext("must specify at least one "
+ "processor set\n"));
+ return (usage());
+ }
+ /*
+ * Go through listed processor sets.
+ */
+ for (; argc > 0; argv++, argc--) {
+ pset = (psetid_t)strtol(*argv, &errptr, 10);
+ if (errptr != NULL && *errptr != '\0') {
+ warn(gettext("invalid processor set ID %s\n"),
+ *argv);
+ errors = ERR_FAIL;
+ continue;
+ }
+ if (iflag) {
+ errors = do_info(pset);
+ } else {
+ errors = do_destroy(pset);
+ }
+ }
+ } else if (nflag) {
+ errors = do_intr(pset, P_ONLINE);
+ } else if (fflag) {
+ errors = do_intr(pset, P_NOINTR);
+ } else if (eflag) {
+ if (argc == 0) {
+ warn(gettext("must specify command\n"));
+ return (usage());
+ }
+ exec_cmd(pset, argv);
+ /* if returning, must have had an error */
+ return (ERR_USAGE);
+ }
+
+ if (cflag || aflag || rflag || pflag) {
+ /*
+ * Perform function for each processor specified.
+ */
+ if (argc == 0) {
+ warn(gettext("must specify at least one processor\n"));
+ return (usage());
+ }
+
+ /*
+ * Go through listed processors.
+ */
+ for (; argc > 0; argv++, argc--) {
+ if (strchr(*argv, '-') == NULL) {
+ /* individual processor id */
+ cpu = (processorid_t)strtol(*argv, &errptr, 10);
+ if (errptr != NULL && *errptr != '\0') {
+ warn(gettext("invalid processor "
+ "ID %s\n"), *argv);
+ errors = ERR_FAIL;
+ continue;
+ }
+ if (do_cpu(pset, cpu, pflag, 1))
+ errors = ERR_FAIL;
+ } else {
+ /* range of processors */
+ processorid_t first, last;
+
+ first = (processorid_t)
+ strtol(*argv, &errptr, 10);
+ if (*errptr++ != '-') {
+ warn(gettext(
+ "invalid processor range %s\n"),
+ *argv);
+ errors = ERR_USAGE;
+ continue;
+ }
+ last = (processorid_t)
+ strtol(errptr, &errptr, 10);
+ if ((errptr != NULL && *errptr != '\0') ||
+ last < first || first < 0) {
+ warn(gettext(
+ "invalid processor range %s\n"),
+ *argv);
+ errors = ERR_USAGE;
+ continue;
+ }
+ if (do_range(pset, first, last, pflag))
+ errors = ERR_FAIL;
+ }
+ }
+ } else if (bflag || uflag || qflag) {
+ /*
+ * Perform function for each pid/lwpid specified.
+ */
+ if (argc == 0) {
+ warn(gettext("must specify at least one pid\n"));
+ return (usage());
+ }
+
+ /*
+ * Go through listed processes/lwp_ranges.
+ */
+ for (; argc > 0; argv++, argc--) {
+ pid = (id_t)strtol(*argv, &errptr, 10);
+ if (errno != 0 ||
+ (errptr != NULL && *errptr != '\0' &&
+ *errptr != '/')) {
+ warn(gettext("invalid process ID: %s\n"),
+ *argv);
+ continue;
+ }
+ if (errptr != NULL && *errptr == '/') {
+ int ret;
+ /*
+ * Handle lwp range case
+ */
+ const char *lwps = (const char *)(++errptr);
+ if (*lwps == '\0' ||
+ proc_lwp_range_valid(lwps) != 0) {
+ warn(gettext("invalid lwp range "
+ "for pid %d\n"), (int)pid);
+ errors = ERR_FAIL;
+ continue;
+ }
+ if (!qflag)
+ (void) proc_initstdio();
+ ret = do_lwps(pid, lwps, pset);
+ if (!qflag)
+ (void) proc_finistdio();
+ if (ret != ERR_OK)
+ errors = ret;
+ } else {
+ /*
+ * Handle whole process case.
+ */
+ if (pset_bind(pset, P_PID, pid,
+ &old_pset) < 0) {
+ bind_err(pset, pid, -1, errno);
+ errors = ERR_FAIL;
+ continue;
+ }
+ if (qflag)
+ query_out(pid, -1, old_pset);
+ else
+ bind_out(pid, -1, old_pset, pset);
+ }
+ }
+ }
+
+ if (Qflag || Uflag) {
+ /*
+ * Go through listed processor set IDs.
+ */
+ for (; argc > 0; argv++, argc--) {
+ errno = 0;
+ pset = (id_t)strtol(*argv, &errptr, 10);
+ if (errno != 0 ||
+ (errptr != NULL && *errptr != '\0')) {
+ warn(gettext("invalid processor set ID\n"));
+ continue;
+ }
+ if (Qflag) {
+ (void) proc_walk(query_all_lwp,
+ &pset, PR_WALK_LWP);
+ continue;
+ }
+ if (Uflag) {
+ if (pset_bind(PS_NONE, P_PSETID, pset,
+ &old_pset) != 0) {
+ warn(gettext("failed to unbind from "
+ "processor set %d"), (int)pset);
+ errors = ERR_FAIL;
+ }
+ continue;
+ }
+ }
+ }
+
+ return (errors);
+}
diff --git a/usr/src/cmd/psrset/sparcv9/Makefile b/usr/src/cmd/psrset/sparcv9/Makefile
new file mode 100644
index 0000000000..cb9242dfff
--- /dev/null
+++ b/usr/src/cmd/psrset/sparcv9/Makefile
@@ -0,0 +1,35 @@
+#
+# 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 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/psrset/sparcv9/Makefile
+#
+
+include ../Makefile.com
+include ../../Makefile.cmd.64
+
+install: all $(ROOTUSRSBINPROG64)
+