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