Print this page
6535 Add pbind -e
Reviewed by: Mohamed Khalfella <khalfella@gmail.com>
Reviewed by: Cody Mello <melloc@joyent.com>
Reviewed by: Albert Lee <trisk@omniti.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/pbind/pbind.c
+++ new/usr/src/cmd/pbind/pbind.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License, Version 1.0 only
6 6 * (the "License"). You may not use this file except in compliance
7 7 * with the License.
8 8 *
9 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 10 * or http://www.opensolaris.org/os/licensing.
11 11 * See the License for the specific language governing permissions
12 12 * and limitations under the License.
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
13 13 *
14 14 * When distributing Covered Code, include this CDDL HEADER in each
15 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 16 * If applicable, add the following below this CDDL HEADER, with the
17 17 * fields enclosed by brackets "[]" replaced with your own identifying
18 18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 19 *
20 20 * CDDL HEADER END
21 21 */
22 22 /*
23 + * Copyright 2015 Ryan Zezeski
23 24 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 25 * Use is subject to license terms.
25 26 */
26 27
27 -#pragma ident "%Z%%M% %I% %E% SMI"
28 -
29 28 /*
30 29 * pbind - bind a process to a processor (non-exclusively)
31 30 */
32 31
33 32 #include <sys/types.h>
34 33 #include <sys/procset.h>
35 34 #include <sys/processor.h>
36 35 #include <stdio.h>
37 36 #include <stdlib.h>
38 37 #include <string.h>
39 38 #include <procfs.h>
40 39 #include <fcntl.h>
41 40 #include <errno.h>
42 41 #include <dirent.h>
43 42 #include <locale.h>
44 43 #include <libproc.h>
45 44 #include <stdarg.h>
46 45
↓ open down ↓ |
8 lines elided |
↑ open up ↑ |
47 46 #if !defined(TEXT_DOMAIN) /* should be defined by cc -D */
48 47 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
49 48 #endif
50 49
51 50 #define ERR_OK 0 /* exit status for success */
52 51 #define ERR_FAIL 1 /* exit status for errors */
53 52 #define ERR_USAGE 2 /* exit status for usage errors */
54 53
55 54 static char *progname;
56 55 static char bflag;
56 +static char eflag;
57 57 static char qflag;
58 58 static char Qflag;
59 59 static char uflag;
60 60 static char Uflag;
61 61 static int errors;
62 62
63 63 #define MAX_PROCFS_PATH 80
64 64
65 65 /*PRINTFLIKE1*/
66 66 static void
67 67 warn(char *format, ...)
68 68 {
69 69 int err = errno;
70 70 va_list alist;
71 71
72 72 (void) fprintf(stderr, "%s: ", progname);
73 73 va_start(alist, format);
74 74 (void) vfprintf(stderr, format, alist);
75 75 va_end(alist);
76 76 if (strchr(format, '\n') == NULL)
77 77 (void) fprintf(stderr, ": %s\n", strerror(err));
78 78 }
79 79
80 80 /*PRINTFLIKE1*/
81 81 static void
82 82 die(char *format, ...)
83 83 {
84 84 int err = errno;
85 85 va_list alist;
86 86
87 87 (void) fprintf(stderr, "%s: ", progname);
88 88 va_start(alist, format);
89 89 (void) vfprintf(stderr, format, alist);
90 90 va_end(alist);
91 91 if (strchr(format, '\n') == NULL)
92 92 (void) fprintf(stderr, ": %s\n", strerror(err));
93 93 exit(ERR_FAIL);
94 94 }
95 95
96 96 /*
97 97 * Output for query.
98 98 */
99 99 static void
100 100 query_out(id_t pid, id_t lwpid, processorid_t cpu)
101 101 {
102 102 char *proclwp;
103 103 char pidstr[21];
104 104
105 105 if (lwpid == -1) {
106 106 (void) snprintf(pidstr, 20, "%d", (int)pid);
107 107 proclwp = "process";
108 108 } else {
109 109 (void) snprintf(pidstr, 20, "%d/%d", (int)pid, (int)lwpid);
110 110 proclwp = "lwp";
111 111 }
112 112
113 113 if (cpu == PBIND_NONE)
114 114 (void) printf(gettext("%s id %s: not bound\n"),
115 115 proclwp, pidstr);
116 116 else
117 117 (void) printf(gettext("%s id %s: %d\n"),
118 118 proclwp, pidstr, cpu);
119 119 }
120 120
121 121 /*
122 122 * Binding error.
123 123 */
124 124 static void
125 125 bind_err(processorid_t cpu, id_t pid, id_t lwpid, int err)
126 126 {
127 127 char *msg;
128 128
129 129 switch (cpu) {
130 130 case PBIND_NONE:
131 131 msg = gettext("unbind");
132 132 break;
133 133 case PBIND_QUERY:
134 134 msg = gettext("query");
135 135 break;
136 136 default:
137 137 msg = gettext("bind");
138 138 break;
139 139 }
140 140 if (lwpid == -1)
141 141 warn(gettext("cannot %s pid %d: %s\n"), msg,
142 142 (int)pid, strerror(err));
143 143 else
144 144 warn(gettext("cannot %s lwpid %d/%d: %s\n"), msg,
145 145 (int)pid, (int)lwpid, strerror(err));
146 146 }
147 147
148 148 /*
149 149 * Output for bind.
150 150 */
151 151 static void
152 152 bind_out(id_t pid, id_t lwpid, processorid_t old, processorid_t new)
153 153 {
154 154 char *proclwp;
155 155 char pidstr[21];
156 156
157 157 if (lwpid == -1) {
↓ open down ↓ |
91 lines elided |
↑ open up ↑ |
158 158 (void) snprintf(pidstr, 20, "%d", (int)pid);
159 159 proclwp = "process";
160 160 } else {
161 161 (void) snprintf(pidstr, 20, "%d/%d", (int)pid, (int)lwpid);
162 162 proclwp = "lwp";
163 163 }
164 164
165 165 if (old == PBIND_NONE) {
166 166 if (new == PBIND_NONE)
167 167 (void) printf(gettext("%s id %s: was not bound, "
168 - "now not bound\n"), proclwp, pidstr);
168 + "now not bound\n"), proclwp, pidstr);
169 169 else
170 170 (void) printf(gettext("%s id %s: was not bound, "
171 - "now %d\n"), proclwp, pidstr, new);
171 + "now %d\n"), proclwp, pidstr, new);
172 172 } else {
173 173 if (new == PBIND_NONE)
174 174 (void) printf(gettext("%s id %s: was %d, "
175 - "now not bound\n"), proclwp, pidstr, old);
175 + "now not bound\n"), proclwp, pidstr, old);
176 176 else
177 177 (void) printf(gettext("%s id %s: was %d, "
178 - "now %d\n"), proclwp, pidstr, old, new);
178 + "now %d\n"), proclwp, pidstr, old, new);
179 179 }
180 180 }
181 181
182 182 static struct ps_prochandle *
183 183 grab_proc(id_t pid)
184 184 {
185 185 int ret;
186 186 struct ps_prochandle *Pr;
187 187
188 188 if ((Pr = Pgrab(pid, 0, &ret)) == NULL) {
189 189 warn(gettext("cannot control process %d: %s\n"),
190 190 (int)pid, Pgrab_error(ret));
191 191 errors = ERR_FAIL;
192 192 return (NULL);
193 193 }
194 194
195 195 /*
196 196 * Set run-on-last-close flag so the controlled process
197 197 * runs even if we die on a signal, and create an agent LWP.
198 198 */
199 199 if (Psetflags(Pr, PR_RLC) != 0 || Pcreate_agent(Pr) != 0) {
200 200 warn(gettext("cannot control process %d\n"), (int)pid);
201 201 errors = ERR_FAIL;
202 202 Prelease(Pr, 0);
203 203 return (NULL);
204 204 }
205 205 return (Pr);
206 206 }
207 207
208 208 static void
209 209 rele_proc(struct ps_prochandle *Pr)
210 210 {
211 211 if (Pr == NULL)
212 212 return;
213 213 Pdestroy_agent(Pr);
214 214 Prelease(Pr, 0);
215 215 }
216 216
217 217 static void
218 218 bind_lwp(struct ps_prochandle *Pr, id_t pid, id_t lwpid, processorid_t cpu)
219 219 {
220 220 processorid_t old_cpu;
221 221
222 222 if (pr_processor_bind(Pr, P_LWPID, lwpid, cpu, &old_cpu) < 0) {
223 223 bind_err(cpu, pid, lwpid, errno);
224 224 errors = ERR_FAIL;
225 225 } else {
226 226 if (qflag)
227 227 query_out(pid, lwpid, old_cpu);
228 228 else
229 229 bind_out(pid, lwpid, old_cpu, cpu);
230 230 }
231 231 }
232 232
233 233 /*
234 234 * Query, set, or clear bindings for the range of LWPs in the given process.
235 235 */
236 236 static int
237 237 do_lwps(id_t pid, const char *range, processorid_t cpu)
238 238 {
239 239 char procfile[MAX_PROCFS_PATH];
240 240 struct ps_prochandle *Pr;
241 241 struct prheader header;
242 242 processorid_t binding;
243 243 struct lwpsinfo *lwp;
244 244 char *lpsinfo, *ptr;
245 245 int nent, size;
246 246 int i, fd, found;
247 247
248 248 /*
249 249 * Report bindings for LWPs in process 'pid'.
250 250 */
251 251 (void) snprintf(procfile, MAX_PROCFS_PATH,
252 252 "/proc/%d/lpsinfo", (int)pid);
253 253 if ((fd = open(procfile, O_RDONLY)) < 0) {
254 254 if (errno == ENOENT)
255 255 errno = ESRCH;
256 256 bind_err(cpu, pid, -1, errno);
257 257 return (ERR_FAIL);
258 258 }
259 259 if (pread(fd, &header, sizeof (header), 0) != sizeof (header)) {
260 260 (void) close(fd);
261 261 bind_err(cpu, pid, -1, errno);
262 262 return (ERR_FAIL);
263 263 }
264 264 nent = header.pr_nent;
265 265 size = header.pr_entsize * nent;
266 266 ptr = lpsinfo = malloc(size);
267 267 if (lpsinfo == NULL) {
268 268 bind_err(cpu, pid, -1, errno);
269 269 return (ERR_FAIL);
270 270 }
271 271 if (pread(fd, lpsinfo, size, sizeof (header)) != size) {
272 272 bind_err(cpu, pid, -1, errno);
273 273 free(lpsinfo);
274 274 (void) close(fd);
275 275 return (ERR_FAIL);
276 276 }
277 277
278 278 if ((bflag || uflag) && (Pr = grab_proc(pid)) == NULL) {
279 279 free(lpsinfo);
280 280 (void) close(fd);
281 281 return (ERR_FAIL);
282 282 }
283 283 found = 0;
284 284 for (i = 0; i < nent; i++, ptr += header.pr_entsize) {
285 285 /*LINTED ALIGNMENT*/
286 286 lwp = (lwpsinfo_t *)ptr;
287 287 binding = lwp->pr_bindpro;
288 288 if (!proc_lwp_in_set(range, lwp->pr_lwpid))
289 289 continue;
290 290 found++;
291 291 if (bflag || uflag)
292 292 bind_lwp(Pr, pid, lwp->pr_lwpid, cpu);
293 293 else if (binding != PBIND_NONE)
294 294 query_out(pid, lwp->pr_lwpid, binding);
295 295 }
296 296 if (bflag || uflag)
297 297 rele_proc(Pr);
298 298 free(lpsinfo);
299 299 (void) close(fd);
300 300 if (found == 0) {
301 301 warn(gettext("cannot %s lwpid %d/%s: "
302 302 "No matching LWPs found\n"),
303 303 bflag ? "bind" : "query", pid, range);
304 304 return (ERR_FAIL);
305 305 }
306 306 return (ERR_OK);
307 307 }
308 308
309 309 /*ARGSUSED*/
310 310 static int
311 311 query_all_proc(psinfo_t *psinfo, lwpsinfo_t *lwpsinfo, void *arg)
312 312 {
313 313 id_t pid = psinfo->pr_pid;
314 314 processorid_t binding;
315 315
316 316 if (processor_bind(P_PID, pid, PBIND_QUERY, &binding) < 0) {
317 317 /*
318 318 * Ignore search errors. The process may have exited
319 319 * since we read the directory.
320 320 */
321 321 if (errno == ESRCH)
322 322 return (0);
323 323 bind_err(PBIND_QUERY, pid, -1, errno);
324 324 errors = ERR_FAIL;
325 325 return (0);
326 326 }
327 327 if (binding != PBIND_NONE)
328 328 query_out(pid, -1, binding);
329 329 return (0);
330 330 }
331 331
332 332 static int
333 333 query_all_lwp(psinfo_t *psinfo, lwpsinfo_t *lwpsinfo, void *arg)
334 334 {
335 335 id_t pid = psinfo->pr_pid;
336 336 id_t lwpid = lwpsinfo->pr_lwpid;
337 337 processorid_t *cpuid = arg;
↓ open down ↓ |
149 lines elided |
↑ open up ↑ |
338 338 processorid_t binding = lwpsinfo->pr_bindpro;
339 339
340 340 if (psinfo->pr_nlwp == 1)
341 341 lwpid = -1; /* report process bindings if only 1 lwp */
342 342 if ((cpuid != NULL && *cpuid == binding) ||
343 343 (cpuid == NULL && binding != PBIND_NONE))
344 344 query_out(pid, lwpid, binding);
345 345 return (0);
346 346 }
347 347
348 +/*
349 + * Execute the cmd with args while bound to cpu. Does not return:
350 + * either executes cmd successfully or dies trying.
351 + */
352 +static void
353 +exec_cmd(processorid_t cpu, char *cmd, char **args)
354 +{
355 + if (processor_bind(P_PID, P_MYID, cpu, NULL) == -1) {
356 + bind_err(cpu, getpid(), -1, errno);
357 + exit(ERR_FAIL);
358 + }
359 +
360 + if (execvp(cmd, args) == -1)
361 + die(gettext("failed to exec %s\n"), cmd);
362 +}
363 +
364 +/*
365 + * Attempt to parse str as a CPU identifier. Return the identifier or
366 + * die.
367 + */
368 +static processorid_t
369 +parse_cpu(char *str)
370 +{
371 + processorid_t cpu;
372 + char *endstr;
373 +
374 + cpu = strtol(str, &endstr, 10);
375 + if (endstr != NULL && *endstr != '\0' || cpu < 0)
376 + die(gettext("invalid processor ID %s\n"), optarg);
377 +
378 + return (cpu);
379 +}
380 +
348 381 static int
349 382 usage(void)
350 383 {
351 384 (void) fprintf(stderr,
352 385 gettext("usage: \n\t%1$s -b processor_id pid[/lwpids] ...\n"
386 + "\t%1$s -e processor_id cmd [args...]\n"
353 387 "\t%1$s -U [processor_id] ...\n"
354 388 "\t%1$s -Q [processor_id] ...\n"
355 389 "\t%1$s -u pid[/lwpids] ...\n"
356 390 "\t%1$s [-q] [pid[/lwpids] ...]\n"),
357 391 progname);
358 392 return (ERR_USAGE);
359 393 }
360 394
361 395 int
362 396 main(int argc, char *argv[])
363 397 {
364 398 int c;
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
365 399 int ret;
366 400 id_t pid;
367 401 processorid_t cpu, old_cpu;
368 402 char *endstr;
369 403
370 404 progname = argv[0]; /* put actual command name in messages */
371 405
372 406 (void) setlocale(LC_ALL, ""); /* setup localization */
373 407 (void) textdomain(TEXT_DOMAIN);
374 408
375 - while ((c = getopt(argc, argv, "b:qQuU")) != EOF) {
409 + while ((c = getopt(argc, argv, "b:e:qQuU")) != EOF) {
376 410 switch (c) {
377 411
378 412 case 'b':
379 413 bflag = 1;
380 - cpu = strtol(optarg, &endstr, 10);
381 - if (endstr != NULL && *endstr != '\0' || cpu < 0)
382 - die(gettext("invalid processor ID %s\n"),
383 - optarg);
414 + cpu = parse_cpu(optarg);
384 415 break;
385 416
417 + case 'e':
418 + eflag = 1;
419 + cpu = parse_cpu(optarg);
420 + break;
421 +
386 422 case 'q':
387 423 qflag = 1;
388 424 cpu = PBIND_QUERY;
389 425 break;
390 426
391 427 case 'Q':
392 428 Qflag = 1;
393 429 cpu = PBIND_QUERY;
394 430 break;
395 431
396 432 case 'u':
397 433 uflag = 1;
398 434 cpu = PBIND_NONE;
399 435 break;
400 436
401 437 case 'U':
↓ open down ↓ |
6 lines elided |
↑ open up ↑ |
402 438 Uflag = 1;
403 439 break;
404 440
405 441 default:
406 442 return (usage());
407 443 }
408 444 }
409 445
410 446
411 447 /*
412 - * Make sure that at most one of the options b, q, Q, u, or U
413 - * was specified.
448 + * Make sure that at most one of the options b, e, q, Q, u, or
449 + * U was specified.
414 450 */
415 - c = bflag + qflag + Qflag + uflag + Uflag;
451 + c = bflag + eflag + qflag + Qflag + uflag + Uflag;
416 452 if (c < 1) { /* nothing specified */
417 453 qflag = 1; /* default to query */
418 454 cpu = PBIND_QUERY;
419 455 } else if (c > 1) {
420 - warn(gettext("options -b, -q, -Q, -u and -U "
456 + warn(gettext("options -b, -e, -q, -Q, -u and -U "
421 457 "are mutually exclusive\n"));
422 458 return (usage());
423 459 }
424 460
425 461 errors = 0;
426 462 argc -= optind;
427 463 argv += optind;
428 464
429 465 /*
430 466 * Handle query of all processes.
431 467 */
432 468 if (argc == 0) {
433 469 if (bflag || uflag) {
434 470 warn(gettext("must specify at least one pid\n"));
435 471 return (usage());
436 472 }
473 + if (eflag) {
474 + warn(gettext("must specify command\n"));
475 + return (usage());
476 + }
437 477 if (Uflag) {
438 478 if (processor_bind(P_ALL, 0, PBIND_NONE, &old_cpu) != 0)
439 479 die(gettext("failed to unbind some LWPs"));
440 480 }
441 481 if (Qflag) {
442 482 (void) proc_walk(query_all_lwp, NULL, PR_WALK_LWP);
443 483 return (errors);
444 484 } else {
445 485 (void) proc_walk(query_all_proc, NULL, PR_WALK_PROC);
446 486 return (errors);
447 487 }
448 488 }
449 489
490 + if (eflag)
491 + exec_cmd(cpu, argv[0], argv);
492 +
450 493 if (Qflag || Uflag) {
451 494 /*
452 495 * Go through listed processor IDs.
453 496 */
454 497 for (; argc > 0; argv++, argc--) {
455 498 errno = 0;
456 499 cpu = (id_t)strtol(*argv, &endstr, 10);
457 500 if (errno != 0 || (endstr != NULL && *endstr != '\0') ||
458 501 p_online(cpu, P_STATUS) == -1) {
459 502 warn(gettext("invalid processor ID\n"));
460 503 continue;
461 504 }
462 505 if (Qflag) {
463 506 (void) proc_walk(query_all_lwp,
464 507 &cpu, PR_WALK_LWP);
465 508 continue;
466 509 }
467 510 if (Uflag) {
468 511 if (processor_bind(P_CPUID, cpu,
469 512 PBIND_NONE, &old_cpu) != 0) {
470 513 warn(gettext("failed to unbind from "
471 514 "processor %d"), (int)cpu);
472 515 errors = ERR_FAIL;
473 516 }
474 517 continue;
475 518 }
476 519 }
477 520 return (errors);
478 521 }
479 522
480 523 /*
481 524 * Go through listed process[/lwp_ranges].
482 525 */
483 526 for (; argc > 0; argv++, argc--) {
484 527 errno = 0;
485 528 pid = (id_t)strtol(*argv, &endstr, 10);
486 529 if (errno != 0 ||
487 530 (endstr != NULL && *endstr != '\0' && *endstr != '/')) {
488 531 warn(gettext("invalid process ID: %s\n"), *argv);
489 532 continue;
490 533 }
491 534 if (endstr != NULL && *endstr == '/') {
492 535 /*
493 536 * Handle lwp range case
494 537 */
495 538 const char *lwps = (const char *)(++endstr);
496 539 if (*lwps == '\0' ||
497 540 proc_lwp_range_valid(lwps) != 0) {
498 541 warn(gettext("invalid lwp range "
499 542 "for pid %d\n"), (int)pid);
500 543 errors = ERR_FAIL;
501 544 continue;
502 545 }
503 546 if (!qflag)
504 547 (void) proc_initstdio();
505 548 ret = do_lwps(pid, lwps, qflag ? PBIND_QUERY : cpu);
506 549 if (!qflag)
507 550 (void) proc_finistdio();
508 551 if (ret != ERR_OK)
509 552 errors = ret;
510 553 } else {
511 554 /*
512 555 * Handle whole process case.
513 556 */
514 557 if (processor_bind(P_PID, pid, cpu, &old_cpu) < 0) {
515 558 bind_err(cpu, pid, -1, errno);
516 559 errors = ERR_FAIL;
517 560 continue;
518 561 }
519 562 if (qflag)
520 563 query_out(pid, -1, old_cpu);
521 564 else
522 565 bind_out(pid, -1, old_cpu, cpu);
523 566 }
524 567 }
525 568 return (errors);
526 569 }
↓ open down ↓ |
67 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX