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
usage(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 *
basename(char * cp)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 *
psr_action_lookup(int action)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
psr_set_state(processorid_t cpu,int action,psr_action_t * pac,int mustexist)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
do_range(processorid_t first,processorid_t last,int action,psr_action_t * pac)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
main(int argc,char * argv[])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