xref: /illumos-gate/usr/src/cmd/psradm/psradm.c (revision dfc4fe31363cc213fe0423dc162bc08298c796cd)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Copyright 2019 Joyent, Inc.
29  */
30 
31 #include <sys/types.h>
32 #include <sys/procset.h>
33 #include <sys/processor.h>
34 #include <unistd.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <syslog.h>
40 #include <time.h>
41 #include <utmpx.h>
42 #include <assert.h>
43 #include <stdbool.h>
44 
45 static char	*cmdname;	/* command name for messages */
46 
47 static char	verbose;	/* non-zero if the -v option has been given */
48 static char	all_flag;	/* non-zero if the -a option has been given */
49 static char	force;		/* non-zero if the -F option has been given */
50 static char	log_open;	/* non-zero if openlog() has been called */
51 
52 static struct utmpx ut;		/* structure for logging to /etc/wtmpx. */
53 
54 static char	*basename(char *);
55 
56 static void
57 usage(void)
58 {
59 	(void) fprintf(stderr, "usage:\n"
60 	    "\t%s [-F] -f|-n|-i|-s [-v] processor_id ...\n"
61 	    "\t%s -a -f|-n|-i [-v]\n"
62 	    "\t%s -aS [-v]\n",
63 	    cmdname, cmdname, cmdname);
64 }
65 
66 /*
67  * Find base name of filename.
68  */
69 static char *
70 basename(char *cp)
71 {
72 	char *sp;
73 
74 	if ((sp = strrchr(cp, '/')) != NULL)
75 		return (sp + 1);
76 	return (cp);
77 }
78 
79 typedef struct _psr_action {
80 	int	p_op;
81 	char	*p_state;
82 	char	*p_action;
83 	char	*p_wtmp;
84 } psr_action_t;
85 
86 static psr_action_t psr_action[] = {
87 	{ P_ONLINE,	"on-line",	"brought",	"on"	},
88 	{ P_OFFLINE,	"off-line",	"taken",	"off"	},
89 	{ P_NOINTR,	"no-intr",	"set to",	"ni"	},
90 	{ P_SPARE,	"spare",	"marked",	"spr"	},
91 	{ P_FAULTED,	"faulted",	"marked",	"flt"	},
92 	{ P_DISABLED,	"disabled",	"set as",	"dis"	},
93 };
94 
95 static int	psr_actions = sizeof (psr_action) / sizeof (psr_action_t);
96 
97 static psr_action_t *
98 psr_action_lookup(int action)
99 {
100 	int	i;
101 
102 	for (i = 0; i < psr_actions; ++i) {
103 		if (psr_action[i].p_op == action) {
104 			return (&psr_action[i]);
105 		}
106 	}
107 	return (NULL);
108 }
109 
110 /*
111  * Set processor state.
112  *	Return non-zero if a processor was found.
113  *	Print messages and update wtmp and the system log.
114  *	If mustexist is set, it is an error if a processor isn't there.
115  */
116 
117 static int
118 psr_set_state(processorid_t cpu, int action, psr_action_t *pac, int mustexist)
119 {
120 	int	old_state;
121 	int	err;
122 	time_t	now;
123 	char	buf[80];
124 
125 	old_state = p_online(cpu, P_STATUS);
126 	if (old_state < 0) {
127 		if (errno == EINVAL && !mustexist)
128 			return (0);	/* no such processor */
129 		err = errno;		/* in case sprintf smashes errno */
130 		(void) snprintf(buf, sizeof (buf), "%s: processor %d",
131 		    cmdname, cpu);
132 		errno = err;
133 		perror(buf);
134 		return (-1);
135 	}
136 
137 	if (old_state == P_FAULTED && action != P_FAULTED && !force) {
138 		(void) printf("%s: processor %d in faulted state; "
139 		    "add -F option to force change\n", cmdname, cpu);
140 		return (-1);
141 	}
142 
143 	old_state = p_online(cpu, force ? action | P_FORCED : action);
144 	if (old_state < 0) {
145 		if (errno == EINVAL && !mustexist)
146 			return (0);	/* no such processor */
147 		err = errno;
148 		(void) snprintf(buf, sizeof (buf), "%s: processor %d",
149 		    cmdname, cpu);
150 		errno = err;
151 		perror(buf);
152 		return (-1);
153 	}
154 	if (old_state == action) {
155 		if (verbose)
156 			(void) printf("processor %d already %s.\n", cpu,
157 			    pac->p_state);
158 		return (1);		/* no change */
159 	}
160 
161 	(void) snprintf(buf, sizeof (buf), "processor %d %s %s.",
162 	    cpu, pac->p_action, pac->p_state);
163 
164 	if (verbose)
165 		(void) printf("%s\n", buf);
166 
167 	/*
168 	 * Log the change.
169 	 */
170 	if (!log_open) {
171 		log_open = 1;
172 		openlog(cmdname, LOG_CONS, LOG_USER);	/* open syslog */
173 		(void) setlogmask(LOG_UPTO(LOG_INFO));
174 
175 		ut.ut_pid = getpid();
176 		ut.ut_type = USER_PROCESS;
177 		(void) strncpy(ut.ut_user, "psradm", sizeof (ut.ut_user) - 1);
178 	}
179 
180 	syslog(LOG_INFO, "%s", buf);
181 
182 	/*
183 	 * Update wtmp.
184 	 */
185 	(void) snprintf(ut.ut_line, sizeof (ut.ut_line), PSRADM_MSG,
186 	    cpu, pac->p_wtmp);
187 	(void) time(&now);
188 	ut.ut_xtime = now;
189 	updwtmpx(WTMPX_FILE, &ut);
190 
191 	return (1);	/* the processor exists and no errors occurred */
192 }
193 
194 static int
195 do_range(processorid_t first, processorid_t last, int action,
196     psr_action_t *pac)
197 {
198 	processorid_t cpu;
199 	int error = 0;
200 	int rv;
201 	int found_one = 0;
202 
203 	for (cpu = first; cpu <= last; cpu++) {
204 		if ((rv = psr_set_state(cpu, action, pac, 0)) > 0)
205 			found_one = 1;
206 		else if (rv < 0)
207 			error = 1;
208 	}
209 	if (!found_one && error == 0) {
210 		(void) fprintf(stderr, "%s: no processors in range %d-%d\n",
211 		    cmdname, first, last);
212 		error = 1;
213 	}
214 	return (error);
215 }
216 
217 int
218 main(int argc, char *argv[])
219 {
220 	int	c;
221 	int	action = 0;
222 	processorid_t	cpu;
223 	processorid_t	cpuid_max;
224 	char	*errptr;
225 	int	errors;
226 	psr_action_t	*pac;
227 	bool disable_smt = 0;
228 
229 	cmdname = basename(argv[0]);
230 
231 	while ((c = getopt(argc, argv, "afFinsSv")) != EOF) {
232 		switch (c) {
233 
234 		case 'a':		/* applies to all possible CPUs */
235 			all_flag = 1;
236 			break;
237 
238 		case 'F':
239 			force = 1;
240 			break;
241 
242 		case 'S':
243 			disable_smt = 1;
244 			break;
245 
246 		case 'f':
247 		case 'i':
248 		case 'n':
249 		case 's':
250 			if (action != 0 && action != c) {
251 				(void) fprintf(stderr,
252 				    "%s: options -f, -n, -i, and -s are "
253 				    "mutually exclusive.\n", cmdname);
254 				usage();
255 				return (2);
256 			}
257 			action = c;
258 			break;
259 
260 		case 'v':
261 			verbose = 1;
262 			break;
263 
264 		default:
265 			usage();
266 			return (2);
267 		}
268 	}
269 
270 	if (disable_smt) {
271 		if (!all_flag) {
272 			fprintf(stderr, "%s: -S must be used with -a.\n",
273 			    cmdname);
274 			usage();
275 			return (2);
276 		}
277 
278 		if (force || action != 0 || argc != optind) {
279 			usage();
280 			return (2);
281 		}
282 
283 		if (p_online(P_ALL_SIBLINGS, P_DISABLED) == -1) {
284 			fprintf(stderr, "Failed to disable simultaneous "
285 			    "multi-threading: %s\n", strerror(errno));
286 			return (EXIT_FAILURE);
287 		}
288 
289 		return (EXIT_SUCCESS);
290 	}
291 
292 	switch (action) {
293 	case 'f':
294 		action = P_OFFLINE;
295 		break;
296 	case 'i':
297 		action = P_NOINTR;
298 		break;
299 	case 'n':
300 		action = P_ONLINE;
301 		break;
302 	case 's':
303 		action = P_SPARE;
304 		break;
305 	default:
306 		if (force != 0) {
307 			/*
308 			 * The -F option without other transition options
309 			 * puts processor(s) into faulted state.
310 			 */
311 			action = P_FAULTED;
312 			break;
313 		}
314 		(void) fprintf(stderr,
315 		    "%s: option -f, -n, -s or -i must "
316 		    "be specified.\n", cmdname);
317 		usage();
318 		return (2);
319 	}
320 
321 	pac = psr_action_lookup(action);
322 	assert(pac != NULL);
323 
324 	errors = 0;
325 	if (all_flag) {
326 		if (argc != optind) {
327 			usage();
328 			return (2);
329 		}
330 		cpuid_max = (processorid_t)sysconf(_SC_CPUID_MAX);
331 		for (cpu = 0; cpu <= cpuid_max; cpu++) {
332 			if (psr_set_state(cpu, action, pac, 0) < 0)
333 				errors = 1;
334 		}
335 	} else {
336 		argc -= optind;
337 		if (argc <= 0) {
338 			usage();	/* not enough arguments */
339 			return (2);
340 		}
341 		for (argv += optind; argc > 0; argv++, argc--) {
342 			if (strchr(*argv, '-') == NULL) {
343 				/* individual processor id */
344 				cpu = (processorid_t)
345 				    strtol(*argv, &errptr, 10);
346 				if (errptr != NULL && *errptr != '\0') {
347 					(void) fprintf(stderr,
348 					    "%s: invalid processor"
349 					    " ID %s\n", cmdname, *argv);
350 					errors = 2;
351 					continue;
352 				}
353 				if (psr_set_state(cpu, action, pac, 1) < 0)
354 					errors = 1;
355 			} else {
356 				/* range of processors */
357 				processorid_t first, last;
358 
359 				first = (processorid_t)
360 				    strtol(*argv, &errptr, 10);
361 				if (*errptr++ != '-') {
362 					(void) fprintf(stderr,
363 					    "%s: invalid processor"
364 					    " range %s\n", cmdname, *argv);
365 					errors = 2;
366 					continue;
367 				}
368 				last = (processorid_t)
369 				    strtol(errptr, &errptr, 10);
370 				if ((errptr != NULL && *errptr != '\0') ||
371 				    last < first || first < 0) {
372 					(void) fprintf(stderr,
373 					    "%s: invalid processor"
374 					    " range %s\n", cmdname, *argv);
375 					errors = 2;
376 					continue;
377 				}
378 				if (do_range(first, last, action, pac))
379 					errors = 1;
380 			}
381 		}
382 	}
383 	if (log_open) {
384 		closelog();
385 	}
386 	return (errors);
387 }
388