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>


   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) {