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 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <sys/types.h>
30 #include <sys/procset.h>
31 #include <sys/processor.h>
32 #include <unistd.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <errno.h>
37 #include <syslog.h>
38 #include <time.h>
39 #include <utmpx.h>
40 #include <assert.h>
41
42 static char *cmdname; /* command name for messages */
43
44 static char verbose; /* non-zero if the -v option has been given */
45 static char all_flag; /* non-zero if the -a option has been given */
46 static char force; /* non-zero if the -F option has been given */
47 static char log_open; /* non-zero if openlog() has been called */
48
49 static struct utmpx ut; /* structure for logging to /etc/wtmpx. */
50
51 static char *basename(char *);
52
53 static void
usage(void)54 usage(void)
55 {
56 (void) fprintf(stderr,
57 "usage: \n\t%s [-F] -f|-n|-i|-s [-v] processor_id ...\n"
58 "\t%s -a -f|-n|-i [-v]\n", cmdname, cmdname);
59 }
60
61 /*
62 * Find base name of filename.
63 */
64 static char *
basename(char * cp)65 basename(char *cp)
66 {
67 char *sp;
68
69 if ((sp = strrchr(cp, '/')) != NULL)
70 return (sp + 1);
71 return (cp);
72 }
73
74 typedef struct _psr_action {
75 int p_op;
76 char *p_state;
77 char *p_action;
78 char *p_wtmp;
79 } psr_action_t;
80
81 static psr_action_t psr_action[] = {
82 { P_ONLINE, "on-line", "brought", "on" },
83 { P_OFFLINE, "off-line", "taken", "off" },
84 { P_NOINTR, "no-intr", "set to", "ni" },
85 { P_SPARE, "spare", "marked", "spr" },
86 { P_FAULTED, "faulted", "marked", "flt" },
87 };
88
89 static int psr_actions = sizeof (psr_action) / sizeof (psr_action_t);
90
91 static psr_action_t *
psr_action_lookup(int action)92 psr_action_lookup(int action)
93 {
94 int i;
95
96 for (i = 0; i < psr_actions; ++i) {
97 if (psr_action[i].p_op == action) {
98 return (&psr_action[i]);
99 }
100 }
101 return (NULL);
102 }
103
104 /*
105 * Set processor state.
106 * Return non-zero if a processor was found.
107 * Print messages and update wtmp and the system log.
108 * If mustexist is set, it is an error if a processor isn't there.
109 */
110
111 static int
psr_set_state(processorid_t cpu,int action,psr_action_t * pac,int mustexist)112 psr_set_state(processorid_t cpu, int action, psr_action_t *pac, int mustexist)
113 {
114 int old_state;
115 int err;
116 time_t now;
117 char buf[80];
118
119 old_state = p_online(cpu, P_STATUS);
120 if (old_state < 0) {
121 if (errno == EINVAL && !mustexist)
122 return (0); /* no such processor */
123 err = errno; /* in case sprintf smashes errno */
124 (void) snprintf(buf, sizeof (buf), "%s: processor %d",
125 cmdname, cpu);
126 errno = err;
127 perror(buf);
128 return (-1);
129 }
130
131 if (old_state == P_FAULTED && action != P_FAULTED && !force) {
132 (void) printf("%s: processor %d in faulted state; "
133 "add -F option to force change\n", cmdname, cpu);
134 return (-1);
135 }
136
137 old_state = p_online(cpu, force ? action | P_FORCED : action);
138 if (old_state < 0) {
139 if (errno == EINVAL && !mustexist)
140 return (0); /* no such processor */
141 err = errno;
142 (void) snprintf(buf, sizeof (buf), "%s: processor %d",
143 cmdname, cpu);
144 errno = err;
145 perror(buf);
146 return (-1);
147 }
148 if (old_state == action) {
149 if (verbose)
150 (void) printf("processor %d already %s.\n", cpu,
151 pac->p_state);
152 return (1); /* no change */
153 }
154
155 (void) snprintf(buf, sizeof (buf), "processor %d %s %s.",
156 cpu, pac->p_action, pac->p_state);
157
158 if (verbose)
159 (void) printf("%s\n", buf);
160
161 /*
162 * Log the change.
163 */
164 if (!log_open) {
165 log_open = 1;
166 openlog(cmdname, LOG_CONS, LOG_USER); /* open syslog */
167 (void) setlogmask(LOG_UPTO(LOG_INFO));
168
169 ut.ut_pid = getpid();
170 ut.ut_type = USER_PROCESS;
171 (void) strncpy(ut.ut_user, "psradm", sizeof (ut.ut_user) - 1);
172 }
173
174 syslog(LOG_INFO, "%s", buf);
175
176 /*
177 * Update wtmp.
178 */
179 (void) snprintf(ut.ut_line, sizeof (ut.ut_line), PSRADM_MSG,
180 cpu, pac->p_wtmp);
181 (void) time(&now);
182 ut.ut_xtime = now;
183 updwtmpx(WTMPX_FILE, &ut);
184
185 return (1); /* the processor exists and no errors occurred */
186 }
187
188 static int
do_range(processorid_t first,processorid_t last,int action,psr_action_t * pac)189 do_range(processorid_t first, processorid_t last, int action,
190 psr_action_t *pac)
191 {
192 processorid_t cpu;
193 int error = 0;
194 int rv;
195 int found_one = 0;
196
197 for (cpu = first; cpu <= last; cpu++) {
198 if ((rv = psr_set_state(cpu, action, pac, 0)) > 0)
199 found_one = 1;
200 else if (rv < 0)
201 error = 1;
202 }
203 if (!found_one && error == 0) {
204 (void) fprintf(stderr, "%s: no processors in range %d-%d\n",
205 cmdname, first, last);
206 error = 1;
207 }
208 return (error);
209 }
210
211 int
main(int argc,char * argv[])212 main(int argc, char *argv[])
213 {
214 int c;
215 int action = 0;
216 processorid_t cpu;
217 processorid_t cpuid_max;
218 char *errptr;
219 int errors;
220 psr_action_t *pac;
221
222 cmdname = basename(argv[0]);
223
224 while ((c = getopt(argc, argv, "afFinsv")) != EOF) {
225 switch (c) {
226
227 case 'a': /* applies to all possible CPUs */
228 all_flag = 1;
229 break;
230
231 case 'F':
232 force = 1;
233 break;
234
235 case 'f':
236 case 'i':
237 case 'n':
238 case 's':
239 if (action != 0 && action != c) {
240 (void) fprintf(stderr,
241 "%s: options -f, -n, -i, and -s are "
242 "mutually exclusive.\n", cmdname);
243 usage();
244 return (2);
245 }
246 action = c;
247 break;
248
249 case 'v':
250 verbose = 1;
251 break;
252
253 default:
254 usage();
255 return (2);
256 }
257 }
258
259 switch (action) {
260 case 'f':
261 action = P_OFFLINE;
262 break;
263 case 'i':
264 action = P_NOINTR;
265 break;
266 case 'n':
267 action = P_ONLINE;
268 break;
269 case 's':
270 action = P_SPARE;
271 break;
272 default:
273 if (force != 0) {
274 /*
275 * The -F option without other transition options
276 * puts processor(s) into faulted state.
277 */
278 action = P_FAULTED;
279 break;
280 }
281 (void) fprintf(stderr,
282 "%s: option -f, -n, -s or -i must "
283 "be specified.\n", cmdname);
284 usage();
285 return (2);
286 }
287
288 pac = psr_action_lookup(action);
289 assert(pac != NULL);
290
291 errors = 0;
292 if (all_flag) {
293 if (argc != optind) {
294 usage();
295 return (2);
296 }
297 cpuid_max = (processorid_t)sysconf(_SC_CPUID_MAX);
298 for (cpu = 0; cpu <= cpuid_max; cpu++) {
299 if (psr_set_state(cpu, action, pac, 0) < 0)
300 errors = 1;
301 }
302 } else {
303 argc -= optind;
304 if (argc <= 0) {
305 usage(); /* not enough arguments */
306 return (2);
307 }
308 for (argv += optind; argc > 0; argv++, argc--) {
309 if (strchr(*argv, '-') == NULL) {
310 /* individual processor id */
311 cpu = (processorid_t)
312 strtol(*argv, &errptr, 10);
313 if (errptr != NULL && *errptr != '\0') {
314 (void) fprintf(stderr,
315 "%s: invalid processor"
316 " ID %s\n", cmdname, *argv);
317 errors = 2;
318 continue;
319 }
320 if (psr_set_state(cpu, action, pac, 1) < 0)
321 errors = 1;
322 } else {
323 /* range of processors */
324 processorid_t first, last;
325
326 first = (processorid_t)
327 strtol(*argv, &errptr, 10);
328 if (*errptr++ != '-') {
329 (void) fprintf(stderr,
330 "%s: invalid processor"
331 " range %s\n", cmdname, *argv);
332 errors = 2;
333 continue;
334 }
335 last = (processorid_t)
336 strtol(errptr, &errptr, 10);
337 if ((errptr != NULL && *errptr != '\0') ||
338 last < first || first < 0) {
339 (void) fprintf(stderr,
340 "%s: invalid processor"
341 " range %s\n", cmdname, *argv);
342 errors = 2;
343 continue;
344 }
345 if (do_range(first, last, action, pac))
346 errors = 1;
347 }
348 }
349 }
350 if (log_open) {
351 closelog();
352 }
353 return (errors);
354 }
355