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 2004 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 /*
30 * pbind - bind a process to a processor (non-exclusively)
31 */
32
33 #include <sys/types.h>
34 #include <sys/procset.h>
35 #include <sys/processor.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <procfs.h>
40 #include <fcntl.h>
41 #include <errno.h>
42 #include <dirent.h>
43 #include <locale.h>
44 #include <libproc.h>
45 #include <stdarg.h>
46
47 #if !defined(TEXT_DOMAIN) /* should be defined by cc -D */
48 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
49 #endif
50
51 #define ERR_OK 0 /* exit status for success */
52 #define ERR_FAIL 1 /* exit status for errors */
53 #define ERR_USAGE 2 /* exit status for usage errors */
54
55 static char *progname;
56 static char bflag;
57 static char qflag;
58 static char Qflag;
59 static char uflag;
60 static char Uflag;
61 static int errors;
62
63 #define MAX_PROCFS_PATH 80
64
65 /*PRINTFLIKE1*/
66 static void
67 warn(char *format, ...)
68 {
69 int err = errno;
70 va_list alist;
71
72 (void) fprintf(stderr, "%s: ", progname);
73 va_start(alist, format);
74 (void) vfprintf(stderr, format, alist);
75 va_end(alist);
76 if (strchr(format, '\n') == NULL)
328 query_out(pid, -1, binding);
329 return (0);
330 }
331
332 static int
333 query_all_lwp(psinfo_t *psinfo, lwpsinfo_t *lwpsinfo, void *arg)
334 {
335 id_t pid = psinfo->pr_pid;
336 id_t lwpid = lwpsinfo->pr_lwpid;
337 processorid_t *cpuid = arg;
338 processorid_t binding = lwpsinfo->pr_bindpro;
339
340 if (psinfo->pr_nlwp == 1)
341 lwpid = -1; /* report process bindings if only 1 lwp */
342 if ((cpuid != NULL && *cpuid == binding) ||
343 (cpuid == NULL && binding != PBIND_NONE))
344 query_out(pid, lwpid, binding);
345 return (0);
346 }
347
348 static int
349 usage(void)
350 {
351 (void) fprintf(stderr,
352 gettext("usage: \n\t%1$s -b processor_id pid[/lwpids] ...\n"
353 "\t%1$s -U [processor_id] ...\n"
354 "\t%1$s -Q [processor_id] ...\n"
355 "\t%1$s -u pid[/lwpids] ...\n"
356 "\t%1$s [-q] [pid[/lwpids] ...]\n"),
357 progname);
358 return (ERR_USAGE);
359 }
360
361 int
362 main(int argc, char *argv[])
363 {
364 int c;
365 int ret;
366 id_t pid;
367 processorid_t cpu, old_cpu;
368 char *endstr;
369
370 progname = argv[0]; /* put actual command name in messages */
371
372 (void) setlocale(LC_ALL, ""); /* setup localization */
373 (void) textdomain(TEXT_DOMAIN);
374
375 while ((c = getopt(argc, argv, "b:qQuU")) != EOF) {
376 switch (c) {
377
378 case 'b':
379 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);
384 break;
385
386 case 'q':
387 qflag = 1;
388 cpu = PBIND_QUERY;
389 break;
390
391 case 'Q':
392 Qflag = 1;
393 cpu = PBIND_QUERY;
394 break;
395
396 case 'u':
397 uflag = 1;
398 cpu = PBIND_NONE;
399 break;
400
401 case 'U':
402 Uflag = 1;
403 break;
404
405 default:
406 return (usage());
407 }
408 }
409
410
411 /*
412 * Make sure that at most one of the options b, q, Q, u, or U
413 * was specified.
414 */
415 c = bflag + qflag + Qflag + uflag + Uflag;
416 if (c < 1) { /* nothing specified */
417 qflag = 1; /* default to query */
418 cpu = PBIND_QUERY;
419 } else if (c > 1) {
420 warn(gettext("options -b, -q, -Q, -u and -U "
421 "are mutually exclusive\n"));
422 return (usage());
423 }
424
425 errors = 0;
426 argc -= optind;
427 argv += optind;
428
429 /*
430 * Handle query of all processes.
431 */
432 if (argc == 0) {
433 if (bflag || uflag) {
434 warn(gettext("must specify at least one pid\n"));
435 return (usage());
436 }
437 if (Uflag) {
438 if (processor_bind(P_ALL, 0, PBIND_NONE, &old_cpu) != 0)
439 die(gettext("failed to unbind some LWPs"));
440 }
441 if (Qflag) {
442 (void) proc_walk(query_all_lwp, NULL, PR_WALK_LWP);
443 return (errors);
444 } else {
445 (void) proc_walk(query_all_proc, NULL, PR_WALK_PROC);
446 return (errors);
447 }
448 }
449
450 if (Qflag || Uflag) {
451 /*
452 * Go through listed processor IDs.
453 */
454 for (; argc > 0; argv++, argc--) {
455 errno = 0;
456 cpu = (id_t)strtol(*argv, &endstr, 10);
457 if (errno != 0 || (endstr != NULL && *endstr != '\0') ||
458 p_online(cpu, P_STATUS) == -1) {
459 warn(gettext("invalid processor ID\n"));
460 continue;
461 }
462 if (Qflag) {
463 (void) proc_walk(query_all_lwp,
464 &cpu, PR_WALK_LWP);
465 continue;
466 }
467 if (Uflag) {
468 if (processor_bind(P_CPUID, cpu,
469 PBIND_NONE, &old_cpu) != 0) {
|
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 2015 Ryan Zezeski
24 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
26 */
27
28 /*
29 * pbind - bind a process to a processor (non-exclusively)
30 */
31
32 #include <sys/types.h>
33 #include <sys/procset.h>
34 #include <sys/processor.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <procfs.h>
39 #include <fcntl.h>
40 #include <errno.h>
41 #include <dirent.h>
42 #include <locale.h>
43 #include <libproc.h>
44 #include <stdarg.h>
45
46 #if !defined(TEXT_DOMAIN) /* should be defined by cc -D */
47 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
48 #endif
49
50 #define ERR_OK 0 /* exit status for success */
51 #define ERR_FAIL 1 /* exit status for errors */
52 #define ERR_USAGE 2 /* exit status for usage errors */
53
54 static char *progname;
55 static char bflag;
56 static char eflag;
57 static char qflag;
58 static char Qflag;
59 static char uflag;
60 static char Uflag;
61 static int errors;
62
63 #define MAX_PROCFS_PATH 80
64
65 /*PRINTFLIKE1*/
66 static void
67 warn(char *format, ...)
68 {
69 int err = errno;
70 va_list alist;
71
72 (void) fprintf(stderr, "%s: ", progname);
73 va_start(alist, format);
74 (void) vfprintf(stderr, format, alist);
75 va_end(alist);
76 if (strchr(format, '\n') == NULL)
328 query_out(pid, -1, binding);
329 return (0);
330 }
331
332 static int
333 query_all_lwp(psinfo_t *psinfo, lwpsinfo_t *lwpsinfo, void *arg)
334 {
335 id_t pid = psinfo->pr_pid;
336 id_t lwpid = lwpsinfo->pr_lwpid;
337 processorid_t *cpuid = arg;
338 processorid_t binding = lwpsinfo->pr_bindpro;
339
340 if (psinfo->pr_nlwp == 1)
341 lwpid = -1; /* report process bindings if only 1 lwp */
342 if ((cpuid != NULL && *cpuid == binding) ||
343 (cpuid == NULL && binding != PBIND_NONE))
344 query_out(pid, lwpid, binding);
345 return (0);
346 }
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
381 static int
382 usage(void)
383 {
384 (void) fprintf(stderr,
385 gettext("usage: \n\t%1$s -b processor_id pid[/lwpids] ...\n"
386 "\t%1$s -e processor_id cmd [args...]\n"
387 "\t%1$s -U [processor_id] ...\n"
388 "\t%1$s -Q [processor_id] ...\n"
389 "\t%1$s -u pid[/lwpids] ...\n"
390 "\t%1$s [-q] [pid[/lwpids] ...]\n"),
391 progname);
392 return (ERR_USAGE);
393 }
394
395 int
396 main(int argc, char *argv[])
397 {
398 int c;
399 int ret;
400 id_t pid;
401 processorid_t cpu, old_cpu;
402 char *endstr;
403
404 progname = argv[0]; /* put actual command name in messages */
405
406 (void) setlocale(LC_ALL, ""); /* setup localization */
407 (void) textdomain(TEXT_DOMAIN);
408
409 while ((c = getopt(argc, argv, "b:e:qQuU")) != EOF) {
410 switch (c) {
411
412 case 'b':
413 bflag = 1;
414 cpu = parse_cpu(optarg);
415 break;
416
417 case 'e':
418 eflag = 1;
419 cpu = parse_cpu(optarg);
420 break;
421
422 case 'q':
423 qflag = 1;
424 cpu = PBIND_QUERY;
425 break;
426
427 case 'Q':
428 Qflag = 1;
429 cpu = PBIND_QUERY;
430 break;
431
432 case 'u':
433 uflag = 1;
434 cpu = PBIND_NONE;
435 break;
436
437 case 'U':
438 Uflag = 1;
439 break;
440
441 default:
442 return (usage());
443 }
444 }
445
446
447 /*
448 * Make sure that at most one of the options b, e, q, Q, u, or
449 * U was specified.
450 */
451 c = bflag + eflag + qflag + Qflag + uflag + Uflag;
452 if (c < 1) { /* nothing specified */
453 qflag = 1; /* default to query */
454 cpu = PBIND_QUERY;
455 } else if (c > 1) {
456 warn(gettext("options -b, -e, -q, -Q, -u and -U "
457 "are mutually exclusive\n"));
458 return (usage());
459 }
460
461 errors = 0;
462 argc -= optind;
463 argv += optind;
464
465 /*
466 * Handle query of all processes.
467 */
468 if (argc == 0) {
469 if (bflag || uflag) {
470 warn(gettext("must specify at least one pid\n"));
471 return (usage());
472 }
473 if (eflag) {
474 warn(gettext("must specify command\n"));
475 return (usage());
476 }
477 if (Uflag) {
478 if (processor_bind(P_ALL, 0, PBIND_NONE, &old_cpu) != 0)
479 die(gettext("failed to unbind some LWPs"));
480 }
481 if (Qflag) {
482 (void) proc_walk(query_all_lwp, NULL, PR_WALK_LWP);
483 return (errors);
484 } else {
485 (void) proc_walk(query_all_proc, NULL, PR_WALK_PROC);
486 return (errors);
487 }
488 }
489
490 if (eflag)
491 exec_cmd(cpu, argv[0], argv);
492
493 if (Qflag || Uflag) {
494 /*
495 * Go through listed processor IDs.
496 */
497 for (; argc > 0; argv++, argc--) {
498 errno = 0;
499 cpu = (id_t)strtol(*argv, &endstr, 10);
500 if (errno != 0 || (endstr != NULL && *endstr != '\0') ||
501 p_online(cpu, P_STATUS) == -1) {
502 warn(gettext("invalid processor ID\n"));
503 continue;
504 }
505 if (Qflag) {
506 (void) proc_walk(query_all_lwp,
507 &cpu, PR_WALK_LWP);
508 continue;
509 }
510 if (Uflag) {
511 if (processor_bind(P_CPUID, cpu,
512 PBIND_NONE, &old_cpu) != 0) {
|