xref: /titanic_54/usr/src/cmd/ptools/plgrp/plgrp.c (revision c64027834c5ffc60c557c2b12555e0cd4d30320c)
1*c6402783Sakolb /*
2*c6402783Sakolb  * CDDL HEADER START
3*c6402783Sakolb  *
4*c6402783Sakolb  * The contents of this file are subject to the terms of the
5*c6402783Sakolb  * Common Development and Distribution License (the "License").
6*c6402783Sakolb  * You may not use this file except in compliance with the License.
7*c6402783Sakolb  *
8*c6402783Sakolb  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*c6402783Sakolb  * or http://www.opensolaris.org/os/licensing.
10*c6402783Sakolb  * See the License for the specific language governing permissions
11*c6402783Sakolb  * and limitations under the License.
12*c6402783Sakolb  *
13*c6402783Sakolb  * When distributing Covered Code, include this CDDL HEADER in each
14*c6402783Sakolb  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*c6402783Sakolb  * If applicable, add the following below this CDDL HEADER, with the
16*c6402783Sakolb  * fields enclosed by brackets "[]" replaced with your own identifying
17*c6402783Sakolb  * information: Portions Copyright [yyyy] [name of copyright owner]
18*c6402783Sakolb  *
19*c6402783Sakolb  * CDDL HEADER END
20*c6402783Sakolb  */
21*c6402783Sakolb 
22*c6402783Sakolb /*
23*c6402783Sakolb  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*c6402783Sakolb  * Use is subject to license terms.
25*c6402783Sakolb  */
26*c6402783Sakolb 
27*c6402783Sakolb #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*c6402783Sakolb 
29*c6402783Sakolb /*
30*c6402783Sakolb  * The plgrp utility allows a user to display and modify the home lgroup and
31*c6402783Sakolb  * lgroup affinities of the specified threads
32*c6402783Sakolb  */
33*c6402783Sakolb 
34*c6402783Sakolb #include <ctype.h>
35*c6402783Sakolb #include <errno.h>
36*c6402783Sakolb #include <libintl.h>
37*c6402783Sakolb #include <libproc.h>
38*c6402783Sakolb #include <locale.h>
39*c6402783Sakolb #include <signal.h>
40*c6402783Sakolb #include <stdio.h>
41*c6402783Sakolb #include <stdlib.h>
42*c6402783Sakolb #include <strings.h>
43*c6402783Sakolb #include <unistd.h>
44*c6402783Sakolb #include <libgen.h>
45*c6402783Sakolb #include <sys/lgrp_user.h>
46*c6402783Sakolb 
47*c6402783Sakolb 
48*c6402783Sakolb /*
49*c6402783Sakolb  * Delimiters
50*c6402783Sakolb  */
51*c6402783Sakolb #define	DELIMIT_AFF	'/'	/* lgroup affinity from lgroups */
52*c6402783Sakolb #define	DELIMIT_LGRP	","	/* lgroups from each other */
53*c6402783Sakolb #define	DELIMIT_LWP	"/"	/* thread/LWP IDs from process ID */
54*c6402783Sakolb #define	DELIMIT_RANGE	'-'	/* range of IDs (eg. lgroup) */
55*c6402783Sakolb #define	DELIMIT_AFF_LST ','	/* list of affinities from another list */
56*c6402783Sakolb 
57*c6402783Sakolb /*
58*c6402783Sakolb  * Exit values other than EXIT_{SUCCESS,FAILURE}
59*c6402783Sakolb  */
60*c6402783Sakolb #define	EXIT_NONFATAL 2		/* non-fatal errors */
61*c6402783Sakolb 
62*c6402783Sakolb /*
63*c6402783Sakolb  * Header and format strings
64*c6402783Sakolb  */
65*c6402783Sakolb #define	HDR_PLGRP_AFF_GET	"     PID/LWPID    HOME  AFFINITY\n"
66*c6402783Sakolb #define	HDR_PLGRP_AFF_SET	"     PID/LWPID    HOME       AFFINITY\n"
67*c6402783Sakolb #define	HDR_PLGRP_HOME_GET	"     PID/LWPID    HOME\n"
68*c6402783Sakolb #define	HDR_PLGRP_HOME_SET	"     PID/LWPID    HOME\n"
69*c6402783Sakolb 
70*c6402783Sakolb /*
71*c6402783Sakolb  * Part of the HDR_PLGRP_AFF_SET header used to calculate space needed to
72*c6402783Sakolb  * represent changing home as old => new
73*c6402783Sakolb  */
74*c6402783Sakolb #define	HDR_PLGRP_HOME_CHANGE	"HOME       "
75*c6402783Sakolb 
76*c6402783Sakolb #define	FMT_AFF			"%d/%s"
77*c6402783Sakolb #define	FMT_AFF_STR		"%s"
78*c6402783Sakolb #define	FMT_HOME		"%-6d"
79*c6402783Sakolb #define	FMT_NEWHOME		"%d => %d"
80*c6402783Sakolb #define	FMT_THREAD		"%8d/%-8d"
81*c6402783Sakolb 
82*c6402783Sakolb /*
83*c6402783Sakolb  * How much to allocate for lgroup bitmap array as it grows
84*c6402783Sakolb  */
85*c6402783Sakolb #define	LGRP_BITMAP_CHUNK 8
86*c6402783Sakolb 
87*c6402783Sakolb /*
88*c6402783Sakolb  * Strings that can be given for lgroups
89*c6402783Sakolb  */
90*c6402783Sakolb #define	LGRP_ALL_STR		"all"
91*c6402783Sakolb #define	LGRP_LEAVES_STR		"leaves"
92*c6402783Sakolb #define	LGRP_ROOT_STR		"root"
93*c6402783Sakolb 
94*c6402783Sakolb /*
95*c6402783Sakolb  * Strings corresponding to lgroup affinities
96*c6402783Sakolb  */
97*c6402783Sakolb #define	LGRP_AFF_NONE_STR	"none"
98*c6402783Sakolb #define	LGRP_AFF_STRONG_STR	"strong"
99*c6402783Sakolb #define	LGRP_AFF_WEAK_STR	"weak"
100*c6402783Sakolb 
101*c6402783Sakolb /*
102*c6402783Sakolb  * Invalid value for lgroup affinity
103*c6402783Sakolb  */
104*c6402783Sakolb #define	LGRP_AFF_INVALID	-1
105*c6402783Sakolb 
106*c6402783Sakolb /*
107*c6402783Sakolb  * Number of args needed for lgroup system call
108*c6402783Sakolb  */
109*c6402783Sakolb #define	LGRPSYS_NARGS		3
110*c6402783Sakolb 
111*c6402783Sakolb #ifndef	TEXT_DOMAIN			/* should be defined by cc -D */
112*c6402783Sakolb #define	TEXT_DOMAIN	"SYS_TEST"	/* use this only if it wasn't */
113*c6402783Sakolb #endif
114*c6402783Sakolb 
115*c6402783Sakolb /*
116*c6402783Sakolb  * plgrp(1) operations
117*c6402783Sakolb  */
118*c6402783Sakolb typedef enum plgrp_ops {
119*c6402783Sakolb 	PLGRP_AFFINITY_GET,
120*c6402783Sakolb 	PLGRP_AFFINITY_SET,
121*c6402783Sakolb 	PLGRP_HOME_GET,
122*c6402783Sakolb 	PLGRP_HOME_SET,
123*c6402783Sakolb 	PLGRP_NO_OP
124*c6402783Sakolb } plgrp_ops_t;
125*c6402783Sakolb 
126*c6402783Sakolb /*
127*c6402783Sakolb  * Arguments specified to plgrp(1) and any state needed to do everything
128*c6402783Sakolb  * that plgrp(1) does for one operation from inside Plwp_iter_all()
129*c6402783Sakolb  */
130*c6402783Sakolb typedef struct plgrp_args {
131*c6402783Sakolb 	struct ps_prochandle	*Ph;		/* proc handle for process */
132*c6402783Sakolb 	const char		*lwps;		/* LWPs */
133*c6402783Sakolb 	lgrp_id_t		*lgrps;		/* lgroups */
134*c6402783Sakolb 	lgrp_affinity_t		*affs;		/* lgroup affinities */
135*c6402783Sakolb 	int			nlgrps;		/* number of lgroups */
136*c6402783Sakolb 	int			nelements;	/* number of elements */
137*c6402783Sakolb 	int			index;		/* index */
138*c6402783Sakolb 	int			nthreads;	/* threads processed */
139*c6402783Sakolb 	plgrp_ops_t		op;		/* operation */
140*c6402783Sakolb } plgrp_args_t;
141*c6402783Sakolb 
142*c6402783Sakolb /*
143*c6402783Sakolb  * How many signals caught from terminal
144*c6402783Sakolb  * We bail out as soon as possible when interrupt is set
145*c6402783Sakolb  */
146*c6402783Sakolb static int	interrupt = 0;
147*c6402783Sakolb 
148*c6402783Sakolb /*
149*c6402783Sakolb  * How many non-fatal errors ocurred
150*c6402783Sakolb  */
151*c6402783Sakolb static int	nerrors = 0;
152*c6402783Sakolb 
153*c6402783Sakolb /*
154*c6402783Sakolb  * Name of this program
155*c6402783Sakolb  */
156*c6402783Sakolb static char	*progname;
157*c6402783Sakolb 
158*c6402783Sakolb /*
159*c6402783Sakolb  * Root of the lgroup hierarchy
160*c6402783Sakolb  */
161*c6402783Sakolb static lgrp_id_t root = LGRP_NONE;
162*c6402783Sakolb 
163*c6402783Sakolb /*
164*c6402783Sakolb  * Bitmap of all lgroups in the system
165*c6402783Sakolb  */
166*c6402783Sakolb static char *lgrps_bitmap = NULL;
167*c6402783Sakolb 
168*c6402783Sakolb /*
169*c6402783Sakolb  * Size of lgrps_bitmap array
170*c6402783Sakolb  */
171*c6402783Sakolb static int lgrps_bitmap_nelements = 0;
172*c6402783Sakolb 
173*c6402783Sakolb /*
174*c6402783Sakolb  * Macro LGRP_VALID returns true when lgrp is present in the system.
175*c6402783Sakolb  */
176*c6402783Sakolb #define	LGRP_VALID(lgrp) (lgrps_bitmap[lgrp] != 0)
177*c6402783Sakolb 
178*c6402783Sakolb 
179*c6402783Sakolb /*
180*c6402783Sakolb  * Maximum lgroup value.
181*c6402783Sakolb  */
182*c6402783Sakolb static int max_lgrpid = LGRP_NONE;
183*c6402783Sakolb 
184*c6402783Sakolb /*
185*c6402783Sakolb  * Total possible number of lgroups
186*c6402783Sakolb  */
187*c6402783Sakolb #define	NLGRPS (max_lgrpid + 1)
188*c6402783Sakolb 
189*c6402783Sakolb 
190*c6402783Sakolb static void
191*c6402783Sakolb usage(int rc)
192*c6402783Sakolb {
193*c6402783Sakolb 	(void) fprintf(stderr,
194*c6402783Sakolb 	    gettext("Usage:\t%s [-h] <pid> | <core> [/lwps] ...\n"), progname);
195*c6402783Sakolb 	(void) fprintf(stderr,
196*c6402783Sakolb 	    gettext("\t%s [-F] -a <lgroup list> <pid>[/lwps] ...\n"), progname);
197*c6402783Sakolb 	(void) fprintf(stderr,
198*c6402783Sakolb 	    gettext("\t%s [-F] -A <lgroup list>/none|weak|strong[,...] "
199*c6402783Sakolb 	    " <pid>[/lwps] ...\n"), progname);
200*c6402783Sakolb 	(void) fprintf(stderr,
201*c6402783Sakolb 	    gettext("\t%s [-F] -H <lgroup list> <pid>[/lwps] ...\n"), progname);
202*c6402783Sakolb 	(void) fprintf(stderr,
203*c6402783Sakolb 	    gettext("\n\twhere <lgroup list> is a comma separated list of\n"
204*c6402783Sakolb 		"\tone or more of the following:\n\n"
205*c6402783Sakolb 		"\t  - lgroup ID\n"
206*c6402783Sakolb 		"\t  - Range of lgroup IDs specified as\n"
207*c6402783Sakolb 		"\t\t<start lgroup ID>-<end lgroup ID>\n"
208*c6402783Sakolb 		"\t  - \"all\"\n"
209*c6402783Sakolb 		"\t  - \"root\"\n"
210*c6402783Sakolb 		"\t  - \"leaves\"\n\n"));
211*c6402783Sakolb 
212*c6402783Sakolb 	exit(rc);
213*c6402783Sakolb }
214*c6402783Sakolb 
215*c6402783Sakolb /*
216*c6402783Sakolb  * Handler for catching signals from terminal
217*c6402783Sakolb  */
218*c6402783Sakolb /* ARGSUSED */
219*c6402783Sakolb static void
220*c6402783Sakolb intr(int sig)
221*c6402783Sakolb {
222*c6402783Sakolb 	interrupt++;
223*c6402783Sakolb }
224*c6402783Sakolb 
225*c6402783Sakolb 
226*c6402783Sakolb /*
227*c6402783Sakolb  * Return string name for given lgroup affinity
228*c6402783Sakolb  */
229*c6402783Sakolb static char *
230*c6402783Sakolb lgrp_affinity_string(lgrp_affinity_t aff)
231*c6402783Sakolb {
232*c6402783Sakolb 	char *rc = "unknown";
233*c6402783Sakolb 
234*c6402783Sakolb 	switch (aff) {
235*c6402783Sakolb 	case LGRP_AFF_STRONG:
236*c6402783Sakolb 		rc = "strong";
237*c6402783Sakolb 		break;
238*c6402783Sakolb 	case LGRP_AFF_WEAK:
239*c6402783Sakolb 		rc = "weak";
240*c6402783Sakolb 		break;
241*c6402783Sakolb 	case LGRP_AFF_NONE:
242*c6402783Sakolb 		rc = "none";
243*c6402783Sakolb 		break;
244*c6402783Sakolb 	default:
245*c6402783Sakolb 		break;
246*c6402783Sakolb 	}
247*c6402783Sakolb 
248*c6402783Sakolb 	return (rc);
249*c6402783Sakolb }
250*c6402783Sakolb 
251*c6402783Sakolb 
252*c6402783Sakolb /*
253*c6402783Sakolb  * Add a new lgroup into lgroup array in "arg", growing lgroup and affinity
254*c6402783Sakolb  * arrays if necessary
255*c6402783Sakolb  */
256*c6402783Sakolb static void
257*c6402783Sakolb lgrps_add_lgrp(plgrp_args_t *arg, int id)
258*c6402783Sakolb {
259*c6402783Sakolb 
260*c6402783Sakolb 	if (arg->nlgrps == arg->nelements) {
261*c6402783Sakolb 		arg->nelements += LGRP_BITMAP_CHUNK;
262*c6402783Sakolb 
263*c6402783Sakolb 		arg->lgrps = realloc(arg->lgrps,
264*c6402783Sakolb 		    arg->nelements * sizeof (lgrp_id_t));
265*c6402783Sakolb 		if (arg->lgrps == NULL) {
266*c6402783Sakolb 			(void) fprintf(stderr, gettext("%s: out of memory\n"),
267*c6402783Sakolb 			    progname);
268*c6402783Sakolb 			exit(EXIT_FAILURE);
269*c6402783Sakolb 		}
270*c6402783Sakolb 
271*c6402783Sakolb 		arg->affs = realloc(arg->affs,
272*c6402783Sakolb 		    arg->nelements * sizeof (lgrp_affinity_t));
273*c6402783Sakolb 
274*c6402783Sakolb 		if (arg->affs == NULL) {
275*c6402783Sakolb 			(void) fprintf(stderr, gettext("%s: out of memory\n"),
276*c6402783Sakolb 			    progname);
277*c6402783Sakolb 			exit(EXIT_FAILURE);
278*c6402783Sakolb 		}
279*c6402783Sakolb 	}
280*c6402783Sakolb 
281*c6402783Sakolb 	arg->lgrps[arg->nlgrps] = id;
282*c6402783Sakolb 	arg->affs[arg->nlgrps] = LGRP_AFF_INVALID;
283*c6402783Sakolb 	arg->nlgrps++;
284*c6402783Sakolb }
285*c6402783Sakolb 
286*c6402783Sakolb 
287*c6402783Sakolb /*
288*c6402783Sakolb  * Return an array having '1' for each lgroup present in given subtree under
289*c6402783Sakolb  * specified lgroup in lgroup hierarchy
290*c6402783Sakolb  */
291*c6402783Sakolb static void
292*c6402783Sakolb lgrps_bitmap_init(lgrp_cookie_t cookie, lgrp_id_t lgrpid, char **bitmap_array,
293*c6402783Sakolb 	int *bitmap_nelements)
294*c6402783Sakolb {
295*c6402783Sakolb 	lgrp_id_t	*children;
296*c6402783Sakolb 	int		i;
297*c6402783Sakolb 	int		nchildren;
298*c6402783Sakolb 
299*c6402783Sakolb 	if (lgrpid < 0) {
300*c6402783Sakolb 		lgrpid = lgrp_root(cookie);
301*c6402783Sakolb 		if (lgrpid < 0)
302*c6402783Sakolb 			return;
303*c6402783Sakolb 	}
304*c6402783Sakolb 
305*c6402783Sakolb 	/*
306*c6402783Sakolb 	 * If new lgroup cannot fit, grow the array and fill unused portion
307*c6402783Sakolb 	 * with zeroes.
308*c6402783Sakolb 	 */
309*c6402783Sakolb 	while (lgrpid >= *bitmap_nelements) {
310*c6402783Sakolb 		*bitmap_nelements += LGRP_BITMAP_CHUNK;
311*c6402783Sakolb 		*bitmap_array = realloc(*bitmap_array,
312*c6402783Sakolb 		    *bitmap_nelements * sizeof (char));
313*c6402783Sakolb 		if (*bitmap_array == NULL) {
314*c6402783Sakolb 			(void) fprintf(stderr, gettext("%s: out of memory\n"),
315*c6402783Sakolb 			    progname);
316*c6402783Sakolb 			exit(EXIT_FAILURE);
317*c6402783Sakolb 		}
318*c6402783Sakolb 		bzero(*bitmap_array + NLGRPS,
319*c6402783Sakolb 		    (*bitmap_nelements - NLGRPS) * sizeof (char));
320*c6402783Sakolb 	}
321*c6402783Sakolb 
322*c6402783Sakolb 	/*
323*c6402783Sakolb 	 * Insert lgroup into bitmap and update max lgroup ID seen so far
324*c6402783Sakolb 	 */
325*c6402783Sakolb 	(*bitmap_array)[lgrpid] = 1;
326*c6402783Sakolb 	if (lgrpid > max_lgrpid)
327*c6402783Sakolb 		max_lgrpid = lgrpid;
328*c6402783Sakolb 
329*c6402783Sakolb 	/*
330*c6402783Sakolb 	 * Get children of specified lgroup and insert descendants of each
331*c6402783Sakolb 	 * of them
332*c6402783Sakolb 	 */
333*c6402783Sakolb 	nchildren = lgrp_children(cookie, lgrpid, NULL, 0);
334*c6402783Sakolb 	if (nchildren > 0) {
335*c6402783Sakolb 		children = malloc(nchildren * sizeof (lgrp_id_t));
336*c6402783Sakolb 		if (children == NULL) {
337*c6402783Sakolb 			(void) fprintf(stderr, gettext("%s: out of memory\n"),
338*c6402783Sakolb 			    progname);
339*c6402783Sakolb 			exit(EXIT_FAILURE);
340*c6402783Sakolb 		}
341*c6402783Sakolb 		if (lgrp_children(cookie, lgrpid, children, nchildren) !=
342*c6402783Sakolb 		    nchildren) {
343*c6402783Sakolb 			free(children);
344*c6402783Sakolb 			return;
345*c6402783Sakolb 		}
346*c6402783Sakolb 
347*c6402783Sakolb 		for (i = 0; i < nchildren; i++)
348*c6402783Sakolb 			lgrps_bitmap_init(cookie, children[i], bitmap_array,
349*c6402783Sakolb 			    bitmap_nelements);
350*c6402783Sakolb 
351*c6402783Sakolb 		free(children);
352*c6402783Sakolb 	}
353*c6402783Sakolb }
354*c6402783Sakolb 
355*c6402783Sakolb 
356*c6402783Sakolb /*
357*c6402783Sakolb  * Parse lgroup affinity from given string
358*c6402783Sakolb  *
359*c6402783Sakolb  * Return lgroup affinity or LGRP_AFF_INVALID if string doesn't match any
360*c6402783Sakolb  * existing lgroup affinity and return pointer to position just after affinity
361*c6402783Sakolb  * string.
362*c6402783Sakolb  */
363*c6402783Sakolb static lgrp_affinity_t
364*c6402783Sakolb parse_lgrp_affinity(char *string, char  **next)
365*c6402783Sakolb {
366*c6402783Sakolb 	int rc = LGRP_AFF_INVALID;
367*c6402783Sakolb 
368*c6402783Sakolb 	if (string == NULL)
369*c6402783Sakolb 		return (LGRP_AFF_INVALID);
370*c6402783Sakolb 
371*c6402783Sakolb 	/*
372*c6402783Sakolb 	 * Skip delimiter
373*c6402783Sakolb 	 */
374*c6402783Sakolb 	if (string[0] == DELIMIT_AFF)
375*c6402783Sakolb 		string++;
376*c6402783Sakolb 
377*c6402783Sakolb 	/*
378*c6402783Sakolb 	 * Return lgroup affinity matching string
379*c6402783Sakolb 	 */
380*c6402783Sakolb 	if (strncmp(string, LGRP_AFF_NONE_STR, strlen(LGRP_AFF_NONE_STR))
381*c6402783Sakolb 	    == 0) {
382*c6402783Sakolb 		rc = LGRP_AFF_NONE;
383*c6402783Sakolb 		*next = string + strlen(LGRP_AFF_NONE_STR);
384*c6402783Sakolb 	} else if (strncmp(string,
385*c6402783Sakolb 			LGRP_AFF_WEAK_STR, strlen(LGRP_AFF_WEAK_STR)) == 0) {
386*c6402783Sakolb 		rc = LGRP_AFF_WEAK;
387*c6402783Sakolb 		*next = string + strlen(LGRP_AFF_WEAK_STR);
388*c6402783Sakolb 	} else if (strncmp(string, LGRP_AFF_STRONG_STR,
389*c6402783Sakolb 			strlen(LGRP_AFF_STRONG_STR)) == 0) {
390*c6402783Sakolb 		rc = LGRP_AFF_STRONG;
391*c6402783Sakolb 		*next = string + strlen(LGRP_AFF_STRONG_STR);
392*c6402783Sakolb 	}
393*c6402783Sakolb 
394*c6402783Sakolb 	return (rc);
395*c6402783Sakolb }
396*c6402783Sakolb 
397*c6402783Sakolb 
398*c6402783Sakolb /*
399*c6402783Sakolb  * Parse lgroups from given string
400*c6402783Sakolb  * Returns the set containing all lgroups parsed or NULL.
401*c6402783Sakolb  */
402*c6402783Sakolb static int
403*c6402783Sakolb parse_lgrps(lgrp_cookie_t cookie, plgrp_args_t *arg, char *s)
404*c6402783Sakolb {
405*c6402783Sakolb 	lgrp_id_t	i;
406*c6402783Sakolb 	char		*token;
407*c6402783Sakolb 
408*c6402783Sakolb 	if (cookie == LGRP_COOKIE_NONE || s == NULL || NLGRPS <= 0)
409*c6402783Sakolb 		return (0);
410*c6402783Sakolb 
411*c6402783Sakolb 	/*
412*c6402783Sakolb 	 * Parse first lgroup (if any)
413*c6402783Sakolb 	 */
414*c6402783Sakolb 	token = strtok(s, DELIMIT_LGRP);
415*c6402783Sakolb 	if (token == NULL)
416*c6402783Sakolb 		return (-1);
417*c6402783Sakolb 
418*c6402783Sakolb 	do {
419*c6402783Sakolb 		/*
420*c6402783Sakolb 		 * Parse lgroups
421*c6402783Sakolb 		 */
422*c6402783Sakolb 		if (isdigit(*token)) {
423*c6402783Sakolb 			lgrp_id_t	first;
424*c6402783Sakolb 			lgrp_id_t	last;
425*c6402783Sakolb 			char		*p;
426*c6402783Sakolb 
427*c6402783Sakolb 			/*
428*c6402783Sakolb 			 * lgroup ID(s)
429*c6402783Sakolb 			 *
430*c6402783Sakolb 			 * Can be <lgroup ID>[-<lgroup ID>]
431*c6402783Sakolb 			 */
432*c6402783Sakolb 			p = strchr(token, DELIMIT_RANGE);
433*c6402783Sakolb 			first = atoi(token);
434*c6402783Sakolb 			if (p == NULL)
435*c6402783Sakolb 				last = first;
436*c6402783Sakolb 			else
437*c6402783Sakolb 				last = atoi(++p);
438*c6402783Sakolb 
439*c6402783Sakolb 			for (i = first; i <= last; i++) {
440*c6402783Sakolb 				/*
441*c6402783Sakolb 				 * Add valid lgroups to lgroup array
442*c6402783Sakolb 				 */
443*c6402783Sakolb 				if ((i >= 0) && (i < NLGRPS) && LGRP_VALID(i))
444*c6402783Sakolb 					lgrps_add_lgrp(arg, i);
445*c6402783Sakolb 				else  {
446*c6402783Sakolb 					(void) fprintf(stderr,
447*c6402783Sakolb 					    gettext("%s: bad lgroup %d\n"),
448*c6402783Sakolb 					    progname, i);
449*c6402783Sakolb 					nerrors++;
450*c6402783Sakolb 				}
451*c6402783Sakolb 			}
452*c6402783Sakolb 		} else if (strncmp(token, LGRP_ALL_STR,
453*c6402783Sakolb 				strlen(LGRP_ALL_STR)) == 0) {
454*c6402783Sakolb 			/*
455*c6402783Sakolb 			 * Add "all" lgroups to lgroups array
456*c6402783Sakolb 			 */
457*c6402783Sakolb 			for (i = 0; i < NLGRPS; i++) {
458*c6402783Sakolb 				if (LGRP_VALID(i))
459*c6402783Sakolb 					lgrps_add_lgrp(arg, i);
460*c6402783Sakolb 			}
461*c6402783Sakolb 		} else if (strncmp(token, LGRP_ROOT_STR,
462*c6402783Sakolb 				strlen(LGRP_ROOT_STR)) == 0) {
463*c6402783Sakolb 			if (root < 0)
464*c6402783Sakolb 				root = lgrp_root(cookie);
465*c6402783Sakolb 			lgrps_add_lgrp(arg, root);
466*c6402783Sakolb 		} else if (strncmp(token, LGRP_LEAVES_STR,
467*c6402783Sakolb 		    strlen(LGRP_LEAVES_STR)) == 0) {
468*c6402783Sakolb 			/*
469*c6402783Sakolb 			 * Add leaf lgroups to lgroups array
470*c6402783Sakolb 			 */
471*c6402783Sakolb 			for (i = 0; i < NLGRPS; i++) {
472*c6402783Sakolb 				if (LGRP_VALID(i) &&
473*c6402783Sakolb 				    lgrp_children(cookie, i, NULL, 0) == 0)
474*c6402783Sakolb 					lgrps_add_lgrp(arg, i);
475*c6402783Sakolb 			}
476*c6402783Sakolb 		} else {
477*c6402783Sakolb 			return (-1);
478*c6402783Sakolb 		}
479*c6402783Sakolb 	} while (token = strtok(NULL, DELIMIT_LGRP));
480*c6402783Sakolb 
481*c6402783Sakolb 	return (0);
482*c6402783Sakolb }
483*c6402783Sakolb 
484*c6402783Sakolb /*
485*c6402783Sakolb  * Print array of lgroup IDs, collapsing any consecutive runs of IDs into a
486*c6402783Sakolb  * range (eg. 2,3,4 into 2-4)
487*c6402783Sakolb  */
488*c6402783Sakolb static void
489*c6402783Sakolb print_lgrps(lgrp_id_t *lgrps, int nlgrps)
490*c6402783Sakolb {
491*c6402783Sakolb 	lgrp_id_t	start;
492*c6402783Sakolb 	lgrp_id_t	end;
493*c6402783Sakolb 	int		i;
494*c6402783Sakolb 
495*c6402783Sakolb 	/*
496*c6402783Sakolb 	 * Initial range consists of the first element
497*c6402783Sakolb 	 */
498*c6402783Sakolb 	start = end = lgrps[0];
499*c6402783Sakolb 
500*c6402783Sakolb 	for (i = 1; i < nlgrps; i++) {
501*c6402783Sakolb 		lgrp_id_t	lgrpid;
502*c6402783Sakolb 
503*c6402783Sakolb 		lgrpid = lgrps[i];
504*c6402783Sakolb 		if (lgrpid == end + 1) {
505*c6402783Sakolb 			/*
506*c6402783Sakolb 			 * Got consecutive lgroup ID, so extend end of range
507*c6402783Sakolb 			 * without printing anything since the range may extend
508*c6402783Sakolb 			 * further
509*c6402783Sakolb 			 */
510*c6402783Sakolb 			end = lgrpid;
511*c6402783Sakolb 		} else {
512*c6402783Sakolb 			/*
513*c6402783Sakolb 			 * Next lgroup ID is not consecutive, so print lgroup
514*c6402783Sakolb 			 * IDs gotten so far.
515*c6402783Sakolb 			 */
516*c6402783Sakolb 			if (end == start) {		/* same value */
517*c6402783Sakolb 				(void) printf("%d,", (int)start);
518*c6402783Sakolb 			} else if (end > start + 1) {	/* range */
519*c6402783Sakolb 				(void) printf("%d-%d,", (int)start, (int)end);
520*c6402783Sakolb 			} else {			/* different values */
521*c6402783Sakolb 				(void) printf("%d,%d,", (int)start, (int)end);
522*c6402783Sakolb 			}
523*c6402783Sakolb 
524*c6402783Sakolb 			/*
525*c6402783Sakolb 			 * Try finding consecutive range starting from this
526*c6402783Sakolb 			 * lgroup ID
527*c6402783Sakolb 			 */
528*c6402783Sakolb 			start = end = lgrpid;
529*c6402783Sakolb 		}
530*c6402783Sakolb 	}
531*c6402783Sakolb 
532*c6402783Sakolb 	/*
533*c6402783Sakolb 	 * Print last lgroup ID(s)
534*c6402783Sakolb 	 */
535*c6402783Sakolb 	if (end == start) {
536*c6402783Sakolb 		(void) printf("%d", (int)start);
537*c6402783Sakolb 	} else if (end > start + 1) {
538*c6402783Sakolb 		(void) printf("%d-%d", (int)start, (int)end);
539*c6402783Sakolb 	} else {
540*c6402783Sakolb 		(void) printf("%d,%d", (int)start, (int)end);
541*c6402783Sakolb 	}
542*c6402783Sakolb }
543*c6402783Sakolb 
544*c6402783Sakolb /*
545*c6402783Sakolb  * Print lgroup affinities given array of lgroups, corresponding array of
546*c6402783Sakolb  * affinities, and number of elements.
547*c6402783Sakolb  * Skip any lgroups set to LGRP_NONE or having invalid affinity.
548*c6402783Sakolb  */
549*c6402783Sakolb static void
550*c6402783Sakolb print_affinities(lgrp_id_t *lgrps, lgrp_affinity_t *affs, int nelements)
551*c6402783Sakolb {
552*c6402783Sakolb 	int		i;
553*c6402783Sakolb 	lgrp_id_t	*lgrps_none;
554*c6402783Sakolb 	lgrp_id_t	*lgrps_strong;
555*c6402783Sakolb 	lgrp_id_t	*lgrps_weak;
556*c6402783Sakolb 	int		nlgrps_none;
557*c6402783Sakolb 	int		nlgrps_strong;
558*c6402783Sakolb 	int		nlgrps_weak;
559*c6402783Sakolb 
560*c6402783Sakolb 	nlgrps_strong = nlgrps_weak = nlgrps_none = 0;
561*c6402783Sakolb 
562*c6402783Sakolb 	lgrps_strong = malloc(nelements * sizeof (lgrp_id_t));
563*c6402783Sakolb 	lgrps_weak = malloc(nelements * sizeof (lgrp_id_t));
564*c6402783Sakolb 	lgrps_none = malloc(nelements * sizeof (lgrp_id_t));
565*c6402783Sakolb 
566*c6402783Sakolb 	if (lgrps_strong == NULL || lgrps_weak == NULL || lgrps_none == NULL) {
567*c6402783Sakolb 		(void) fprintf(stderr, gettext("%s: out of memory\n"),
568*c6402783Sakolb 		    progname);
569*c6402783Sakolb 		interrupt = 1;
570*c6402783Sakolb 		return;
571*c6402783Sakolb 	}
572*c6402783Sakolb 
573*c6402783Sakolb 	/*
574*c6402783Sakolb 	 * Group lgroups by affinity
575*c6402783Sakolb 	 */
576*c6402783Sakolb 	for (i = 0; i < nelements; i++) {
577*c6402783Sakolb 		lgrp_id_t lgrpid = lgrps[i];
578*c6402783Sakolb 
579*c6402783Sakolb 		/*
580*c6402783Sakolb 		 * Skip any lgroups set to LGRP_NONE
581*c6402783Sakolb 		 */
582*c6402783Sakolb 		if (lgrpid == LGRP_NONE)
583*c6402783Sakolb 			continue;
584*c6402783Sakolb 
585*c6402783Sakolb 		switch (affs[i]) {
586*c6402783Sakolb 		case LGRP_AFF_STRONG:
587*c6402783Sakolb 			lgrps_strong[nlgrps_strong++] = lgrpid;
588*c6402783Sakolb 			break;
589*c6402783Sakolb 		case LGRP_AFF_WEAK:
590*c6402783Sakolb 			lgrps_weak[nlgrps_weak++] = lgrpid;
591*c6402783Sakolb 			break;
592*c6402783Sakolb 		case LGRP_AFF_NONE:
593*c6402783Sakolb 			lgrps_none[nlgrps_none++] = lgrpid;
594*c6402783Sakolb 			break;
595*c6402783Sakolb 		default:
596*c6402783Sakolb 			/*
597*c6402783Sakolb 			 * Skip any lgroups with invalid affinity.
598*c6402783Sakolb 			 */
599*c6402783Sakolb 			break;
600*c6402783Sakolb 		}
601*c6402783Sakolb 	}
602*c6402783Sakolb 
603*c6402783Sakolb 	/*
604*c6402783Sakolb 	 * Print all lgroups with same affinity together
605*c6402783Sakolb 	 */
606*c6402783Sakolb 	if (nlgrps_strong) {
607*c6402783Sakolb 		print_lgrps(lgrps_strong, nlgrps_strong);
608*c6402783Sakolb 		(void) printf("/%s", lgrp_affinity_string(LGRP_AFF_STRONG));
609*c6402783Sakolb 		if (nlgrps_weak || nlgrps_none)
610*c6402783Sakolb 			(void) printf("%c", DELIMIT_AFF_LST);
611*c6402783Sakolb 	}
612*c6402783Sakolb 
613*c6402783Sakolb 	if (nlgrps_weak) {
614*c6402783Sakolb 		print_lgrps(lgrps_weak, nlgrps_weak);
615*c6402783Sakolb 		(void) printf("/%s", lgrp_affinity_string(LGRP_AFF_WEAK));
616*c6402783Sakolb 		if (nlgrps_none)
617*c6402783Sakolb 			(void) printf("%c", DELIMIT_AFF_LST);
618*c6402783Sakolb 	}
619*c6402783Sakolb 
620*c6402783Sakolb 	if (nlgrps_none) {
621*c6402783Sakolb 		print_lgrps(lgrps_none, nlgrps_none);
622*c6402783Sakolb 		(void) printf("/%s", lgrp_affinity_string(LGRP_AFF_NONE));
623*c6402783Sakolb 	}
624*c6402783Sakolb 
625*c6402783Sakolb 	free(lgrps_strong);
626*c6402783Sakolb 	free(lgrps_weak);
627*c6402783Sakolb 	free(lgrps_none);
628*c6402783Sakolb }
629*c6402783Sakolb 
630*c6402783Sakolb 
631*c6402783Sakolb /*
632*c6402783Sakolb  * Print heading for specified operation
633*c6402783Sakolb  */
634*c6402783Sakolb static void
635*c6402783Sakolb print_heading(plgrp_ops_t op)
636*c6402783Sakolb {
637*c6402783Sakolb 
638*c6402783Sakolb 	switch (op) {
639*c6402783Sakolb 	case PLGRP_AFFINITY_GET:
640*c6402783Sakolb 		(void) printf(HDR_PLGRP_AFF_GET);
641*c6402783Sakolb 		break;
642*c6402783Sakolb 
643*c6402783Sakolb 	case PLGRP_AFFINITY_SET:
644*c6402783Sakolb 		(void) printf(HDR_PLGRP_AFF_SET);
645*c6402783Sakolb 		break;
646*c6402783Sakolb 
647*c6402783Sakolb 	case PLGRP_HOME_GET:
648*c6402783Sakolb 		(void) printf(HDR_PLGRP_HOME_GET);
649*c6402783Sakolb 		break;
650*c6402783Sakolb 
651*c6402783Sakolb 	case PLGRP_HOME_SET:
652*c6402783Sakolb 		(void) printf(HDR_PLGRP_HOME_SET);
653*c6402783Sakolb 		break;
654*c6402783Sakolb 
655*c6402783Sakolb 	default:
656*c6402783Sakolb 		break;
657*c6402783Sakolb 	}
658*c6402783Sakolb }
659*c6402783Sakolb 
660*c6402783Sakolb /*
661*c6402783Sakolb  * Use /proc to call lgrp_affinity_get() in another process
662*c6402783Sakolb  */
663*c6402783Sakolb static lgrp_affinity_t
664*c6402783Sakolb Plgrp_affinity_get(struct ps_prochandle *Ph, idtype_t idtype, id_t id,
665*c6402783Sakolb     lgrp_id_t lgrp)
666*c6402783Sakolb {
667*c6402783Sakolb 	lgrp_affinity_args_t	args;
668*c6402783Sakolb 	argdes_t		Pargd[3];
669*c6402783Sakolb 	argdes_t		*Pargdp;
670*c6402783Sakolb 	int			Pnargs;
671*c6402783Sakolb 	int			Pretval;
672*c6402783Sakolb 	sysret_t		retval;
673*c6402783Sakolb 	int			syscall;
674*c6402783Sakolb 
675*c6402783Sakolb 	/*
676*c6402783Sakolb 	 * Fill in arguments needed for syscall(SYS_lgrpsys,
677*c6402783Sakolb 	 * LGRP_SYS_AFFINITY_GET, 0, &args)
678*c6402783Sakolb 	 */
679*c6402783Sakolb 	syscall = SYS_lgrpsys;
680*c6402783Sakolb 
681*c6402783Sakolb 	args.idtype = idtype;
682*c6402783Sakolb 	args.id = id;
683*c6402783Sakolb 	args.lgrp = lgrp;
684*c6402783Sakolb 	args.aff = LGRP_AFF_INVALID;
685*c6402783Sakolb 
686*c6402783Sakolb 	/*
687*c6402783Sakolb 	 * Fill out /proc argument descriptors for syscall(SYS_lgrpsys,
688*c6402783Sakolb 	 * LGRP_SYS_AFFINITY_GET, idtype, id)
689*c6402783Sakolb 	 */
690*c6402783Sakolb 	Pnargs = LGRPSYS_NARGS;
691*c6402783Sakolb 	Pargdp = &Pargd[0];
692*c6402783Sakolb 	Pargdp->arg_value = LGRP_SYS_AFFINITY_GET;
693*c6402783Sakolb 	Pargdp->arg_object = NULL;
694*c6402783Sakolb 	Pargdp->arg_type = AT_BYVAL;
695*c6402783Sakolb 	Pargdp->arg_inout = AI_INPUT;
696*c6402783Sakolb 	Pargdp->arg_size = 0;
697*c6402783Sakolb 	Pargdp++;
698*c6402783Sakolb 
699*c6402783Sakolb 	Pargdp->arg_value = 0;
700*c6402783Sakolb 	Pargdp->arg_object = NULL;
701*c6402783Sakolb 	Pargdp->arg_type = AT_BYVAL;
702*c6402783Sakolb 	Pargdp->arg_inout = AI_INPUT;
703*c6402783Sakolb 	Pargdp->arg_size = 0;
704*c6402783Sakolb 	Pargdp++;
705*c6402783Sakolb 
706*c6402783Sakolb 	Pargdp->arg_value = 0;
707*c6402783Sakolb 	Pargdp->arg_object = &args;
708*c6402783Sakolb 	Pargdp->arg_type = AT_BYREF;
709*c6402783Sakolb 	Pargdp->arg_inout = AI_INPUT;
710*c6402783Sakolb 	Pargdp->arg_size = sizeof (lgrp_affinity_args_t);
711*c6402783Sakolb 	Pargdp++;
712*c6402783Sakolb 
713*c6402783Sakolb 	/*
714*c6402783Sakolb 	 * Have agent LWP call syscall with appropriate arguments in target
715*c6402783Sakolb 	 * process
716*c6402783Sakolb 	 */
717*c6402783Sakolb 	Pretval = Psyscall(Ph, &retval, syscall, Pnargs, &Pargd[0]);
718*c6402783Sakolb 	if (Pretval) {
719*c6402783Sakolb 		errno = (Pretval < 0) ? ENOSYS : Pretval;
720*c6402783Sakolb 		return (LGRP_AFF_INVALID);
721*c6402783Sakolb 	}
722*c6402783Sakolb 
723*c6402783Sakolb 	return (retval.sys_rval1);
724*c6402783Sakolb }
725*c6402783Sakolb 
726*c6402783Sakolb 
727*c6402783Sakolb /*
728*c6402783Sakolb  * Use /proc to call lgrp_affinity_set() in another process
729*c6402783Sakolb  */
730*c6402783Sakolb static int
731*c6402783Sakolb Plgrp_affinity_set(struct ps_prochandle *Ph, idtype_t idtype, id_t id,
732*c6402783Sakolb     lgrp_id_t lgrp, lgrp_affinity_t aff)
733*c6402783Sakolb {
734*c6402783Sakolb 	lgrp_affinity_args_t	args;
735*c6402783Sakolb 	argdes_t		Pargd[3];
736*c6402783Sakolb 	argdes_t		*Pargdp;
737*c6402783Sakolb 	int			Pnargs;
738*c6402783Sakolb 	int			Pretval;
739*c6402783Sakolb 	sysret_t		retval;
740*c6402783Sakolb 	int			syscall;
741*c6402783Sakolb 
742*c6402783Sakolb 	/*
743*c6402783Sakolb 	 * Fill in arguments needed for syscall(SYS_lgrpsys,
744*c6402783Sakolb 	 * LGRP_SYS_AFFINITY_SET, 0, &args)
745*c6402783Sakolb 	 */
746*c6402783Sakolb 	syscall = SYS_lgrpsys;
747*c6402783Sakolb 
748*c6402783Sakolb 	args.idtype = idtype;
749*c6402783Sakolb 	args.id = id;
750*c6402783Sakolb 	args.lgrp = lgrp;
751*c6402783Sakolb 	args.aff = aff;
752*c6402783Sakolb 
753*c6402783Sakolb 	/*
754*c6402783Sakolb 	 * Fill out /proc argument descriptors for syscall(SYS_lgrpsys,
755*c6402783Sakolb 	 * LGRP_SYS_AFFINITY_SET, idtype, id)
756*c6402783Sakolb 	 */
757*c6402783Sakolb 	Pnargs = LGRPSYS_NARGS;
758*c6402783Sakolb 	Pargdp = &Pargd[0];
759*c6402783Sakolb 	Pargdp->arg_value = LGRP_SYS_AFFINITY_SET;
760*c6402783Sakolb 	Pargdp->arg_object = NULL;
761*c6402783Sakolb 	Pargdp->arg_type = AT_BYVAL;
762*c6402783Sakolb 	Pargdp->arg_inout = AI_INPUT;
763*c6402783Sakolb 	Pargdp->arg_size = 0;
764*c6402783Sakolb 	Pargdp++;
765*c6402783Sakolb 
766*c6402783Sakolb 	Pargdp->arg_value = 0;
767*c6402783Sakolb 	Pargdp->arg_object = NULL;
768*c6402783Sakolb 	Pargdp->arg_type = AT_BYVAL;
769*c6402783Sakolb 	Pargdp->arg_inout = AI_INPUT;
770*c6402783Sakolb 	Pargdp->arg_size = 0;
771*c6402783Sakolb 	Pargdp++;
772*c6402783Sakolb 
773*c6402783Sakolb 	Pargdp->arg_value = 0;
774*c6402783Sakolb 	Pargdp->arg_object = &args;
775*c6402783Sakolb 	Pargdp->arg_type = AT_BYREF;
776*c6402783Sakolb 	Pargdp->arg_inout = AI_INPUT;
777*c6402783Sakolb 	Pargdp->arg_size = sizeof (lgrp_affinity_args_t);
778*c6402783Sakolb 	Pargdp++;
779*c6402783Sakolb 
780*c6402783Sakolb 	/*
781*c6402783Sakolb 	 * Have agent LWP call syscall with appropriate arguments in
782*c6402783Sakolb 	 * target process
783*c6402783Sakolb 	 */
784*c6402783Sakolb 	Pretval = Psyscall(Ph, &retval, syscall, Pnargs, &Pargd[0]);
785*c6402783Sakolb 	if (Pretval) {
786*c6402783Sakolb 		errno = (Pretval < 0) ? ENOSYS : Pretval;
787*c6402783Sakolb 		return (-1);
788*c6402783Sakolb 	}
789*c6402783Sakolb 
790*c6402783Sakolb 	return (retval.sys_rval1);
791*c6402783Sakolb }
792*c6402783Sakolb 
793*c6402783Sakolb /*
794*c6402783Sakolb  * Use /proc to call lgrp_home() in another process
795*c6402783Sakolb  */
796*c6402783Sakolb static lgrp_id_t
797*c6402783Sakolb Plgrp_home(struct ps_prochandle *Ph, idtype_t idtype, id_t id)
798*c6402783Sakolb {
799*c6402783Sakolb 	argdes_t		Pargd[3];
800*c6402783Sakolb 	argdes_t		*Pargdp;
801*c6402783Sakolb 	int			Pnargs;
802*c6402783Sakolb 	int			Pretval;
803*c6402783Sakolb 	sysret_t		retval;
804*c6402783Sakolb 	int			syscall;
805*c6402783Sakolb 
806*c6402783Sakolb 	/*
807*c6402783Sakolb 	 * Fill in arguments needed for syscall(SYS_lgrpsys,
808*c6402783Sakolb 	 * LGRP_SYS_HOME, idtype, id)
809*c6402783Sakolb 	 */
810*c6402783Sakolb 	syscall = SYS_lgrpsys;
811*c6402783Sakolb 
812*c6402783Sakolb 	/*
813*c6402783Sakolb 	 * Fill out /proc argument descriptors for syscall(SYS_lgrpsys,
814*c6402783Sakolb 	 * LGRP_SYS_HOME, idtype, id)
815*c6402783Sakolb 	 */
816*c6402783Sakolb 	Pnargs = LGRPSYS_NARGS;
817*c6402783Sakolb 	Pargdp = &Pargd[0];
818*c6402783Sakolb 	Pargdp->arg_value = LGRP_SYS_HOME;
819*c6402783Sakolb 	Pargdp->arg_object = NULL;
820*c6402783Sakolb 	Pargdp->arg_type = AT_BYVAL;
821*c6402783Sakolb 	Pargdp->arg_inout = AI_INPUT;
822*c6402783Sakolb 	Pargdp->arg_size = 0;
823*c6402783Sakolb 	Pargdp++;
824*c6402783Sakolb 
825*c6402783Sakolb 	Pargdp->arg_value = idtype;
826*c6402783Sakolb 	Pargdp->arg_object = NULL;
827*c6402783Sakolb 	Pargdp->arg_type = AT_BYVAL;
828*c6402783Sakolb 	Pargdp->arg_inout = AI_INPUT;
829*c6402783Sakolb 	Pargdp->arg_size = 0;
830*c6402783Sakolb 	Pargdp++;
831*c6402783Sakolb 
832*c6402783Sakolb 	Pargdp->arg_value = id;
833*c6402783Sakolb 	Pargdp->arg_object = NULL;
834*c6402783Sakolb 	Pargdp->arg_type = AT_BYVAL;
835*c6402783Sakolb 	Pargdp->arg_inout = AI_INPUT;
836*c6402783Sakolb 	Pargdp->arg_size = 0;
837*c6402783Sakolb 	Pargdp++;
838*c6402783Sakolb 
839*c6402783Sakolb 	/*
840*c6402783Sakolb 	 * Have agent LWP call syscall with appropriate arguments in
841*c6402783Sakolb 	 * target process
842*c6402783Sakolb 	 */
843*c6402783Sakolb 	Pretval = Psyscall(Ph, &retval, syscall, Pnargs, &Pargd[0]);
844*c6402783Sakolb 	if (Pretval) {
845*c6402783Sakolb 		errno = (Pretval < 0) ? ENOSYS : Pretval;
846*c6402783Sakolb 		return (-1);
847*c6402783Sakolb 	}
848*c6402783Sakolb 
849*c6402783Sakolb 	return (retval.sys_rval1);
850*c6402783Sakolb }
851*c6402783Sakolb 
852*c6402783Sakolb /*
853*c6402783Sakolb  * Use /proc to call lgrp_affinity_set(3LGRP) to set home lgroup of given
854*c6402783Sakolb  * thread
855*c6402783Sakolb  */
856*c6402783Sakolb static int
857*c6402783Sakolb Plgrp_home_set(struct ps_prochandle *Ph, idtype_t idtype, id_t id,
858*c6402783Sakolb     lgrp_id_t lgrp)
859*c6402783Sakolb {
860*c6402783Sakolb 	return (Plgrp_affinity_set(Ph, idtype, id, lgrp,
861*c6402783Sakolb 	    LGRP_AFF_STRONG));
862*c6402783Sakolb }
863*c6402783Sakolb 
864*c6402783Sakolb 
865*c6402783Sakolb /*
866*c6402783Sakolb  * Do plgrp(1) operation on specified thread
867*c6402783Sakolb  */
868*c6402783Sakolb static int
869*c6402783Sakolb do_op(plgrp_args_t *plgrp_args, id_t pid, id_t lwpid,
870*c6402783Sakolb     const lwpsinfo_t *lwpsinfo)
871*c6402783Sakolb {
872*c6402783Sakolb 	lgrp_affinity_t		*affs;
873*c6402783Sakolb 	lgrp_affinity_t		*cur_affs;
874*c6402783Sakolb 	lgrp_id_t		home;
875*c6402783Sakolb 	int			i;
876*c6402783Sakolb 	lgrp_affinity_t		*init_affs;
877*c6402783Sakolb 	lgrp_id_t		*lgrps;
878*c6402783Sakolb 	lgrp_id_t		*lgrps_changed;
879*c6402783Sakolb 	int			nlgrps;
880*c6402783Sakolb 	lgrp_id_t		old_home;
881*c6402783Sakolb 	lgrp_id_t		lgrpid;
882*c6402783Sakolb 	struct ps_prochandle	*Ph;
883*c6402783Sakolb 	int			nchanged;
884*c6402783Sakolb 
885*c6402783Sakolb 	/*
886*c6402783Sakolb 	 * No args, so nothing to do.
887*c6402783Sakolb 	 */
888*c6402783Sakolb 	if (plgrp_args == NULL)
889*c6402783Sakolb 		return (0);
890*c6402783Sakolb 
891*c6402783Sakolb 	/*
892*c6402783Sakolb 	 * Unpack plgrp(1) arguments and state needed to process this LWP
893*c6402783Sakolb 	 */
894*c6402783Sakolb 	Ph = plgrp_args->Ph;
895*c6402783Sakolb 	lgrps = plgrp_args->lgrps;
896*c6402783Sakolb 	affs = plgrp_args->affs;
897*c6402783Sakolb 	nlgrps = plgrp_args->nlgrps;
898*c6402783Sakolb 
899*c6402783Sakolb 	switch (plgrp_args->op) {
900*c6402783Sakolb 
901*c6402783Sakolb 	case PLGRP_HOME_GET:
902*c6402783Sakolb 		/*
903*c6402783Sakolb 		 * Get and display home lgroup for given LWP
904*c6402783Sakolb 		 */
905*c6402783Sakolb 		home = lwpsinfo->pr_lgrp;
906*c6402783Sakolb 		(void) printf(FMT_HOME"\n", (int)home);
907*c6402783Sakolb 		break;
908*c6402783Sakolb 
909*c6402783Sakolb 	case PLGRP_AFFINITY_GET:
910*c6402783Sakolb 		/*
911*c6402783Sakolb 		 * Get and display this LWP's home lgroup and affinities
912*c6402783Sakolb 		 * for specified lgroups
913*c6402783Sakolb 		 */
914*c6402783Sakolb 		home = lwpsinfo->pr_lgrp;
915*c6402783Sakolb 		(void) printf(FMT_HOME, (int)home);
916*c6402783Sakolb 
917*c6402783Sakolb 		/*
918*c6402783Sakolb 		 * Collect affinity values
919*c6402783Sakolb 		 */
920*c6402783Sakolb 		for (i = 0; i < nlgrps; i++) {
921*c6402783Sakolb 			affs[i] = Plgrp_affinity_get(Ph, P_LWPID, lwpid,
922*c6402783Sakolb 			    lgrps[i]);
923*c6402783Sakolb 
924*c6402783Sakolb 			if (affs[i] == LGRP_AFF_INVALID) {
925*c6402783Sakolb 				nerrors++;
926*c6402783Sakolb 				(void) fprintf(stderr,
927*c6402783Sakolb 				    gettext("%s: cannot get affinity"
928*c6402783Sakolb 					" for lgroup %d for %d/%d: %s\n"),
929*c6402783Sakolb 				    progname, lgrps[i], pid, lwpid,
930*c6402783Sakolb 				    strerror(errno));
931*c6402783Sakolb 			}
932*c6402783Sakolb 		}
933*c6402783Sakolb 
934*c6402783Sakolb 		/*
935*c6402783Sakolb 		 * Print affinities for each type.
936*c6402783Sakolb 		 */
937*c6402783Sakolb 		print_affinities(lgrps, affs, nlgrps);
938*c6402783Sakolb 		(void) printf("\n");
939*c6402783Sakolb 
940*c6402783Sakolb 		break;
941*c6402783Sakolb 
942*c6402783Sakolb 	case PLGRP_HOME_SET:
943*c6402783Sakolb 		/*
944*c6402783Sakolb 		 * Get home lgroup before and after setting it and display
945*c6402783Sakolb 		 * change.  If more than one lgroup and one LWP are specified,
946*c6402783Sakolb 		 * then home LWPs to lgroups in round robin fashion.
947*c6402783Sakolb 		 */
948*c6402783Sakolb 		old_home = lwpsinfo->pr_lgrp;
949*c6402783Sakolb 
950*c6402783Sakolb 		i = plgrp_args->index;
951*c6402783Sakolb 		if (Plgrp_home_set(Ph, P_LWPID, lwpid, lgrps[i]) != 0) {
952*c6402783Sakolb 			nerrors++;
953*c6402783Sakolb 			(void) fprintf(stderr,
954*c6402783Sakolb 			    gettext("%s: cannot set home lgroup of %d/%d"
955*c6402783Sakolb 				" to lgroup %d: %s\n"),
956*c6402783Sakolb 				progname, pid, lwpid, lgrps[i],
957*c6402783Sakolb 			    strerror(errno));
958*c6402783Sakolb 			(void) printf("\n");
959*c6402783Sakolb 		} else {
960*c6402783Sakolb 			int len;
961*c6402783Sakolb 			int width = strlen(HDR_PLGRP_HOME_CHANGE);
962*c6402783Sakolb 
963*c6402783Sakolb 			home = Plgrp_home(Ph, P_LWPID, lwpid);
964*c6402783Sakolb 
965*c6402783Sakolb 			if (home < 0) {
966*c6402783Sakolb 				(void) fprintf(stderr,
967*c6402783Sakolb 				    gettext("%s cannot get home lgroup for"
968*c6402783Sakolb 					" %d/%d: %s\n"),
969*c6402783Sakolb 				    progname, pid, lwpid, strerror(errno));
970*c6402783Sakolb 				nerrors++;
971*c6402783Sakolb 			}
972*c6402783Sakolb 
973*c6402783Sakolb 			len = printf(FMT_NEWHOME, (int)old_home, (int)home);
974*c6402783Sakolb 			if (len < width)
975*c6402783Sakolb 				(void) printf("%*c\n", (int)(width - len), ' ');
976*c6402783Sakolb 		}
977*c6402783Sakolb 
978*c6402783Sakolb 		plgrp_args->index = (i + 1) % nlgrps;
979*c6402783Sakolb 
980*c6402783Sakolb 		break;
981*c6402783Sakolb 
982*c6402783Sakolb 	case PLGRP_AFFINITY_SET:
983*c6402783Sakolb 		/*
984*c6402783Sakolb 		 * Set affinities for specified lgroups and print old and new
985*c6402783Sakolb 		 * affinities and any resulting change in home lgroups
986*c6402783Sakolb 		 */
987*c6402783Sakolb 
988*c6402783Sakolb 		/*
989*c6402783Sakolb 		 * Get initial home lgroup as it may change.
990*c6402783Sakolb 		 */
991*c6402783Sakolb 		old_home = lwpsinfo->pr_lgrp;
992*c6402783Sakolb 
993*c6402783Sakolb 		/*
994*c6402783Sakolb 		 * Need to allocate arrays indexed by lgroup (ID) for
995*c6402783Sakolb 		 * affinities and lgroups because user may specify affinity
996*c6402783Sakolb 		 * for same lgroup multiple times....
997*c6402783Sakolb 		 *
998*c6402783Sakolb 		 * Keeping these arrays by lgroup (ID) eliminates any
999*c6402783Sakolb 		 * duplication and makes it easier to just print initial and
1000*c6402783Sakolb 		 * final lgroup affinities (instead of trying to keep a list
1001*c6402783Sakolb 		 * of lgroups specified which may include duplicates)
1002*c6402783Sakolb 		 */
1003*c6402783Sakolb 		init_affs = malloc(NLGRPS * sizeof (lgrp_affinity_t));
1004*c6402783Sakolb 		cur_affs = malloc(NLGRPS * sizeof (lgrp_affinity_t));
1005*c6402783Sakolb 		lgrps_changed = malloc(NLGRPS * sizeof (lgrp_id_t));
1006*c6402783Sakolb 
1007*c6402783Sakolb 		if (init_affs == NULL || cur_affs == NULL ||
1008*c6402783Sakolb 		    lgrps_changed == NULL) {
1009*c6402783Sakolb 			(void) fprintf(stderr, gettext("%s: out of memory\n"),
1010*c6402783Sakolb 			    progname);
1011*c6402783Sakolb 			Prelease(Ph, PRELEASE_RETAIN);
1012*c6402783Sakolb 			exit(EXIT_NONFATAL);
1013*c6402783Sakolb 		}
1014*c6402783Sakolb 
1015*c6402783Sakolb 		/*
1016*c6402783Sakolb 		 * Initialize current and initial lgroup affinities and
1017*c6402783Sakolb 		 * lgroups changed
1018*c6402783Sakolb 		 */
1019*c6402783Sakolb 		for (lgrpid = 0; lgrpid < NLGRPS; lgrpid++) {
1020*c6402783Sakolb 
1021*c6402783Sakolb 			if (!LGRP_VALID(lgrpid)) {
1022*c6402783Sakolb 				init_affs[lgrpid] = LGRP_AFF_INVALID;
1023*c6402783Sakolb 			} else {
1024*c6402783Sakolb 				init_affs[lgrpid] =
1025*c6402783Sakolb 				    Plgrp_affinity_get(Ph, P_LWPID,
1026*c6402783Sakolb 					lwpid, lgrpid);
1027*c6402783Sakolb 
1028*c6402783Sakolb 				if (init_affs[lgrpid] == LGRP_AFF_INVALID) {
1029*c6402783Sakolb 					nerrors++;
1030*c6402783Sakolb 					(void) fprintf(stderr,
1031*c6402783Sakolb 					    gettext("%s: cannot get"
1032*c6402783Sakolb 						" affinity for lgroup %d"
1033*c6402783Sakolb 						" for %d/%d: %s\n"),
1034*c6402783Sakolb 					    progname, lgrpid, pid, lwpid,
1035*c6402783Sakolb 					    strerror(errno));
1036*c6402783Sakolb 				}
1037*c6402783Sakolb 			}
1038*c6402783Sakolb 
1039*c6402783Sakolb 			cur_affs[lgrpid] = init_affs[lgrpid];
1040*c6402783Sakolb 			lgrps_changed[lgrpid] = LGRP_NONE;
1041*c6402783Sakolb 		}
1042*c6402783Sakolb 
1043*c6402783Sakolb 		/*
1044*c6402783Sakolb 		 * Change affinities.
1045*c6402783Sakolb 		 */
1046*c6402783Sakolb 		for (i = 0; i < nlgrps; i++) {
1047*c6402783Sakolb 			lgrp_affinity_t	aff = affs[i];
1048*c6402783Sakolb 
1049*c6402783Sakolb 			lgrpid = lgrps[i];
1050*c6402783Sakolb 
1051*c6402783Sakolb 			/*
1052*c6402783Sakolb 			 * If the suggested affinity is the same as the current
1053*c6402783Sakolb 			 * one, skip this lgroup.
1054*c6402783Sakolb 			 */
1055*c6402783Sakolb 			if (aff == cur_affs[lgrpid])
1056*c6402783Sakolb 				continue;
1057*c6402783Sakolb 
1058*c6402783Sakolb 			/*
1059*c6402783Sakolb 			 * Set affinity to the new value
1060*c6402783Sakolb 			 */
1061*c6402783Sakolb 			if (Plgrp_affinity_set(Ph, P_LWPID, lwpid, lgrpid,
1062*c6402783Sakolb 				aff) < 0) {
1063*c6402783Sakolb 				nerrors++;
1064*c6402783Sakolb 				(void) fprintf(stderr,
1065*c6402783Sakolb 				    gettext("%s: cannot set"
1066*c6402783Sakolb 					" %s affinity for lgroup %d"
1067*c6402783Sakolb 					" for %d/%d: %s\n"),
1068*c6402783Sakolb 				    progname, lgrp_affinity_string(aff),
1069*c6402783Sakolb 				    lgrpid, pid, lwpid,
1070*c6402783Sakolb 				    strerror(errno));
1071*c6402783Sakolb 				continue;
1072*c6402783Sakolb 			}
1073*c6402783Sakolb 
1074*c6402783Sakolb 			/*
1075*c6402783Sakolb 			 * Get the new value and verify that it changed as
1076*c6402783Sakolb 			 * expected.
1077*c6402783Sakolb 			 */
1078*c6402783Sakolb 			cur_affs[lgrpid] =
1079*c6402783Sakolb 			    Plgrp_affinity_get(Ph, P_LWPID, lwpid, lgrpid);
1080*c6402783Sakolb 
1081*c6402783Sakolb 			if (cur_affs[lgrpid] == LGRP_AFF_INVALID) {
1082*c6402783Sakolb 				nerrors++;
1083*c6402783Sakolb 				(void) fprintf(stderr,
1084*c6402783Sakolb 				    gettext("%s: cannot get"
1085*c6402783Sakolb 					" affinity for lgroup %d"
1086*c6402783Sakolb 					" for %d/%d: %s\n"),
1087*c6402783Sakolb 				    progname, lgrpid, pid, lwpid,
1088*c6402783Sakolb 				    strerror(errno));
1089*c6402783Sakolb 				continue;
1090*c6402783Sakolb 			}
1091*c6402783Sakolb 
1092*c6402783Sakolb 			if (aff != cur_affs[lgrpid]) {
1093*c6402783Sakolb 				(void) fprintf(stderr,
1094*c6402783Sakolb 				    gettext("%s: affinity for"
1095*c6402783Sakolb 					" lgroup %d is set to %d instead of %d"
1096*c6402783Sakolb 					" for %d/%d\n"),
1097*c6402783Sakolb 				    progname, lgrpid, cur_affs[lgrpid], aff,
1098*c6402783Sakolb 				    pid, lwpid);
1099*c6402783Sakolb 				nerrors++;
1100*c6402783Sakolb 			}
1101*c6402783Sakolb 		}
1102*c6402783Sakolb 
1103*c6402783Sakolb 		/*
1104*c6402783Sakolb 		 * Compare current and initial affinities and mark lgroups with
1105*c6402783Sakolb 		 * changed affinities.
1106*c6402783Sakolb 		 */
1107*c6402783Sakolb 		nchanged = 0;
1108*c6402783Sakolb 		for (lgrpid = 0; lgrpid < NLGRPS; lgrpid++) {
1109*c6402783Sakolb 			if (init_affs[lgrpid] != cur_affs[lgrpid]) {
1110*c6402783Sakolb 				lgrps_changed[lgrpid] = lgrpid;
1111*c6402783Sakolb 				nchanged++;
1112*c6402783Sakolb 			}
1113*c6402783Sakolb 		}
1114*c6402783Sakolb 
1115*c6402783Sakolb 		if (nchanged == 0) {
1116*c6402783Sakolb 			/*
1117*c6402783Sakolb 			 * Nothing changed, so just print current affinities for
1118*c6402783Sakolb 			 * specified lgroups.
1119*c6402783Sakolb 			 */
1120*c6402783Sakolb 			for (i = 0; i < nlgrps; i++) {
1121*c6402783Sakolb 				lgrps_changed[lgrps[i]] = lgrps[i];
1122*c6402783Sakolb 			}
1123*c6402783Sakolb 
1124*c6402783Sakolb 			(void) printf("%-*d",
1125*c6402783Sakolb 			    (int)strlen(HDR_PLGRP_HOME_CHANGE),
1126*c6402783Sakolb 			    (int)old_home);
1127*c6402783Sakolb 
1128*c6402783Sakolb 			print_affinities(lgrps_changed, cur_affs, NLGRPS);
1129*c6402783Sakolb 			(void) printf("\n");
1130*c6402783Sakolb 		} else {
1131*c6402783Sakolb 			int width = strlen(HDR_PLGRP_HOME_CHANGE);
1132*c6402783Sakolb 
1133*c6402783Sakolb 			/*
1134*c6402783Sakolb 			 * Some lgroup affinities changed, so display old
1135*c6402783Sakolb 			 * and new home lgroups for thread and its old and new
1136*c6402783Sakolb 			 * affinities for affected lgroups
1137*c6402783Sakolb 			 */
1138*c6402783Sakolb 			home = Plgrp_home(Ph, P_LWPID, lwpid);
1139*c6402783Sakolb 			if (home < 0) {
1140*c6402783Sakolb 				(void) fprintf(stderr,
1141*c6402783Sakolb 				    gettext("%s: cannot get home"
1142*c6402783Sakolb 					" for %d/%d: %s\n"),
1143*c6402783Sakolb 				    progname, pid, lwpid, strerror(errno));
1144*c6402783Sakolb 				nerrors++;
1145*c6402783Sakolb 			}
1146*c6402783Sakolb 			if (old_home != home) {
1147*c6402783Sakolb 				int len;
1148*c6402783Sakolb 
1149*c6402783Sakolb 				/*
1150*c6402783Sakolb 				 * Fit string into fixed width
1151*c6402783Sakolb 				 */
1152*c6402783Sakolb 				len = printf(FMT_NEWHOME,
1153*c6402783Sakolb 				    (int)old_home, (int)home);
1154*c6402783Sakolb 				if (len < width)
1155*c6402783Sakolb 					(void) printf("%*c", width - len, ' ');
1156*c6402783Sakolb 			} else {
1157*c6402783Sakolb 				(void) printf("%-*d", width, (int)home);
1158*c6402783Sakolb 			}
1159*c6402783Sakolb 
1160*c6402783Sakolb 			/*
1161*c6402783Sakolb 			 * Print change in affinities from old to new
1162*c6402783Sakolb 			 */
1163*c6402783Sakolb 			print_affinities(lgrps_changed, init_affs, NLGRPS);
1164*c6402783Sakolb 			(void) printf(" => ");
1165*c6402783Sakolb 			print_affinities(lgrps_changed, cur_affs, NLGRPS);
1166*c6402783Sakolb 			(void) printf("\n");
1167*c6402783Sakolb 		}
1168*c6402783Sakolb 
1169*c6402783Sakolb 		free(lgrps_changed);
1170*c6402783Sakolb 		free(init_affs);
1171*c6402783Sakolb 		free(cur_affs);
1172*c6402783Sakolb 
1173*c6402783Sakolb 		break;
1174*c6402783Sakolb 
1175*c6402783Sakolb 	default:
1176*c6402783Sakolb 		break;
1177*c6402783Sakolb 	}
1178*c6402783Sakolb 
1179*c6402783Sakolb 	return (0);
1180*c6402783Sakolb }
1181*c6402783Sakolb 
1182*c6402783Sakolb 
1183*c6402783Sakolb /*
1184*c6402783Sakolb  * Routine called by Plwp_iter_all() as it iterates through LWPs of another
1185*c6402783Sakolb  * process
1186*c6402783Sakolb  */
1187*c6402783Sakolb /* ARGSUSED */
1188*c6402783Sakolb static int
1189*c6402783Sakolb Plwp_iter_handler(void *arg, const lwpstatus_t *lwpstatus,
1190*c6402783Sakolb     const lwpsinfo_t *lwpsinfo)
1191*c6402783Sakolb {
1192*c6402783Sakolb 	id_t			lwpid;
1193*c6402783Sakolb 	struct ps_prochandle	*Ph;
1194*c6402783Sakolb 	const pstatus_t		*pstatus;
1195*c6402783Sakolb 	plgrp_args_t		*plgrp_args;
1196*c6402783Sakolb 
1197*c6402783Sakolb 	/*
1198*c6402783Sakolb 	 * Nothing to do if no arguments
1199*c6402783Sakolb 	 */
1200*c6402783Sakolb 	if (arg == NULL || interrupt)
1201*c6402783Sakolb 		return (0);
1202*c6402783Sakolb 
1203*c6402783Sakolb 	/*
1204*c6402783Sakolb 	 * Unpack plgrp(1) arguments and state needed to process this LWP
1205*c6402783Sakolb 	 */
1206*c6402783Sakolb 	plgrp_args = arg;
1207*c6402783Sakolb 	Ph = plgrp_args->Ph;
1208*c6402783Sakolb 
1209*c6402783Sakolb 	/*
1210*c6402783Sakolb 	 * Just return if no /proc handle for process
1211*c6402783Sakolb 	 */
1212*c6402783Sakolb 	if (Ph == NULL)
1213*c6402783Sakolb 		return (0);
1214*c6402783Sakolb 
1215*c6402783Sakolb 	pstatus = Pstatus(Ph);
1216*c6402783Sakolb 
1217*c6402783Sakolb 	/*
1218*c6402783Sakolb 	 * Skip agent LWP and any LWPs that weren't specified
1219*c6402783Sakolb 	 */
1220*c6402783Sakolb 	lwpid = lwpsinfo->pr_lwpid;
1221*c6402783Sakolb 	if (lwpid == pstatus->pr_agentid ||
1222*c6402783Sakolb 	    !proc_lwp_in_set(plgrp_args->lwps, lwpid))
1223*c6402783Sakolb 		return (0);
1224*c6402783Sakolb 
1225*c6402783Sakolb 	plgrp_args->nthreads++;
1226*c6402783Sakolb 
1227*c6402783Sakolb 	/*
1228*c6402783Sakolb 	 * Do all plgrp(1) operations specified on given thread
1229*c6402783Sakolb 	 */
1230*c6402783Sakolb 	(void) printf(FMT_THREAD" ", (int)pstatus->pr_pid, (int)lwpid);
1231*c6402783Sakolb 	return (do_op(plgrp_args, pstatus->pr_pid, lwpid, lwpsinfo));
1232*c6402783Sakolb }
1233*c6402783Sakolb 
1234*c6402783Sakolb /*
1235*c6402783Sakolb  * Get target process specified in "pidstring" argument to do operation(s)
1236*c6402783Sakolb  * specified in "plgrp_todo" using /proc and agent LWP
1237*c6402783Sakolb  */
1238*c6402783Sakolb static void
1239*c6402783Sakolb do_process(char *pidstring, plgrp_args_t *plgrp_todo, int force)
1240*c6402783Sakolb {
1241*c6402783Sakolb 	int			error;
1242*c6402783Sakolb 	const char		*lwps;
1243*c6402783Sakolb 	struct ps_prochandle	*Ph;
1244*c6402783Sakolb 
1245*c6402783Sakolb 	/*
1246*c6402783Sakolb 	 * Nothing to do, so return.
1247*c6402783Sakolb 	 */
1248*c6402783Sakolb 	if (plgrp_todo == NULL || interrupt)
1249*c6402783Sakolb 		return;
1250*c6402783Sakolb 
1251*c6402783Sakolb 	/*
1252*c6402783Sakolb 	 * Grab target process or core and return
1253*c6402783Sakolb 	 * /proc handle for process and string of LWP
1254*c6402783Sakolb 	 * IDs
1255*c6402783Sakolb 	 */
1256*c6402783Sakolb 	Ph = proc_arg_xgrab(pidstring, NULL,
1257*c6402783Sakolb 	    PR_ARG_ANY, force | PGRAB_RETAIN | PGRAB_NOSTOP, &error, &lwps);
1258*c6402783Sakolb 	if (Ph == NULL) {
1259*c6402783Sakolb 		(void) fprintf(stderr,
1260*c6402783Sakolb 		    gettext("%s: Unable to grab process %s: %s\n"),
1261*c6402783Sakolb 		    progname, pidstring, Pgrab_error(error));
1262*c6402783Sakolb 		nerrors++;
1263*c6402783Sakolb 		return;
1264*c6402783Sakolb 	}
1265*c6402783Sakolb 
1266*c6402783Sakolb 	/*
1267*c6402783Sakolb 	 * Fill in remaining plgrp(1) arguments and state needed to do
1268*c6402783Sakolb 	 * plgrp(1) operation(s) on desired LWPs in our handler
1269*c6402783Sakolb 	 * called by Plwp_iter_all() as it iterates over LWPs
1270*c6402783Sakolb 	 * in given process
1271*c6402783Sakolb 	 */
1272*c6402783Sakolb 	plgrp_todo->Ph = Ph;
1273*c6402783Sakolb 	plgrp_todo->lwps = lwps;
1274*c6402783Sakolb 
1275*c6402783Sakolb 	/*
1276*c6402783Sakolb 	 * Iterate over LWPs in process and do specified
1277*c6402783Sakolb 	 * operation(s) on those specified
1278*c6402783Sakolb 	 */
1279*c6402783Sakolb 	if (Plwp_iter_all(Ph, Plwp_iter_handler, plgrp_todo) != 0) {
1280*c6402783Sakolb 		(void) fprintf(stderr,
1281*c6402783Sakolb 		    gettext("%s: error iterating over threads\n"),
1282*c6402783Sakolb 		    progname);
1283*c6402783Sakolb 		nerrors++;
1284*c6402783Sakolb 	}
1285*c6402783Sakolb 
1286*c6402783Sakolb 	Prelease(Ph, PRELEASE_RETAIN);
1287*c6402783Sakolb }
1288*c6402783Sakolb 
1289*c6402783Sakolb 
1290*c6402783Sakolb /*
1291*c6402783Sakolb  * Parse command line and kick off any resulting actions
1292*c6402783Sakolb  *
1293*c6402783Sakolb  * plgrp(1) has the following command line syntax:
1294*c6402783Sakolb  *
1295*c6402783Sakolb  *	plgrp [-h] <pid> | <core> [/lwps] ...
1296*c6402783Sakolb  *	plgrp [-F] -a <lgroup>,... <pid>[/lwps] ...
1297*c6402783Sakolb  *	plgrp [-F] -H <lgroup>,... <pid>[/lwps] ...
1298*c6402783Sakolb  *	plgrp [-F] -A <lgroup>,... [/none|weak|strong] ... <pid>[/lwps] ...
1299*c6402783Sakolb  *
1300*c6402783Sakolb  *	where <lgroup> is an lgroup ID, "all", "root", "leaves".
1301*c6402783Sakolb  */
1302*c6402783Sakolb int
1303*c6402783Sakolb main(int argc, char *argv[])
1304*c6402783Sakolb {
1305*c6402783Sakolb 	lgrp_affinity_t		aff;
1306*c6402783Sakolb 	char			*affstring;
1307*c6402783Sakolb 	int			c;
1308*c6402783Sakolb 	lgrp_cookie_t		cookie;
1309*c6402783Sakolb 	int			Fflag;
1310*c6402783Sakolb 	int			i;
1311*c6402783Sakolb 	int			opt_seen;
1312*c6402783Sakolb 	plgrp_args_t		plgrp_todo;
1313*c6402783Sakolb 	char			*s;
1314*c6402783Sakolb 
1315*c6402783Sakolb 	(void) setlocale(LC_ALL, "");
1316*c6402783Sakolb 	(void) textdomain(TEXT_DOMAIN);
1317*c6402783Sakolb 
1318*c6402783Sakolb 	opt_seen = 0;
1319*c6402783Sakolb 
1320*c6402783Sakolb 	/*
1321*c6402783Sakolb 	 * Get name of program
1322*c6402783Sakolb 	 */
1323*c6402783Sakolb 	progname = basename(argv[0]);
1324*c6402783Sakolb 
1325*c6402783Sakolb 	/*
1326*c6402783Sakolb 	 * Not much to do when only name of program given
1327*c6402783Sakolb 	 */
1328*c6402783Sakolb 	if (argc == 1)
1329*c6402783Sakolb 		usage(0);
1330*c6402783Sakolb 
1331*c6402783Sakolb 	/*
1332*c6402783Sakolb 	 * Catch signals from terminal, so they can be handled asynchronously
1333*c6402783Sakolb 	 * when we're ready instead of when we're not (;-)
1334*c6402783Sakolb 	 */
1335*c6402783Sakolb 	if (sigset(SIGHUP, SIG_IGN) == SIG_DFL)
1336*c6402783Sakolb 		(void) sigset(SIGHUP, intr);
1337*c6402783Sakolb 	if (sigset(SIGINT, SIG_IGN) == SIG_DFL)
1338*c6402783Sakolb 		(void) sigset(SIGINT, intr);
1339*c6402783Sakolb 	if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL)
1340*c6402783Sakolb 		(void) sigset(SIGQUIT, intr);
1341*c6402783Sakolb 	(void) sigset(SIGPIPE, intr);
1342*c6402783Sakolb 	(void) sigset(SIGTERM, intr);
1343*c6402783Sakolb 
1344*c6402783Sakolb 	/*
1345*c6402783Sakolb 	 * Take snapshot of lgroup hierarchy
1346*c6402783Sakolb 	 */
1347*c6402783Sakolb 	cookie = lgrp_init(LGRP_VIEW_OS);
1348*c6402783Sakolb 	if (cookie == LGRP_COOKIE_NONE) {
1349*c6402783Sakolb 		(void) fprintf(stderr,
1350*c6402783Sakolb 		    gettext("%s: Fatal error: cannot get lgroup"
1351*c6402783Sakolb 			" information from the OS: %s\n"),
1352*c6402783Sakolb 		    progname, strerror(errno));
1353*c6402783Sakolb 		return (EXIT_FAILURE);
1354*c6402783Sakolb 	}
1355*c6402783Sakolb 
1356*c6402783Sakolb 	root = lgrp_root(cookie);
1357*c6402783Sakolb 	lgrps_bitmap_init(cookie, root, &lgrps_bitmap, &lgrps_bitmap_nelements);
1358*c6402783Sakolb 
1359*c6402783Sakolb 	/*
1360*c6402783Sakolb 	 * Remember arguments and state needed to do plgrp(1) operation
1361*c6402783Sakolb 	 * on desired LWPs
1362*c6402783Sakolb 	 */
1363*c6402783Sakolb 	bzero(&plgrp_todo, sizeof (plgrp_args_t));
1364*c6402783Sakolb 	plgrp_todo.op = PLGRP_HOME_GET;
1365*c6402783Sakolb 
1366*c6402783Sakolb 	/*
1367*c6402783Sakolb 	 * Parse options
1368*c6402783Sakolb 	 */
1369*c6402783Sakolb 	opterr = 0;
1370*c6402783Sakolb 	Fflag = 0;
1371*c6402783Sakolb 	while (!interrupt && (c = getopt(argc, argv, "a:A:FhH:")) != -1) {
1372*c6402783Sakolb 		/*
1373*c6402783Sakolb 		 * Parse option and only allow one option besides -F to be
1374*c6402783Sakolb 		 * specified
1375*c6402783Sakolb 		 */
1376*c6402783Sakolb 		switch (c) {
1377*c6402783Sakolb 
1378*c6402783Sakolb 		case 'h':	/* Get home lgroup */
1379*c6402783Sakolb 			/*
1380*c6402783Sakolb 			 * Only allow one option (besides -F) to be specified
1381*c6402783Sakolb 			 */
1382*c6402783Sakolb 			if (opt_seen)
1383*c6402783Sakolb 				usage(EXIT_FAILURE);
1384*c6402783Sakolb 			opt_seen = 1;
1385*c6402783Sakolb 
1386*c6402783Sakolb 			plgrp_todo.op = PLGRP_HOME_GET;
1387*c6402783Sakolb 			break;
1388*c6402783Sakolb 
1389*c6402783Sakolb 		case 'H':	/* Set home lgroup */
1390*c6402783Sakolb 
1391*c6402783Sakolb 			/*
1392*c6402783Sakolb 			 * Fail if already specified option (besides -F)
1393*c6402783Sakolb 			 * or no more arguments
1394*c6402783Sakolb 			 */
1395*c6402783Sakolb 			if (opt_seen || optind >= argc) {
1396*c6402783Sakolb 				usage(EXIT_FAILURE);
1397*c6402783Sakolb 			}
1398*c6402783Sakolb 			opt_seen = 1;
1399*c6402783Sakolb 
1400*c6402783Sakolb 			plgrp_todo.op = PLGRP_HOME_SET;
1401*c6402783Sakolb 
1402*c6402783Sakolb 			if (parse_lgrps(cookie, &plgrp_todo, optarg) < 0)
1403*c6402783Sakolb 				usage(EXIT_FAILURE);
1404*c6402783Sakolb 
1405*c6402783Sakolb 			/* If there are no valid lgroups exit immediately */
1406*c6402783Sakolb 			if (plgrp_todo.nlgrps == 0) {
1407*c6402783Sakolb 				(void) fprintf(stderr,
1408*c6402783Sakolb 				    gettext("%s: no valid lgroups"
1409*c6402783Sakolb 					" specified for -%c\n\n"),
1410*c6402783Sakolb 				    progname, c);
1411*c6402783Sakolb 				    usage(EXIT_FAILURE);
1412*c6402783Sakolb 			}
1413*c6402783Sakolb 
1414*c6402783Sakolb 			break;
1415*c6402783Sakolb 
1416*c6402783Sakolb 		case 'a':	/* Get lgroup affinity */
1417*c6402783Sakolb 
1418*c6402783Sakolb 			/*
1419*c6402783Sakolb 			 * Fail if already specified option (besides -F)
1420*c6402783Sakolb 			 * or no more arguments
1421*c6402783Sakolb 			 */
1422*c6402783Sakolb 			if (opt_seen || optind >= argc) {
1423*c6402783Sakolb 				usage(EXIT_FAILURE);
1424*c6402783Sakolb 			}
1425*c6402783Sakolb 			opt_seen = 1;
1426*c6402783Sakolb 
1427*c6402783Sakolb 			plgrp_todo.op = PLGRP_AFFINITY_GET;
1428*c6402783Sakolb 
1429*c6402783Sakolb 			if (parse_lgrps(cookie, &plgrp_todo, optarg) < 0)
1430*c6402783Sakolb 				usage(EXIT_FAILURE);
1431*c6402783Sakolb 
1432*c6402783Sakolb 			/* If there are no valid lgroups exit immediately */
1433*c6402783Sakolb 			if (plgrp_todo.nlgrps == 0) {
1434*c6402783Sakolb 				(void) fprintf(stderr,
1435*c6402783Sakolb 				    gettext("%s: no valid lgroups specified"
1436*c6402783Sakolb 					" for -%c\n\n"),
1437*c6402783Sakolb 				    progname, c);
1438*c6402783Sakolb 				    usage(EXIT_FAILURE);
1439*c6402783Sakolb 			}
1440*c6402783Sakolb 
1441*c6402783Sakolb 			break;
1442*c6402783Sakolb 
1443*c6402783Sakolb 		case 'A':	/* Set lgroup affinity */
1444*c6402783Sakolb 
1445*c6402783Sakolb 			/*
1446*c6402783Sakolb 			 * Fail if already specified option (besides -F)
1447*c6402783Sakolb 			 * or no more arguments
1448*c6402783Sakolb 			 */
1449*c6402783Sakolb 			if (opt_seen || optind >= argc) {
1450*c6402783Sakolb 				usage(EXIT_FAILURE);
1451*c6402783Sakolb 			}
1452*c6402783Sakolb 			opt_seen = 1;
1453*c6402783Sakolb 
1454*c6402783Sakolb 			plgrp_todo.op = PLGRP_AFFINITY_SET;
1455*c6402783Sakolb 
1456*c6402783Sakolb 			/*
1457*c6402783Sakolb 			 * 'affstring' is the unparsed prtion of the affinity
1458*c6402783Sakolb 			 * specification like 1,2/none,2/weak,0/strong
1459*c6402783Sakolb 			 *
1460*c6402783Sakolb 			 * 'next' is the next affinity specification to parse.
1461*c6402783Sakolb 			 */
1462*c6402783Sakolb 			affstring = optarg;
1463*c6402783Sakolb 			while (affstring != NULL && strlen(affstring) > 0) {
1464*c6402783Sakolb 				char	*next;
1465*c6402783Sakolb 
1466*c6402783Sakolb 				/*
1467*c6402783Sakolb 				 * affstring points to the first affinity
1468*c6402783Sakolb 				 * specification. Split the string by
1469*c6402783Sakolb 				 * DELIMIT_AFF separator and parse lgroups and
1470*c6402783Sakolb 				 * affinity value separately.
1471*c6402783Sakolb 				 */
1472*c6402783Sakolb 				s = strchr(affstring, DELIMIT_AFF);
1473*c6402783Sakolb 				if (s == NULL) {
1474*c6402783Sakolb 					(void) fprintf(stderr,
1475*c6402783Sakolb 					    gettext("%s: invalid "
1476*c6402783Sakolb 						"syntax >%s<\n"),
1477*c6402783Sakolb 					    progname, affstring);
1478*c6402783Sakolb 					usage(EXIT_FAILURE);
1479*c6402783Sakolb 				}
1480*c6402783Sakolb 
1481*c6402783Sakolb 				aff = parse_lgrp_affinity(s, &next);
1482*c6402783Sakolb 				if (aff == LGRP_AFF_INVALID) {
1483*c6402783Sakolb 					(void) fprintf(stderr,
1484*c6402783Sakolb 					    gettext("%s: invalid "
1485*c6402783Sakolb 						"affinity >%s<\n"),
1486*c6402783Sakolb 					    progname, affstring);
1487*c6402783Sakolb 					usage(EXIT_FAILURE);
1488*c6402783Sakolb 				}
1489*c6402783Sakolb 
1490*c6402783Sakolb 				/*
1491*c6402783Sakolb 				 * next should either point to the empty string
1492*c6402783Sakolb 				 * or to the DELIMIT_AFF_LST separator.
1493*c6402783Sakolb 				 */
1494*c6402783Sakolb 				if (*next != '\0') {
1495*c6402783Sakolb 					if (*next != DELIMIT_AFF_LST) {
1496*c6402783Sakolb 						(void) fprintf(stderr,
1497*c6402783Sakolb 						    gettext("%s: invalid "
1498*c6402783Sakolb 							"syntax >%s<\n"),
1499*c6402783Sakolb 						    progname, next);
1500*c6402783Sakolb 						usage(EXIT_FAILURE);
1501*c6402783Sakolb 					}
1502*c6402783Sakolb 					*next = '\0';
1503*c6402783Sakolb 					next++;
1504*c6402783Sakolb 				}
1505*c6402783Sakolb 
1506*c6402783Sakolb 
1507*c6402783Sakolb 				/*
1508*c6402783Sakolb 				 * Now parse the list of lgroups
1509*c6402783Sakolb 				 */
1510*c6402783Sakolb 				if (parse_lgrps(cookie, &plgrp_todo,
1511*c6402783Sakolb 					affstring) < 0) {
1512*c6402783Sakolb 					usage(EXIT_FAILURE);
1513*c6402783Sakolb 				}
1514*c6402783Sakolb 
1515*c6402783Sakolb 				/*
1516*c6402783Sakolb 				 * Set desired affinity for specified lgroup to
1517*c6402783Sakolb 				 * the specified affinity.
1518*c6402783Sakolb 				 */
1519*c6402783Sakolb 				for (i = 0; i < plgrp_todo.nlgrps; i++) {
1520*c6402783Sakolb 					if (plgrp_todo.affs[i] ==
1521*c6402783Sakolb 					    LGRP_AFF_INVALID)
1522*c6402783Sakolb 						plgrp_todo.affs[i] = aff;
1523*c6402783Sakolb 				}
1524*c6402783Sakolb 
1525*c6402783Sakolb 				/*
1526*c6402783Sakolb 				 * We processed the leftmost element of the
1527*c6402783Sakolb 				 * list. Advance affstr to the remaining part of
1528*c6402783Sakolb 				 * the list. and repeat.
1529*c6402783Sakolb 				 */
1530*c6402783Sakolb 				affstring = next;
1531*c6402783Sakolb 			}
1532*c6402783Sakolb 
1533*c6402783Sakolb 			/*
1534*c6402783Sakolb 			 * If there are no valid lgroups, exit immediately
1535*c6402783Sakolb 			 */
1536*c6402783Sakolb 			if (plgrp_todo.nlgrps == 0) {
1537*c6402783Sakolb 				(void) fprintf(stderr,
1538*c6402783Sakolb 				    gettext("%s: no valid lgroups specified "
1539*c6402783Sakolb 				    "for -%c\n\n"), progname, c);
1540*c6402783Sakolb 				    usage(EXIT_FAILURE);
1541*c6402783Sakolb 			}
1542*c6402783Sakolb 
1543*c6402783Sakolb 			break;
1544*c6402783Sakolb 
1545*c6402783Sakolb 		case 'F':	/* Force */
1546*c6402783Sakolb 
1547*c6402783Sakolb 			/*
1548*c6402783Sakolb 			 * Only allow one occurrence
1549*c6402783Sakolb 			 */
1550*c6402783Sakolb 			if (Fflag != 0) {
1551*c6402783Sakolb 				usage(EXIT_FAILURE);
1552*c6402783Sakolb 			}
1553*c6402783Sakolb 
1554*c6402783Sakolb 			/*
1555*c6402783Sakolb 			 * Set flag to force /proc to grab process even though
1556*c6402783Sakolb 			 * it's been grabbed by another process already
1557*c6402783Sakolb 			 */
1558*c6402783Sakolb 			Fflag = PGRAB_FORCE;
1559*c6402783Sakolb 			break;
1560*c6402783Sakolb 
1561*c6402783Sakolb 		case '?':	/* Unrecognized option */
1562*c6402783Sakolb 		default:
1563*c6402783Sakolb 			usage(EXIT_FAILURE);
1564*c6402783Sakolb 			break;
1565*c6402783Sakolb 
1566*c6402783Sakolb 		}
1567*c6402783Sakolb 	}
1568*c6402783Sakolb 
1569*c6402783Sakolb 	/*
1570*c6402783Sakolb 	 * Should have more arguments left at least for PID or core
1571*c6402783Sakolb 	 */
1572*c6402783Sakolb 	if (optind >= argc)
1573*c6402783Sakolb 		usage(EXIT_FAILURE);
1574*c6402783Sakolb 
1575*c6402783Sakolb 	(void) lgrp_fini(cookie);
1576*c6402783Sakolb 
1577*c6402783Sakolb 	/*
1578*c6402783Sakolb 	 * Print heading and process each [pid | core]/lwps argument
1579*c6402783Sakolb 	 */
1580*c6402783Sakolb 	print_heading(plgrp_todo.op);
1581*c6402783Sakolb 	for (i = optind; i < argc && !interrupt; i++) {
1582*c6402783Sakolb 		do_process(argv[i], &plgrp_todo, Fflag);
1583*c6402783Sakolb 	}
1584*c6402783Sakolb 
1585*c6402783Sakolb 	if (plgrp_todo.nthreads == 0) {
1586*c6402783Sakolb 		(void) fprintf(stderr, gettext("%s: no matching LWPs found\n"),
1587*c6402783Sakolb 		    progname);
1588*c6402783Sakolb 	}
1589*c6402783Sakolb 
1590*c6402783Sakolb 	return ((nerrors ||interrupt) ? EXIT_NONFATAL : EXIT_SUCCESS);
1591*c6402783Sakolb }
1592