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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <unistd.h> 27 #include <rctl.h> 28 #include <libproc.h> 29 #include <stdio.h> 30 #include <libintl.h> 31 #include <locale.h> 32 #include <string.h> 33 #include <signal.h> 34 #include <strings.h> 35 #include <ctype.h> 36 #include <project.h> 37 #include <sys/types.h> 38 #include <dirent.h> 39 #include <errno.h> 40 #include <stdlib.h> 41 #include <sys/varargs.h> 42 #include <priv.h> 43 #include <zone.h> 44 #include "utils.h" 45 46 /* Valid user actions */ 47 #define ACTION_DISABLE 0x01 48 #define ACTION_ENABLE 0x02 49 #define ACTION_SET 0x04 50 #define ACTION_REPLACE 0x08 51 #define ACTION_DELETE 0x10 52 53 #define PRCTL_VALUE_WIDTH 4 54 55 /* Maximum string length for deferred errors */ 56 #define GLOBAL_ERR_SZ 1024 57 58 /* allow important process values to be passed together easily */ 59 typedef struct pr_info_handle { 60 struct ps_prochandle *pr; 61 pid_t pid; 62 psinfo_t psinfo; 63 taskid_t taskid; 64 projid_t projid; 65 char *projname; 66 zoneid_t zoneid; 67 char *zonename; 68 69 } pr_info_handle_t; 70 71 /* Structures for list of resource controls */ 72 typedef struct prctl_value { 73 rctlblk_t *rblk; 74 struct prctl_value *next; 75 } prctl_value_t; 76 77 typedef struct prctl_list { 78 char *name; 79 rctl_qty_t *usage; 80 prctl_value_t *val_list; 81 struct prctl_list *next; 82 } prctl_list_t; 83 84 static volatile int interrupt; 85 86 static prctl_list_t *global_rctl_list_head = NULL; 87 static prctl_list_t *global_rctl_list_tail = NULL; 88 static char global_error[GLOBAL_ERR_SZ]; 89 90 /* global variables that contain commmand line option info */ 91 static int arg_operation = 0; 92 static int arg_force = 0; 93 94 95 /* String and type from -i */ 96 static rctl_entity_t arg_entity_type = RCENTITY_PROCESS; 97 static char *arg_entity_string = NULL; 98 99 /* -n argument */ 100 static char *arg_name = NULL; 101 102 static rctl_entity_t arg_name_entity = 0; 103 104 /* -t argument value */ 105 static int arg_priv = 0; 106 107 /* -v argument string */ 108 static char *arg_valuestring = NULL; 109 110 /* global flags of rctl name passed to -n */ 111 static int arg_global_flags = 0; 112 static rctl_qty_t arg_global_max; 113 114 /* appropriate scaling variables determined by rctl unit type */ 115 scale_t *arg_scale; 116 static char *arg_unit = NULL; 117 118 /* -v argument string converted to uint64_t */ 119 static uint64_t arg_value = 0; 120 121 /* if -v argument is scaled value, points to "K", "M", "G", ... */ 122 static char *arg_modifier = NULL; 123 124 /* -e/-d argument string */ 125 static char *arg_action_string = NULL; 126 127 /* Set to RCTL_LOCAL_SIGNAL|DENY based on arg_action_string */ 128 static int arg_action = 0; 129 130 /* if -e/-d arg is signal=XXX, set to signal number of XXX */ 131 static int arg_signal = 0; 132 133 /* -p arg if -p is specified */ 134 static int arg_pid = -1; 135 static char *arg_pid_string = NULL; 136 137 /* Set to 1 if -P is specified */ 138 static int arg_parseable_mode = 0; 139 140 /* interupt handler */ 141 static void intr(int); 142 143 static int get_rctls(struct ps_prochandle *); 144 static int store_rctls(const char *rctlname, void *walk_data); 145 static prctl_value_t *store_value_entry(rctlblk_t *rblk, prctl_list_t *list); 146 static prctl_list_t *store_list_entry(const char *name); 147 static void free_lists(); 148 149 static int change_action(rctlblk_t *blk); 150 151 static int prctl_setrctl(struct ps_prochandle *Pr, const char *name, 152 rctlblk_t *, rctlblk_t *, uint_t); 153 154 static int match_rctl(struct ps_prochandle *Pr, rctlblk_t **rctl, char *name, 155 char *valuestringin, int valuein, rctl_priv_t privin, 156 int pidin); 157 static int match_rctl_blk(rctlblk_t *rctl, char *valuestringin, 158 uint64_t valuein, 159 rctl_priv_t privin, int pidin); 160 static pid_t regrab_process(pid_t pid, pr_info_handle_t *p, int, int *gret); 161 static pid_t grab_process_by_id(char *idname, rctl_entity_t type, 162 pr_info_handle_t *p, int, int *gret); 163 static int grab_process(pr_info_handle_t *p, int *gret); 164 static void release_process(struct ps_prochandle *Pr); 165 static void preserve_error(char *format, ...); 166 167 static void print_rctls(pr_info_handle_t *p); 168 static void print_priv(rctl_priv_t local_priv, char *format); 169 static void print_local_action(int action, int *signalp, char *format); 170 171 static const char USAGE[] = "" 172 "usage:\n" 173 " Report resource control values and actions:\n" 174 " prctl [-P] [-t [basic | privileged | system]\n" 175 " [-n name] [-i process | task | project | zone] id ...\n" 176 " -P space delimited output\n" 177 " -t privilege level of rctl values to get\n" 178 " -n name of resource control values to get\n" 179 " -i idtype of operand list\n" 180 " Manipulate resource control values:\n" 181 " prctl [-t [basic | privileged | system]\n" 182 " -n name [-srx] [-v value] [-p pid ] [-e | -d action]\n" 183 " [-i process | task | project | zone] id ...\n" 184 " -t privilege level of rctl value to set/replace/delete/modify\n" 185 " -n name of resource control to set/replace/delete/modify\n" 186 " -s set new resource control value\n" 187 " -r replace first rctl value of matching privilege\n" 188 " -x delete first rctl value of matching privilege, value, and \n" 189 " recipient pid\n" 190 " -v value of rctl to set/replace/delete/modify\n" 191 " -p recipient pid of rctl to set/replace/delete/modify\n" 192 " -e enable action of first rctl value of matching privilege,\n" 193 " value, and recipient pid\n" 194 " -d disable action of first rctl value of matching privilege,\n" 195 " value, and recipient pid\n" 196 " -i idtype of operand list\n"; 197 198 199 static void 200 usage() 201 { 202 (void) fprintf(stderr, gettext(USAGE)); 203 exit(2); 204 } 205 206 int 207 main(int argc, char **argv) 208 { 209 int flags; 210 int opt, errflg = 0; 211 rctlblk_t *rctlblkA = NULL; 212 rctlblk_t *rctlblkB = NULL; 213 rctlblk_t *tmp = NULL; 214 pid_t pid; 215 char *target_id; 216 int search_type; 217 int signal; 218 int localaction; 219 int printed = 0; 220 int gret; 221 char *end; 222 223 (void) setlocale(LC_ALL, ""); 224 (void) textdomain(TEXT_DOMAIN); 225 (void) setpname(argv[0]); 226 227 while ((opt = getopt(argc, argv, "sPp:Fd:e:i:n:rt:v:x")) != EOF) { 228 229 switch (opt) { 230 case 'F': /* force grabbing (no O_EXCL) */ 231 arg_force = PGRAB_FORCE; 232 break; 233 case 'i': /* id type for arguments */ 234 arg_entity_string = optarg; 235 if (strcmp(optarg, "process") == 0 || 236 strcmp(optarg, "pid") == 0) 237 arg_entity_type = RCENTITY_PROCESS; 238 else if (strcmp(optarg, "project") == 0 || 239 strcmp(optarg, "projid") == 0) 240 arg_entity_type = RCENTITY_PROJECT; 241 else if (strcmp(optarg, "task") == 0 || 242 strcmp(optarg, "taskid") == 0) 243 arg_entity_type = RCENTITY_TASK; 244 else if (strcmp(optarg, "zone") == 0 || 245 strcmp(optarg, "zoneid") == 0) 246 arg_entity_type = RCENTITY_ZONE; 247 else { 248 warn(gettext("unknown idtype %s"), optarg); 249 errflg = 1; 250 } 251 break; 252 case 'd': 253 arg_action_string = optarg; 254 arg_operation |= ACTION_DISABLE; 255 break; 256 case 'e': 257 arg_action_string = optarg; 258 arg_operation |= ACTION_ENABLE; 259 break; 260 case 'n': /* name of rctl */ 261 arg_name = optarg; 262 if (strncmp(optarg, "process.", 263 strlen("process.")) == 0) 264 arg_name_entity = RCENTITY_PROCESS; 265 else if (strncmp(optarg, "project.", 266 strlen("project.")) == 0) 267 arg_name_entity = RCENTITY_PROJECT; 268 else if (strncmp(optarg, "task.", 269 strlen("task.")) == 0) 270 arg_name_entity = RCENTITY_TASK; 271 else if (strncmp(optarg, "zone.", 272 strlen("zone.")) == 0) 273 arg_name_entity = RCENTITY_ZONE; 274 break; 275 case 'r': 276 arg_operation |= ACTION_REPLACE; 277 break; 278 case 't': /* rctl type */ 279 if (strcmp(optarg, "basic") == 0) 280 arg_priv = RCPRIV_BASIC; 281 else if (strcmp(optarg, "privileged") == 0) 282 arg_priv = RCPRIV_PRIVILEGED; 283 else if (strcmp(optarg, "priv") == 0) 284 arg_priv = RCPRIV_PRIVILEGED; 285 else if (strcmp(optarg, "system") == 0) 286 arg_priv = RCPRIV_SYSTEM; 287 else { 288 warn(gettext("unknown privilege %s"), optarg); 289 errflg = 1; 290 } 291 break; 292 case 'v': /* value */ 293 arg_valuestring = optarg; 294 break; 295 case 's': 296 arg_operation |= ACTION_SET; 297 break; 298 case 'x': /* delete */ 299 arg_operation |= ACTION_DELETE; 300 break; 301 case 'p': 302 errno = 0; 303 /* Stick with -1 if arg is "-" */ 304 if (strcmp("-", optarg) == 0) 305 break; 306 307 arg_pid_string = optarg; 308 arg_pid = strtoul(optarg, &end, 10); 309 if (errno || *end != '\0' || end == optarg) { 310 warn(gettext("invalid pid %s"), optarg); 311 errflg = 1; 312 break; 313 } 314 break; 315 case 'P': 316 arg_parseable_mode = 1; 317 break; 318 default: 319 warn(gettext("unknown option")); 320 errflg = 1; 321 break; 322 } 323 } 324 argc -= optind; 325 argv += optind; 326 327 if (argc < 1) { 328 warn(gettext("no arguments specified")); 329 errflg = 1; 330 goto done_parse; 331 } 332 /* if -v is specified without -r, -x, -d, or -e, -s is implied */ 333 if (arg_valuestring && 334 (!(arg_operation & (ACTION_REPLACE | ACTION_DELETE | 335 ACTION_DISABLE | ACTION_ENABLE)))) { 336 arg_operation |= ACTION_SET; 337 } 338 /* operations require -n */ 339 if (arg_operation && (arg_name == NULL)) { 340 warn(gettext("-n is required with -s, -r, -x, -e, or -d")); 341 errflg = 1; 342 goto done_parse; 343 } 344 /* enable and disable are exclusive */ 345 if ((arg_operation & ACTION_ENABLE) && 346 (arg_operation & ACTION_DISABLE)) { 347 warn(gettext("options -d and -e are exclusive")); 348 errflg = 1; 349 goto done_parse; 350 } 351 /* -s, -r, and -x are exclusive */ 352 flags = arg_operation & 353 (ACTION_REPLACE | ACTION_SET | ACTION_DELETE); 354 if (flags & (flags - 1)) { 355 warn(gettext("options -s, -r, and -x are exclusive")); 356 errflg = 1; 357 goto done_parse; 358 } 359 /* -e or -d makes no sense with -x */ 360 if ((arg_operation & ACTION_DELETE) & 361 (arg_operation & (ACTION_ENABLE | ACTION_DISABLE))) { 362 warn(gettext("options -e or -d not allowed with -x")); 363 errflg = 1; 364 goto done_parse; 365 } 366 /* if -r is specified -v must be as well */ 367 if ((arg_operation & ACTION_REPLACE) && (!arg_valuestring)) { 368 warn(gettext("option -r requires use of option -v")); 369 errflg = 1; 370 goto done_parse; 371 } 372 /* if -s is specified -v must be as well */ 373 if ((arg_operation & ACTION_SET) && (!arg_valuestring)) { 374 warn(gettext("option -s requires use of option -v")); 375 errflg = 1; 376 goto done_parse; 377 } 378 /* Specifying a recipient pid on a non-basic rctl makes no sense */ 379 if (arg_pid != -1 && arg_priv > RCPRIV_BASIC) { 380 warn(gettext("option -p not allowed on non-basic rctl")); 381 errflg = 1; 382 goto done_parse; 383 } 384 /* Specifying a recipient pid on a privileged rctl makes no sense */ 385 if (arg_pid != -1 && 386 arg_priv == RCPRIV_PRIVILEGED) { 387 warn(gettext("option -p not allowed with privileged rctl")); 388 errflg = 1; 389 goto done_parse; 390 } 391 if (arg_operation) { 392 393 /* do additional checks if there is an operation */ 394 395 if (arg_parseable_mode == 1) { 396 warn(gettext("-P not valid when manipulating " 397 "resource control values")); 398 errflg = 1; 399 goto done_parse; 400 } 401 /* get rctl global flags to determine if actions are valid */ 402 if ((rctlblkA = calloc(1, rctlblk_size())) == NULL) { 403 warn(gettext("malloc failed: %s"), 404 strerror(errno)); 405 errflg = 1; 406 goto done_parse; 407 } 408 if ((rctlblkB = calloc(1, rctlblk_size())) == NULL) { 409 warn(gettext("malloc failed: %s"), 410 strerror(errno)); 411 errflg = 1; 412 goto done_parse; 413 } 414 /* get system rctl to get global flags and max value */ 415 if (getrctl(arg_name, NULL, rctlblkA, RCTL_FIRST)) { 416 warn(gettext("failed to get resource control " 417 "for %s: %s"), arg_name, strerror(errno)); 418 errflg = 1; 419 goto done_parse; 420 } 421 while (getrctl(arg_name, rctlblkA, rctlblkB, RCTL_NEXT) == 0) { 422 423 /* allow user interrupt */ 424 if (interrupt) { 425 errflg = 1; 426 goto done_parse; 427 } 428 tmp = rctlblkB; 429 rctlblkB = rctlblkA; 430 rctlblkA = tmp; 431 432 if (rctlblk_get_privilege(rctlblkA) == 433 RCPRIV_SYSTEM) { 434 break; 435 } 436 } 437 if (rctlblk_get_privilege(rctlblkA) != RCPRIV_SYSTEM) { 438 warn(gettext("failed to get system resource control " 439 "for %s: %s"), arg_name, strerror(errno)); 440 errflg = 1; 441 goto done_parse; 442 } 443 /* figure out the correct scale and unit for this rctl */ 444 arg_global_flags = rctlblk_get_global_flags(rctlblkA); 445 arg_global_max = rctlblk_get_value(rctlblkA); 446 447 if (arg_global_flags & RCTL_GLOBAL_BYTES) { 448 arg_unit = SCALED_UNIT_BYTES; 449 arg_scale = scale_binary; 450 451 } else if (arg_global_flags & RCTL_GLOBAL_SECONDS) { 452 arg_unit = SCALED_UNIT_SECONDS; 453 arg_scale = scale_metric; 454 455 } else { 456 arg_unit = SCALED_UNIT_NONE; 457 arg_scale = scale_metric; 458 } 459 /* parse -v value string */ 460 if (arg_valuestring) { 461 if (scaledtouint64(arg_valuestring, 462 &arg_value, NULL, &arg_modifier, NULL, 463 arg_scale, arg_unit, 464 SCALED_ALL_FLAGS)) { 465 466 warn(gettext("invalid -v value %s"), 467 arg_valuestring); 468 errflg = 1; 469 goto done_parse; 470 } 471 if (arg_value > arg_global_max) { 472 warn(gettext("-v value %s exceeds system " 473 "limit for resource control: %s"), 474 arg_valuestring, arg_name); 475 errflg = 1; 476 goto done_parse; 477 } 478 } 479 /* parse action */ 480 if (arg_action_string) { 481 482 char *sigchr; 483 char *iter; 484 485 if ((strcmp(arg_action_string, "signal") == 0) || 486 (strcmp(arg_action_string, "sig") == 0)) { 487 488 if (arg_operation & ACTION_ENABLE) { 489 warn(gettext( 490 "signal name or number must be " 491 "specified with -e")); 492 errflg = 1; 493 goto done_parse; 494 } 495 arg_action = RCTL_LOCAL_SIGNAL; 496 arg_signal = -1; 497 498 } else if ((strncmp(arg_action_string, 499 "signal=", strlen("signal=")) == 0) || 500 (strncmp(arg_action_string, 501 "sig=", strlen("sig=")) == 0)) { 502 503 arg_action = RCTL_LOCAL_SIGNAL; 504 sigchr = strrchr(arg_action_string, '='); 505 sigchr++; 506 507 iter = sigchr; 508 while (*iter) { 509 *iter = toupper(*iter); 510 iter++; 511 } 512 if (strncmp("SIG", sigchr, 3) == 0) 513 sigchr += 3; 514 515 516 if (str2sig(sigchr, &arg_signal) != 0) { 517 warn(gettext("signal invalid")); 518 errflg = 1; 519 goto done_parse; 520 } 521 } else if (strcmp(arg_action_string, "deny") == 0) { 522 523 arg_action = RCTL_LOCAL_DENY; 524 525 } else if (strcmp(arg_action_string, "all") == 0) { 526 527 if (arg_operation & ACTION_ENABLE) { 528 warn(gettext( 529 "cannot use action 'all' with -e")); 530 errflg = 1; 531 goto done_parse; 532 } 533 arg_action = RCTL_LOCAL_DENY | 534 RCTL_LOCAL_SIGNAL; 535 arg_signal = -1; 536 goto done_parse; 537 } else { 538 warn(gettext("action invalid")); 539 errflg = 1; 540 goto done_parse; 541 } 542 } 543 /* cannot manipulate system rctls */ 544 if (arg_priv == RCPRIV_SYSTEM) { 545 546 warn(gettext("cannot modify system values")); 547 errflg = 1; 548 goto done_parse; 549 } 550 /* validate that the privilege is allowed */ 551 if ((arg_priv == RCPRIV_BASIC) && 552 (arg_global_flags & RCTL_GLOBAL_NOBASIC)) { 553 554 warn(gettext("basic values not allowed on rctl %s"), 555 arg_name); 556 errflg = 1; 557 goto done_parse; 558 } 559 /* validate that actions are appropriate for given rctl */ 560 if ((arg_operation & ACTION_ENABLE) && 561 (arg_action & RCTL_LOCAL_DENY) && 562 (arg_global_flags & RCTL_GLOBAL_DENY_NEVER)) { 563 564 warn(gettext("unable to enable deny on rctl with " 565 "global flag 'no-deny'")); 566 errflg = 1; 567 goto done_parse; 568 } 569 if ((arg_operation & ACTION_DISABLE) && 570 (arg_action & RCTL_LOCAL_DENY) && 571 (arg_global_flags & RCTL_GLOBAL_DENY_ALWAYS)) { 572 573 warn(gettext("unable to disable deny on rctl with " 574 "global flag 'deny'")); 575 errflg = 1; 576 goto done_parse; 577 } 578 if ((arg_operation & ACTION_ENABLE) && 579 (arg_action & RCTL_LOCAL_SIGNAL) && 580 (arg_global_flags & RCTL_GLOBAL_SIGNAL_NEVER)) { 581 582 warn(gettext("unable to enable signal on rctl with " 583 "global flag 'no-signal'")); 584 errflg = 1; 585 goto done_parse; 586 } 587 /* now set defaults for options not supplied */ 588 589 /* 590 * default privilege to basic if this is a seting an rctl 591 * operation 592 */ 593 if (arg_operation & ACTION_SET) { 594 if (arg_priv == 0) { 595 arg_priv = RCPRIV_BASIC; 596 } 597 } 598 /* 599 * -p is required when set a basic task, 600 * project or zone rctl 601 */ 602 if ((arg_pid == -1) && 603 (arg_priv == RCPRIV_BASIC) && 604 (arg_entity_type != RCENTITY_PROCESS) && 605 (arg_operation & ACTION_SET) && 606 (arg_name) && 607 (arg_name_entity == RCENTITY_TASK || 608 arg_name_entity == RCENTITY_PROJECT || 609 arg_name_entity == RCENTITY_ZONE)) { 610 611 warn(gettext("-p pid required when setting or " 612 "replacing task or project rctl")); 613 errflg = 1; 614 goto done_parse; 615 } 616 } else { 617 618 /* validate for list mode */ 619 /* -p is not valid in list mode */ 620 if (arg_pid != -1) { 621 warn(gettext("-p pid requires -s, -r, -x, -e, or -d")); 622 errflg = 1; 623 goto done_parse; 624 } 625 } 626 /* getting/setting process rctl on task or project is error */ 627 if ((arg_name && (arg_name_entity == RCENTITY_PROCESS)) && 628 ((arg_entity_type == RCENTITY_TASK) || 629 (arg_entity_type == RCENTITY_PROJECT))) { 630 631 warn(gettext("cannot get/set process rctl on task " 632 "or project")); 633 errflg = 1; 634 goto done_parse; 635 } 636 /* getting/setting task rctl on project is error */ 637 if ((arg_name && (arg_name_entity == RCENTITY_TASK)) && 638 (arg_entity_type == RCENTITY_PROJECT)) { 639 640 warn(gettext("cannot get/set task rctl on project")); 641 errflg = 1; 642 goto done_parse; 643 } 644 645 done_parse: 646 647 /* free any rctlblk's that we may have allocated */ 648 if (rctlblkA) { 649 free(rctlblkA); 650 rctlblkA = NULL; 651 } 652 if (rctlblkB) { 653 free(rctlblkB); 654 rctlblkB = NULL; 655 } 656 if (errflg) 657 usage(); 658 659 /* catch signals from terminal */ 660 if (sigset(SIGHUP, SIG_IGN) == SIG_DFL) 661 (void) sigset(SIGHUP, intr); 662 if (sigset(SIGINT, SIG_IGN) == SIG_DFL) 663 (void) sigset(SIGINT, intr); 664 if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL) 665 (void) sigset(SIGQUIT, intr); 666 (void) sigset(SIGTERM, intr); 667 668 while (--argc >= 0 && !interrupt) { 669 pr_info_handle_t p; 670 char *arg = *argv++; 671 int intarg; 672 char *end; 673 errflg = 0; 674 675 gret = 0; 676 677 /* Store int version of arg */ 678 errno = 0; 679 intarg = strtoul(arg, &end, 10); 680 if (errno || *end != '\0' || end == arg) { 681 intarg = -1; 682 } 683 684 /* 685 * -p defaults to arg if basic and collective rctl 686 * and -i process is specified 687 */ 688 if ((arg_pid == -1) && 689 (arg_priv == RCPRIV_BASIC) && 690 (arg_entity_type == RCENTITY_PROCESS) && 691 (arg_name) && 692 (arg_name_entity == RCENTITY_TASK || 693 arg_name_entity == RCENTITY_PROJECT)) { 694 arg_pid_string = arg; 695 errno = 0; 696 arg_pid = intarg; 697 } 698 /* Specifying a recipient pid and -i pid is redundent */ 699 if (arg_pid != -1 && arg_entity_type == RCENTITY_PROCESS && 700 arg_pid != intarg) { 701 warn(gettext("option -p pid must match -i process")); 702 errflg = 1; 703 continue; 704 } 705 /* use recipient pid if we have one */ 706 if (arg_pid_string != NULL) { 707 target_id = arg_pid_string; 708 search_type = RCENTITY_PROCESS; 709 } else { 710 target_id = arg; 711 search_type = arg_entity_type; 712 } 713 (void) fflush(stdout); /* process-at-a-time */ 714 715 if (arg_operation != 0) { 716 717 if ((pid = grab_process_by_id(target_id, 718 search_type, &p, arg_priv, &gret)) < 0) { 719 /* 720 * Mark that an error occurred so that the 721 * return value can be set, but continue 722 * on with other processes 723 */ 724 errflg = 1; 725 continue; 726 } 727 728 /* 729 * At this point, the victim process is held. 730 * Do not call any Pgrab-unsafe functions until 731 * the process is released via release_process(). 732 */ 733 734 errflg = get_rctls(p.pr); 735 736 if (arg_operation & ACTION_DELETE) { 737 738 /* match by privilege, value, and pid */ 739 if (match_rctl(p.pr, &rctlblkA, arg_name, 740 arg_valuestring, arg_value, arg_priv, 741 arg_pid) != 0 || rctlblkA == NULL) { 742 743 if (interrupt) 744 goto out; 745 746 preserve_error(gettext("no matching " 747 "resource control found for " 748 "deletion")); 749 errflg = 1; 750 goto out; 751 } 752 /* 753 * grab correct process. This is neccessary 754 * if the recipient pid does not match the 755 * one we grabbed 756 */ 757 pid = regrab_process( 758 rctlblk_get_recipient_pid(rctlblkA), 759 &p, arg_priv, &gret); 760 761 if (pid < 0) { 762 errflg = 1; 763 goto out; 764 } 765 if (prctl_setrctl(p.pr, arg_name, NULL, 766 rctlblkA, RCTL_DELETE) != 0) { 767 errflg = 1; 768 goto out; 769 } 770 } else if (arg_operation & ACTION_SET) { 771 772 /* match by privilege, value, and pid */ 773 774 if (match_rctl(p.pr, &rctlblkA, arg_name, 775 arg_valuestring, arg_value, arg_priv, 776 arg_pid) == 0) { 777 778 if (interrupt) 779 goto out; 780 781 preserve_error(gettext("resource " 782 "control already exists")); 783 errflg = 1; 784 goto out; 785 } 786 rctlblkB = calloc(1, rctlblk_size()); 787 if (rctlblkB == NULL) { 788 preserve_error(gettext( 789 "malloc failed"), strerror(errno)); 790 errflg = 1; 791 goto out; 792 } 793 rctlblk_set_value(rctlblkB, arg_value); 794 rctlblk_set_privilege(rctlblkB, arg_priv); 795 if (change_action(rctlblkB)) { 796 errflg = 1; 797 goto out; 798 } 799 if (prctl_setrctl(p.pr, arg_name, NULL, 800 rctlblkB, RCTL_INSERT) != 0) { 801 errflg = 1; 802 goto out; 803 } 804 } else if (arg_operation & ACTION_REPLACE) { 805 /* 806 * match rctl for deletion by privilege and 807 * pid only 808 */ 809 if (match_rctl(p.pr, &rctlblkA, arg_name, 810 NULL, 0, arg_priv, 811 arg_pid) != 0 || rctlblkA == NULL) { 812 813 if (interrupt) 814 goto out; 815 816 preserve_error(gettext("no matching " 817 "resource control to replace")); 818 errflg = 1; 819 goto out; 820 } 821 /* 822 * grab correct process. This is neccessary 823 * if the recipient pid does not match the 824 * one we grabbed 825 */ 826 pid = regrab_process( 827 rctlblk_get_recipient_pid(rctlblkA), 828 &p, arg_priv, &gret); 829 if (pid < 0) { 830 errflg = 1; 831 goto out; 832 } 833 pid = rctlblk_get_recipient_pid(rctlblkA); 834 835 /* 836 * match by privilege, value and pid to 837 * check if new rctl already exists 838 */ 839 if (match_rctl(p.pr, &rctlblkB, arg_name, 840 arg_valuestring, arg_value, arg_priv, 841 pid) < 0) { 842 843 if (interrupt) 844 goto out; 845 846 preserve_error(gettext( 847 "Internal Error")); 848 errflg = 1; 849 goto out; 850 } 851 /* 852 * If rctl already exists, and it does not 853 * match the one that we will delete, than 854 * the replace will fail. 855 */ 856 if (rctlblkB != NULL && 857 arg_value != rctlblk_get_value(rctlblkA)) { 858 859 preserve_error(gettext("replacement " 860 "resource control already " 861 "exists")); 862 863 errflg = 1; 864 goto out; 865 } 866 /* create new rctl */ 867 rctlblkB = calloc(1, rctlblk_size()); 868 if (rctlblkB == NULL) { 869 preserve_error(gettext( 870 "malloc failed"), strerror(errno)); 871 errflg = 1; 872 goto out; 873 } 874 localaction = 875 rctlblk_get_local_action(rctlblkA, &signal); 876 rctlblk_set_local_action(rctlblkB, localaction, 877 signal); 878 rctlblk_set_value(rctlblkB, arg_value); 879 rctlblk_set_privilege(rctlblkB, 880 rctlblk_get_privilege(rctlblkA)); 881 if (change_action(rctlblkB)) { 882 errflg = 1; 883 goto out; 884 } 885 /* do replacement */ 886 if (prctl_setrctl(p.pr, arg_name, rctlblkA, 887 rctlblkB, RCTL_REPLACE) != 0) { 888 errflg = 1; 889 goto out; 890 } 891 } else if (arg_operation & 892 (ACTION_ENABLE | ACTION_DISABLE)) { 893 894 rctlblkB = calloc(1, rctlblk_size()); 895 if (rctlblkB == NULL) { 896 preserve_error(gettext( 897 "malloc failed"), strerror(errno)); 898 errflg = 1; 899 goto out; 900 } 901 /* match by privilege, value, and pid */ 902 if (match_rctl(p.pr, &rctlblkA, arg_name, 903 arg_valuestring, arg_value, arg_priv, 904 arg_pid) != 0) { 905 906 if (interrupt) 907 goto out; 908 909 /* if no match, just set new rctl */ 910 if (arg_priv == 0) 911 arg_priv = RCPRIV_BASIC; 912 913 if ((arg_priv == RCPRIV_BASIC) && 914 (arg_entity_type != 915 RCENTITY_PROCESS) && 916 (arg_pid_string == NULL)) { 917 preserve_error(gettext( 918 "-p required when setting " 919 "basic rctls")); 920 errflg = 1; 921 goto out; 922 } 923 rctlblk_set_value(rctlblkB, 924 arg_value); 925 rctlblk_set_privilege( 926 rctlblkB, arg_priv); 927 if (change_action(rctlblkB)) { 928 errflg = 1; 929 goto out; 930 } 931 if (prctl_setrctl(p.pr, 932 arg_name, NULL, rctlblkB, 933 RCTL_INSERT) != 0) { 934 errflg = 1; 935 goto out; 936 } 937 goto out; 938 } 939 if (rctlblkA == NULL) { 940 preserve_error(gettext("no matching " 941 "resource control found")); 942 errflg = 1; 943 goto out; 944 } 945 /* 946 * grab correct process. This is neccessary 947 * if the recipient pid does not match the 948 * one we grabbed 949 */ 950 pid = regrab_process( 951 rctlblk_get_recipient_pid(rctlblkA), 952 &p, arg_priv, &gret); 953 if (pid < 0) { 954 errflg = 1; 955 goto out; 956 } 957 localaction = 958 rctlblk_get_local_action(rctlblkA, 959 &signal); 960 rctlblk_set_local_action(rctlblkB, localaction, 961 signal); 962 rctlblk_set_privilege(rctlblkB, 963 rctlblk_get_privilege(rctlblkA)); 964 rctlblk_set_value(rctlblkB, 965 rctlblk_get_value(rctlblkA)); 966 967 if (change_action(rctlblkB)) { 968 errflg = 1; 969 goto out; 970 } 971 if (prctl_setrctl(p.pr, arg_name, rctlblkA, 972 rctlblkB, RCTL_REPLACE) != 0) { 973 errflg = 1; 974 goto out; 975 } 976 } 977 out: 978 release_process(p.pr); 979 if (rctlblkA) 980 free(rctlblkA); 981 if (rctlblkB) 982 free(rctlblkB); 983 984 /* Print any errors that occurred */ 985 if (errflg && *global_error != '\0') { 986 proc_unctrl_psinfo(&(p.psinfo)); 987 (void) fprintf(stderr, "%d:\t%.70s\n", 988 (int)p.pid, p.psinfo.pr_psargs); 989 warn("%s\n", global_error); 990 break; 991 } 992 } else { 993 994 struct project projent; 995 char buf[PROJECT_BUFSZ]; 996 char zonename[ZONENAME_MAX]; 997 998 /* 999 * Hack to allow the user to specify a system 1000 * process. 1001 */ 1002 gret = G_SYS; 1003 pid = grab_process_by_id( 1004 target_id, search_type, &p, RCPRIV_BASIC, &gret); 1005 1006 /* 1007 * Print system process if user chose specifically 1008 * to inspect a system process. 1009 */ 1010 if (arg_entity_type == RCENTITY_PROCESS && 1011 pid < 0 && 1012 gret == G_SYS) { 1013 /* 1014 * Add blank lines between output for 1015 * operands. 1016 */ 1017 if (printed) { 1018 (void) fprintf(stdout, "\n"); 1019 } 1020 1021 proc_unctrl_psinfo(&(p.psinfo)); 1022 (void) printf( 1023 "process: %d: %s [ system process ]\n", 1024 (int)p.pid, p.psinfo.pr_psargs); 1025 1026 printed = 1; 1027 continue; 1028 1029 } else if (pid < 0) { 1030 1031 /* 1032 * Mark that an error occurred so that the 1033 * return value can be set, but continue 1034 * on with other processes 1035 */ 1036 errflg = 1; 1037 continue; 1038 } 1039 1040 errflg = get_rctls(p.pr); 1041 1042 release_process(p.pr); 1043 1044 /* handle user interrupt of getting rctls */ 1045 if (interrupt) 1046 break; 1047 1048 /* add blank lines between output for operands */ 1049 if (printed) { 1050 (void) fprintf(stdout, "\n"); 1051 } 1052 /* First print any errors */ 1053 if (errflg) { 1054 warn("%s\n", global_error); 1055 free_lists(); 1056 break; 1057 } 1058 if (getprojbyid(p.projid, &projent, buf, 1059 sizeof (buf))) { 1060 p.projname = projent.pj_name; 1061 } else { 1062 p.projname = ""; 1063 } 1064 if (getzonenamebyid(p.zoneid, zonename, 1065 sizeof (zonename)) > 0) { 1066 p.zonename = zonename; 1067 } else { 1068 p.zonename = ""; 1069 } 1070 print_rctls(&p); 1071 printed = 1; 1072 /* Free the resource control lists */ 1073 free_lists(); 1074 } 1075 } 1076 if (interrupt) 1077 errflg = 1; 1078 1079 /* 1080 * return error if one occurred 1081 */ 1082 return (errflg); 1083 } 1084 1085 1086 static void 1087 intr(int sig) 1088 { 1089 interrupt = sig; 1090 } 1091 1092 /* 1093 * get_rctls(struct ps_prochandle *, const char *) 1094 * 1095 * If controlname is given, store only controls for that named 1096 * resource. If controlname is NULL, store all controls for all 1097 * resources. 1098 * 1099 * This function is Pgrab-safe. 1100 */ 1101 static int 1102 get_rctls(struct ps_prochandle *Pr) 1103 { 1104 int ret = 0; 1105 1106 if (arg_name == NULL) { 1107 if (rctl_walk(store_rctls, Pr) != 0) 1108 ret = 1; 1109 } else { 1110 ret = store_rctls(arg_name, Pr); 1111 } 1112 return (ret); 1113 } 1114 1115 /* 1116 * store_rctls(const char *, void *) 1117 * 1118 * Store resource controls for the given name in a linked list. 1119 * Honor the user's options, and store only the ones they are 1120 * interested in. If priv is not 0, show only controls that match 1121 * the given privilege. 1122 * 1123 * This function is Pgrab-safe 1124 */ 1125 static int 1126 store_rctls(const char *rctlname, void *walk_data) 1127 { 1128 struct ps_prochandle *Pr = walk_data; 1129 rctlblk_t *rblk2, *rblk_tmp, *rblk1 = NULL; 1130 prctl_list_t *list = NULL; 1131 rctl_priv_t rblk_priv; 1132 rctl_entity_t rblk_entity; 1133 1134 if (((rblk1 = calloc(1, rctlblk_size())) == NULL) || 1135 ((rblk2 = calloc(1, rctlblk_size())) == NULL)) { 1136 if (rblk1 != NULL) 1137 free(rblk1); 1138 preserve_error(gettext("malloc failed: %s"), 1139 strerror(errno)); 1140 return (1); 1141 } 1142 if (pr_getrctl(Pr, rctlname, NULL, rblk1, RCTL_FIRST)) { 1143 preserve_error(gettext("failed to get resource control " 1144 "for %s: %s"), rctlname, strerror(errno)); 1145 free(rblk1); 1146 free(rblk2); 1147 return (1); 1148 } 1149 /* Store control if it matches privilege and enity type criteria */ 1150 rblk_priv = rctlblk_get_privilege(rblk1); 1151 rblk_entity = 0; 1152 if (strncmp(rctlname, "process.", 1153 strlen("process.")) == 0) 1154 rblk_entity = RCENTITY_PROCESS; 1155 else if (strncmp(rctlname, "project.", 1156 strlen("project.")) == 0) 1157 rblk_entity = RCENTITY_PROJECT; 1158 else if (strncmp(rctlname, "task.", 1159 strlen("task.")) == 0) 1160 rblk_entity = RCENTITY_TASK; 1161 else if (strncmp(rctlname, "zone.", 1162 strlen("zone.")) == 0) 1163 rblk_entity = RCENTITY_ZONE; 1164 1165 if (((arg_priv == 0) || (rblk_priv == arg_priv)) && 1166 ((arg_name == NULL) || 1167 strncmp(rctlname, arg_name, strlen(arg_name)) == 0) && 1168 (arg_entity_string == NULL || rblk_entity >= arg_entity_type)) { 1169 1170 /* Once we know we have some controls, store the name */ 1171 if ((list = store_list_entry(rctlname)) == NULL) { 1172 free(rblk1); 1173 free(rblk2); 1174 return (1); 1175 } 1176 if (store_value_entry(rblk1, list) == NULL) { 1177 free(rblk1); 1178 free(rblk2); 1179 return (1); 1180 } 1181 } 1182 while (pr_getrctl(Pr, rctlname, rblk1, rblk2, RCTL_NEXT) == 0) { 1183 1184 /* 1185 * in case this is stuck for some reason, allow manual 1186 * interrupt 1187 */ 1188 if (interrupt) { 1189 free(rblk1); 1190 free(rblk2); 1191 return (1); 1192 } 1193 rblk_priv = rctlblk_get_privilege(rblk2); 1194 /* 1195 * Store control if it matches privilege and entity type 1196 * criteria 1197 */ 1198 if (((arg_priv == 0) || (rblk_priv == arg_priv)) && 1199 ((arg_name == NULL) || 1200 strncmp(rctlname, arg_name, strlen(arg_name)) == 0) && 1201 (arg_entity_string == NULL || 1202 rblk_entity == arg_entity_type)) { 1203 1204 /* May not have created the list yet. */ 1205 if (list == NULL) { 1206 if ((list = store_list_entry(rctlname)) 1207 == NULL) { 1208 free(rblk1); 1209 free(rblk2); 1210 return (1); 1211 } 1212 } 1213 if (store_value_entry(rblk2, list) == NULL) { 1214 free(rblk1); 1215 free(rblk2); 1216 return (1); 1217 } 1218 } 1219 rblk_tmp = rblk1; 1220 rblk1 = rblk2; 1221 rblk2 = rblk_tmp; 1222 } 1223 1224 /* 1225 * Get the current usage for the resource control if it matched the 1226 * privilege and entity type criteria. 1227 */ 1228 if (list != NULL) { 1229 if (pr_getrctl(Pr, rctlname, NULL, rblk2, RCTL_USAGE) == 0) { 1230 list->usage = (rctl_qty_t *)malloc(sizeof (rctl_qty_t)); 1231 if (list->usage == NULL) { 1232 preserve_error(gettext("malloc failed: %s"), 1233 strerror(errno)); 1234 free(rblk1); 1235 free(rblk2); 1236 return (1); 1237 } 1238 *list->usage = rctlblk_get_value(rblk2); 1239 } else { 1240 list->usage = NULL; 1241 if (errno != ENOTSUP) { 1242 preserve_error(gettext("failed to get " 1243 "resource control usage for %s: %s"), 1244 rctlname, strerror(errno)); 1245 free(rblk1); 1246 free(rblk2); 1247 return (1); 1248 } 1249 } 1250 } 1251 free(rblk1); 1252 free(rblk2); 1253 return (0); 1254 } 1255 1256 /* 1257 * store_value_entry(rctlblk_t *, prctl_list_t *) 1258 * 1259 * Store an rblk for a given resource control into the global list. 1260 * 1261 * This function is Pgrab-safe. 1262 */ 1263 prctl_value_t * 1264 store_value_entry(rctlblk_t *rblk, prctl_list_t *list) 1265 { 1266 prctl_value_t *e = calloc(1, sizeof (prctl_value_t)); 1267 rctlblk_t *store_blk = calloc(1, rctlblk_size()); 1268 prctl_value_t *iter = list->val_list; 1269 1270 if (e == NULL || store_blk == NULL) { 1271 preserve_error(gettext("malloc failed %s"), 1272 strerror(errno)); 1273 if (e != NULL) 1274 free(e); 1275 if (store_blk != NULL) 1276 free(store_blk); 1277 return (NULL); 1278 } 1279 if (iter == NULL) 1280 list->val_list = e; 1281 else { 1282 while (iter->next != NULL) { 1283 iter = iter->next; 1284 } 1285 iter->next = e; 1286 } 1287 bcopy(rblk, store_blk, rctlblk_size()); 1288 1289 e->rblk = store_blk; 1290 e->next = NULL; 1291 return (e); 1292 } 1293 1294 /* 1295 * store_list_entry(const char *) 1296 * 1297 * Store a new resource control value in the global list. No checking 1298 * for duplicates done. 1299 * 1300 * This function is Pgrab-safe. 1301 */ 1302 prctl_list_t * 1303 store_list_entry(const char *name) 1304 { 1305 prctl_list_t *e = calloc(1, sizeof (prctl_list_t)); 1306 1307 if (e == NULL) { 1308 preserve_error(gettext("malloc failed %s"), 1309 strerror(errno)); 1310 return (NULL); 1311 } 1312 if ((e->name = calloc(1, strlen(name) + 1)) == NULL) { 1313 preserve_error(gettext("malloc failed %s"), 1314 strerror(errno)); 1315 free(e); 1316 return (NULL); 1317 } 1318 (void) strcpy(e->name, name); 1319 e->val_list = NULL; 1320 1321 if (global_rctl_list_head == NULL) { 1322 global_rctl_list_head = e; 1323 global_rctl_list_tail = e; 1324 } else { 1325 global_rctl_list_tail->next = e; 1326 global_rctl_list_tail = e; 1327 } 1328 e->next = NULL; 1329 return (e); 1330 } 1331 1332 /* 1333 * free_lists() 1334 * 1335 * Free all resource control blocks and values from the global lists. 1336 * 1337 * This function is Pgrab-safe. 1338 */ 1339 void 1340 free_lists() 1341 { 1342 prctl_list_t *new_list, *old_list = global_rctl_list_head; 1343 prctl_value_t *old_val, *new_val; 1344 1345 while (old_list != NULL) { 1346 old_val = old_list->val_list; 1347 while (old_val != NULL) { 1348 free(old_val->rblk); 1349 new_val = old_val->next; 1350 free(old_val); 1351 old_val = new_val; 1352 } 1353 free(old_list->name); 1354 free(old_list->usage); 1355 new_list = old_list->next; 1356 free(old_list); 1357 old_list = new_list; 1358 } 1359 global_rctl_list_head = NULL; 1360 global_rctl_list_tail = NULL; 1361 } 1362 1363 void 1364 print_heading() 1365 { 1366 1367 /* print headings */ 1368 (void) fprintf(stdout, "%-8s%-16s%-9s%-7s%-28s%10s\n", 1369 "NAME", "PRIVILEGE", "VALUE", 1370 "FLAG", "ACTION", "RECIPIENT"); 1371 } 1372 1373 /* 1374 * print_rctls() 1375 * 1376 * Print all resource controls from the global list that was 1377 * previously populated by store_rctls. 1378 */ 1379 void 1380 print_rctls(pr_info_handle_t *p) 1381 { 1382 prctl_list_t *iter_list = global_rctl_list_head; 1383 prctl_value_t *iter_val; 1384 rctl_qty_t rblk_value; 1385 rctl_priv_t rblk_priv; 1386 uint_t local_action; 1387 int signal, local_flags, global_flags; 1388 pid_t pid; 1389 char rctl_valuestring[SCALED_STRLEN]; 1390 char *unit = NULL; 1391 scale_t *scale; 1392 char *string; 1393 int doneheading = 0; 1394 1395 if (iter_list == NULL) 1396 return; 1397 1398 while (iter_list != NULL) { 1399 1400 if (doneheading == 0 && 1401 arg_entity_type == RCENTITY_PROCESS) { 1402 proc_unctrl_psinfo(&(p->psinfo)); 1403 doneheading = 1; 1404 (void) fprintf(stdout, 1405 "process: %d: %.70s\n", (int)p->pid, 1406 p->psinfo.pr_psargs); 1407 if (!arg_parseable_mode) 1408 print_heading(); 1409 } 1410 if (doneheading == 0 && 1411 arg_entity_type == RCENTITY_TASK) { 1412 doneheading = 1; 1413 (void) fprintf(stdout, "task: %d\n", (int)p->taskid); 1414 if (!arg_parseable_mode) 1415 print_heading(); 1416 } 1417 if (doneheading == 0 && 1418 arg_entity_type == RCENTITY_PROJECT) { 1419 if (!arg_parseable_mode && doneheading) 1420 (void) fprintf(stdout, "\n"); 1421 doneheading = 1; 1422 (void) fprintf(stdout, 1423 "project: %d: %.70s\n", (int)p->projid, 1424 p->projname); 1425 if (!arg_parseable_mode) 1426 print_heading(); 1427 } 1428 if (doneheading == 0 && 1429 arg_entity_type == RCENTITY_ZONE) { 1430 doneheading = 1; 1431 (void) fprintf(stdout, 1432 "zone: %d: %.70s\n", (int)p->zoneid, 1433 p->zonename); 1434 if (!arg_parseable_mode) 1435 print_heading(); 1436 } 1437 /* only print name once in normal output */ 1438 if (!arg_parseable_mode) 1439 (void) fprintf(stdout, "%s\n", iter_list->name); 1440 1441 iter_val = iter_list->val_list; 1442 1443 /* if for some reason there are no values, skip */ 1444 if (iter_val == 0) 1445 continue; 1446 1447 1448 /* get the global flags the first rctl only */ 1449 global_flags = rctlblk_get_global_flags(iter_val->rblk); 1450 1451 1452 if (global_flags & RCTL_GLOBAL_BYTES) { 1453 unit = SCALED_UNIT_BYTES; 1454 scale = scale_binary; 1455 1456 } else if (global_flags & RCTL_GLOBAL_SECONDS) { 1457 unit = SCALED_UNIT_SECONDS; 1458 scale = scale_metric; 1459 1460 } else { 1461 unit = SCALED_UNIT_NONE; 1462 scale = scale_metric; 1463 } 1464 1465 /* print the current usage for the rctl if available */ 1466 if (iter_list->usage != NULL) { 1467 rblk_value = *(iter_list->usage); 1468 if (!arg_parseable_mode) { 1469 (void) uint64toscaled(rblk_value, 4, "E", 1470 rctl_valuestring, NULL, NULL, 1471 scale, NULL, 0); 1472 1473 (void) fprintf(stdout, "%8s%-16s%5s%-4s\n", 1474 "", "usage", rctl_valuestring, unit); 1475 } else { 1476 (void) fprintf(stdout, "%s %s %llu - - -\n", 1477 iter_list->name, "usage", rblk_value); 1478 } 1479 } 1480 1481 /* iterate over an print all control values */ 1482 while (iter_val != NULL) { 1483 1484 /* print name or empty name field */ 1485 if (!arg_parseable_mode) 1486 (void) fprintf(stdout, "%8s", ""); 1487 else 1488 (void) fprintf(stdout, "%s ", iter_list->name); 1489 1490 1491 rblk_priv = rctlblk_get_privilege(iter_val->rblk); 1492 if (!arg_parseable_mode) 1493 print_priv(rblk_priv, "%-16s"); 1494 else 1495 print_priv(rblk_priv, "%s "); 1496 1497 rblk_value = rctlblk_get_value(iter_val->rblk); 1498 if (arg_parseable_mode) { 1499 (void) fprintf(stdout, "%llu ", rblk_value); 1500 1501 } else { 1502 1503 (void) uint64toscaled(rblk_value, 4, "E", 1504 rctl_valuestring, NULL, NULL, 1505 scale, NULL, 0); 1506 1507 (void) fprintf(stdout, "%5s", 1508 rctl_valuestring); 1509 (void) fprintf(stdout, "%-4s", unit); 1510 } 1511 local_flags = rctlblk_get_local_flags(iter_val->rblk); 1512 1513 if (local_flags & RCTL_LOCAL_MAXIMAL) { 1514 1515 if (global_flags & RCTL_GLOBAL_INFINITE) { 1516 string = "inf"; 1517 } else { 1518 string = "max"; 1519 } 1520 } else { 1521 string = "-"; 1522 } 1523 if (arg_parseable_mode) 1524 (void) fprintf(stdout, "%s ", string); 1525 else 1526 (void) fprintf(stdout, "%4s%3s", 1527 string, ""); 1528 1529 1530 local_action = rctlblk_get_local_action(iter_val->rblk, 1531 &signal); 1532 1533 if (arg_parseable_mode) 1534 print_local_action(local_action, &signal, 1535 "%s "); 1536 else 1537 print_local_action(local_action, &signal, 1538 "%-28s"); 1539 1540 pid = rctlblk_get_recipient_pid(iter_val->rblk); 1541 1542 if (arg_parseable_mode) { 1543 if (pid < 0) { 1544 (void) fprintf(stdout, "%s\n", "-"); 1545 } else { 1546 (void) fprintf(stdout, "%d\n", 1547 (int)pid); 1548 } 1549 } else { 1550 if (pid < 0) { 1551 (void) fprintf(stdout, "%10s\n", "-"); 1552 } else { 1553 (void) fprintf(stdout, "%10d\n", 1554 (int)pid); 1555 } 1556 } 1557 iter_val = iter_val->next; 1558 } 1559 iter_list = iter_list->next; 1560 } 1561 } 1562 1563 /* 1564 * 1565 * match_rctl 1566 * 1567 * find the first rctl with matching name, value, priv, and recipient pid 1568 */ 1569 int 1570 match_rctl(struct ps_prochandle *Pr, rctlblk_t **rctl, char *name, 1571 char *valuestringin, int valuein, rctl_priv_t privin, int pidin) 1572 { 1573 rctlblk_t *next; 1574 rctlblk_t *last; 1575 rctlblk_t *tmp; 1576 1577 *rctl = NULL; 1578 1579 next = calloc(1, rctlblk_size()); 1580 last = calloc(1, rctlblk_size()); 1581 1582 if ((last == NULL) || (next == NULL)) { 1583 preserve_error(gettext("malloc failed"), strerror(errno)); 1584 return (-1); 1585 } 1586 /* 1587 * For this resource name, now iterate through all 1588 * the controls, looking for a match to the 1589 * user-specified input. 1590 */ 1591 if (pr_getrctl(Pr, name, NULL, next, RCTL_FIRST)) { 1592 preserve_error(gettext("failed to get resource control " 1593 "for %s: %s"), name, strerror(errno)); 1594 return (-1); 1595 } 1596 if (match_rctl_blk(next, valuestringin, valuein, privin, pidin) == 1) { 1597 free(last); 1598 *rctl = next; 1599 return (0); 1600 } 1601 tmp = next; 1602 next = last; 1603 last = tmp; 1604 1605 while (pr_getrctl(Pr, name, last, next, RCTL_NEXT) == 0) { 1606 1607 /* allow user interrupt */ 1608 if (interrupt) 1609 break; 1610 1611 if (match_rctl_blk(next, valuestringin, valuein, privin, pidin) 1612 == 1) { 1613 free(last); 1614 *rctl = next; 1615 return (0); 1616 } 1617 tmp = next; 1618 next = last; 1619 last = tmp; 1620 } 1621 free(next); 1622 free(last); 1623 1624 return (1); 1625 } 1626 1627 /* 1628 * int match_rctl_blk(rctlblk_t *, char *, uint64, rctl_priv_t, int pid) 1629 * 1630 * Input 1631 * Must supply a valid rctl, value, privilege, and pid to match on. 1632 * If valuestring is NULL, then valuestring and valuein will not be used 1633 * If privilege type is 0 it will not be used. 1634 * If pid is -1 it will not be used. 1635 * 1636 * Return values 1637 * Returns 1 if a matching rctl given matches the parameters specified, and 1638 * 0 if they do not. 1639 * 1640 * This function is Pgrab-safe. 1641 */ 1642 int 1643 match_rctl_blk(rctlblk_t *rctl, char *valuestringin, 1644 uint64_t valuein, rctl_priv_t privin, int pidin) 1645 { 1646 1647 rctl_qty_t value; 1648 rctl_priv_t priv; 1649 pid_t pid; 1650 int valuematch = 1; 1651 int privmatch = 1; 1652 int pidmatch = 1; 1653 1654 value = rctlblk_get_value(rctl); 1655 priv = rctlblk_get_privilege(rctl); 1656 pid = rctlblk_get_recipient_pid(rctl); 1657 1658 if (valuestringin) { 1659 1660 if (arg_modifier == NULL) { 1661 valuematch = (valuein == value); 1662 } else { 1663 valuematch = scaledequint64(valuestringin, value, 1664 PRCTL_VALUE_WIDTH, 1665 arg_scale, arg_unit, 1666 SCALED_ALL_FLAGS); 1667 } 1668 } 1669 if (privin != 0) { 1670 privmatch = (privin == priv); 1671 } 1672 if (pidin != -1) { 1673 pidmatch = (pidin == pid); 1674 } 1675 return (valuematch && privmatch && pidmatch); 1676 } 1677 1678 static int 1679 change_action(rctlblk_t *blk) 1680 { 1681 int signal = 0; 1682 int action; 1683 1684 action = rctlblk_get_local_action(blk, &signal); 1685 1686 if (arg_operation & ACTION_ENABLE) { 1687 1688 if (arg_action & RCTL_LOCAL_SIGNAL) { 1689 signal = arg_signal; 1690 } 1691 action = action | arg_action; 1692 /* add local action */ 1693 rctlblk_set_local_action(blk, action, signal); 1694 1695 } else if (arg_operation & ACTION_DISABLE) { 1696 1697 /* 1698 * if deleting signal and signal number is specified, 1699 * then signal number must match 1700 */ 1701 if ((arg_action & RCTL_LOCAL_SIGNAL) && 1702 (arg_signal != -1)) { 1703 if (arg_signal != signal) { 1704 preserve_error(gettext("signal name or number " 1705 "does not match existing action")); 1706 return (-1); 1707 } 1708 } 1709 /* remove local action */ 1710 action = action & (~arg_action); 1711 rctlblk_set_local_action(blk, RCTL_LOCAL_NOACTION, 0); 1712 rctlblk_set_local_action(blk, action, signal); 1713 } 1714 /* enable deny if it must be enabled */ 1715 if (arg_global_flags & RCTL_GLOBAL_DENY_ALWAYS) { 1716 rctlblk_set_local_action(blk, RCTL_LOCAL_DENY | action, 1717 signal); 1718 } 1719 return (0); 1720 } 1721 1722 /* 1723 * prctl_setrctl 1724 * 1725 * Input 1726 * This function expects that input has been validated. In the 1727 * case of a replace operation, both old_rblk and new_rblk must 1728 * be valid resource controls. If a resource control is being 1729 * created, only new_rblk must be supplied. If a resource control 1730 * is being deleted, only new_rblk must be supplied. 1731 * 1732 * If the privilege is a priviliged type, at this time, the process 1733 * tries to take on superuser privileges. 1734 */ 1735 int 1736 prctl_setrctl(struct ps_prochandle *Pr, const char *name, 1737 rctlblk_t *old_rblk, rctlblk_t *new_rblk, uint_t flags) 1738 { 1739 int ret = 0; 1740 rctl_priv_t rblk_priv; 1741 psinfo_t psinfo; 1742 zoneid_t oldzoneid = GLOBAL_ZONEID; 1743 prpriv_t *old_prpriv = NULL, *new_prpriv = NULL; 1744 priv_set_t *eset, *pset; 1745 boolean_t relinquish_failed = B_FALSE; 1746 1747 rblk_priv = rctlblk_get_privilege(new_rblk); 1748 1749 if (rblk_priv == RCPRIV_SYSTEM) { 1750 preserve_error(gettext("cannot modify system values")); 1751 return (1); 1752 } 1753 if (rblk_priv == RCPRIV_PRIVILEGED) { 1754 new_prpriv = proc_get_priv(Pstatus(Pr)->pr_pid); 1755 if (new_prpriv == NULL) { 1756 preserve_error(gettext("cannot get process privileges " 1757 "for pid %d: %s"), Pstatus(Pr)->pr_pid, 1758 strerror(errno)); 1759 return (1); 1760 } 1761 /* 1762 * We only have to change the process privileges if it doesn't 1763 * already have PRIV_SYS_RESOURCE. In addition, we want to make 1764 * sure that we don't leave a process with elevated privileges, 1765 * so we make sure the process dies if we exit unexpectedly. 1766 */ 1767 eset = (priv_set_t *) 1768 &new_prpriv->pr_sets[new_prpriv->pr_setsize * 1769 priv_getsetbyname(PRIV_EFFECTIVE)]; 1770 pset = (priv_set_t *) 1771 &new_prpriv->pr_sets[new_prpriv->pr_setsize * 1772 priv_getsetbyname(PRIV_PERMITTED)]; 1773 if (!priv_ismember(eset, PRIV_SYS_RESOURCE)) { 1774 /* Keep track of original privileges */ 1775 old_prpriv = proc_get_priv(Pstatus(Pr)->pr_pid); 1776 if (old_prpriv == NULL) { 1777 preserve_error(gettext("cannot get process " 1778 "privileges for pid %d: %s"), 1779 Pstatus(Pr)->pr_pid, strerror(errno)); 1780 free(new_prpriv); 1781 return (1); 1782 } 1783 (void) priv_addset(eset, PRIV_SYS_RESOURCE); 1784 (void) priv_addset(pset, PRIV_SYS_RESOURCE); 1785 if (Psetflags(Pr, PR_KLC) != 0 || 1786 Psetpriv(Pr, new_prpriv) != 0) { 1787 preserve_error(gettext("cannot set process " 1788 "privileges for pid %d: %s"), 1789 Pstatus(Pr)->pr_pid, strerror(errno)); 1790 (void) Punsetflags(Pr, PR_KLC); 1791 free(new_prpriv); 1792 free(old_prpriv); 1793 return (1); 1794 } 1795 } 1796 /* 1797 * If this is a zone.* rctl, it requires more than 1798 * PRIV_SYS_RESOURCE: it wants the process to have global-zone 1799 * credentials. We temporarily grant non-global zone processes 1800 * these credentials, and make sure the process dies if we exit 1801 * unexpectedly. 1802 */ 1803 if (arg_name && 1804 arg_name_entity == RCENTITY_ZONE && 1805 getzoneid() == GLOBAL_ZONEID && 1806 proc_get_psinfo(Pstatus(Pr)->pr_pid, &psinfo) == 0 && 1807 (oldzoneid = psinfo.pr_zoneid) != GLOBAL_ZONEID) { 1808 /* 1809 * We need to give this process superuser 1810 * ("super-zone") privileges. 1811 * 1812 * Must never return without setting this back! 1813 */ 1814 if (Psetflags(Pr, PR_KLC) != 0 || 1815 Psetzoneid(Pr, GLOBAL_ZONEID) < 0) { 1816 preserve_error(gettext( 1817 "cannot set global-zone " 1818 "privileges for pid %d: %s"), 1819 Pstatus(Pr)->pr_pid, strerror(errno)); 1820 /* 1821 * We couldn't set the zoneid to begin with, so 1822 * there's no point in warning the user about 1823 * trying to un-set it. 1824 */ 1825 oldzoneid = GLOBAL_ZONEID; 1826 ret = 1; 1827 goto bail; 1828 } 1829 } 1830 } 1831 /* Now, actually populate the rctlblk in the kernel */ 1832 if (flags == RCTL_REPLACE) { 1833 /* 1834 * Replace should be a delete followed by an insert. This 1835 * allows us to replace rctl value blocks which match in 1836 * privilege and value, but have updated actions, etc. 1837 * setrctl() doesn't allow a direct replace, but we 1838 * should do the right thing for the user in the command. 1839 */ 1840 if (pr_setrctl(Pr, name, NULL, 1841 old_rblk, RCTL_DELETE)) { 1842 preserve_error(gettext("failed to delete resource " 1843 "control %s for pid %d: %s"), name, 1844 Pstatus(Pr)->pr_pid, strerror(errno)); 1845 ret = 1; 1846 goto bail; 1847 } 1848 if (pr_setrctl(Pr, name, NULL, 1849 new_rblk, RCTL_INSERT)) { 1850 preserve_error(gettext("failed to insert resource " 1851 "control %s for pid %d: %s"), name, 1852 Pstatus(Pr)->pr_pid, strerror(errno)); 1853 ret = 1; 1854 goto bail; 1855 } 1856 } else if (flags == RCTL_INSERT) { 1857 if (pr_setrctl(Pr, name, NULL, 1858 new_rblk, RCTL_INSERT)) { 1859 preserve_error(gettext("failed to create resource " 1860 "control %s for pid %d: %s"), name, 1861 Pstatus(Pr)->pr_pid, strerror(errno)); 1862 ret = 1; 1863 goto bail; 1864 } 1865 } else if (flags == RCTL_DELETE) { 1866 if (pr_setrctl(Pr, name, NULL, 1867 new_rblk, RCTL_DELETE)) { 1868 preserve_error(gettext("failed to delete resource " 1869 "control %s for pid %d: %s"), name, 1870 Pstatus(Pr)->pr_pid, strerror(errno)); 1871 ret = 1; 1872 goto bail; 1873 } 1874 } 1875 bail: 1876 if (oldzoneid != GLOBAL_ZONEID) { 1877 if (Psetzoneid(Pr, oldzoneid) != 0) 1878 relinquish_failed = B_TRUE; 1879 } 1880 if (old_prpriv != NULL) { 1881 if (Psetpriv(Pr, old_prpriv) != 0) 1882 relinquish_failed = B_TRUE; 1883 free(old_prpriv); 1884 } 1885 if (relinquish_failed) { 1886 /* 1887 * If this failed, we can't leave a process hanging 1888 * around with elevated privileges, so we'll have to 1889 * release the process from libproc, knowing that it 1890 * will be killed (since we set PR_KLC). 1891 */ 1892 Pdestroy_agent(Pr); 1893 preserve_error(gettext("cannot relinquish privileges " 1894 "for pid %d. The process was killed."), 1895 Pstatus(Pr)->pr_pid); 1896 } else { 1897 if (Punsetflags(Pr, PR_KLC) != 0) 1898 preserve_error(gettext("cannot relinquish privileges " 1899 "for pid %d. The process was killed."), 1900 Pstatus(Pr)->pr_pid); 1901 } 1902 if (new_prpriv != NULL) 1903 free(new_prpriv); 1904 1905 return (ret); 1906 } 1907 1908 void 1909 print_priv(rctl_priv_t local_priv, char *format) 1910 { 1911 char pstring[11]; 1912 1913 switch (local_priv) { 1914 case RCPRIV_BASIC: 1915 (void) strcpy(pstring, "basic"); 1916 break; 1917 case RCPRIV_PRIVILEGED: 1918 (void) strcpy(pstring, "privileged"); 1919 break; 1920 case RCPRIV_SYSTEM: 1921 (void) strcpy(pstring, "system"); 1922 break; 1923 default: 1924 (void) sprintf(pstring, "%d", local_priv); 1925 break; 1926 } 1927 /* LINTED */ 1928 (void) fprintf(stdout, format, pstring); 1929 } 1930 1931 void 1932 print_local_action(int action, int *signalp, char *format) 1933 { 1934 char sig[SIG2STR_MAX]; 1935 char sigstring[SIG2STR_MAX + 7]; 1936 char astring[5 + SIG2STR_MAX + 7]; 1937 int set = 0; 1938 1939 astring[0] = '\0'; 1940 1941 if (action == RCTL_LOCAL_NOACTION) { 1942 (void) strcat(astring, "none"); 1943 set++; 1944 } 1945 if (action & RCTL_LOCAL_DENY) { 1946 (void) strcat(astring, "deny"); 1947 set++; 1948 } 1949 if ((action & RCTL_LOCAL_DENY) && 1950 (action & RCTL_LOCAL_SIGNAL)) { 1951 (void) strcat(astring, ","); 1952 } 1953 if (action & RCTL_LOCAL_SIGNAL) { 1954 if (sig2str(*signalp, sig)) 1955 (void) snprintf(sigstring, sizeof (astring), 1956 "signal=%d", *signalp); 1957 else 1958 (void) snprintf(sigstring, sizeof (astring), 1959 "signal=%s", sig); 1960 1961 (void) strcat(astring, sigstring); 1962 set++; 1963 } 1964 if (set) 1965 /* LINTED */ 1966 (void) fprintf(stdout, format, astring); 1967 else 1968 /* LINTED */ 1969 (void) fprintf(stdout, format, action); 1970 } 1971 1972 /* 1973 * This function is used to grab the process matching the recipient pid 1974 */ 1975 pid_t 1976 regrab_process(pid_t pid, pr_info_handle_t *p, int priv, int *gret) 1977 { 1978 1979 char pidstring[24]; 1980 1981 gret = 0; 1982 if (pid == -1) 1983 return (p->pid); 1984 if (p->pid == pid) 1985 return (p->pid); 1986 1987 release_process(p->pr); 1988 (void) memset(p, 0, sizeof (*p)); 1989 1990 (void) snprintf(pidstring, 24, "%d", pid); 1991 return (grab_process_by_id( 1992 pidstring, RCENTITY_PROCESS, p, priv, gret)); 1993 } 1994 1995 /* 1996 * int grab_process_by_id(char *, rctl_entity_t, pr_info_handle_t *, int, int *) 1997 * 1998 * Input 1999 * Supply a non-NULL string containing: 2000 * - logical project/zone name or project/zone number if type is 2001 * RCENTITY_PROJECT or RCENTITY_ZONE 2002 * - task number if type is RCENTITY_TYPE 2003 * - a pid if type is RCENTITY_PID 2004 * Also supply an un-allocated prochandle, and an allocated info_handle. 2005 * This function assumes that the type is set. 2006 * If priv is not RCPRIV_BASIC, the grabbed process is required to have 2007 * PRIV_SYS_RESOURCE in it's limit set. 2008 * 2009 * Return Values 2010 * Returns 0 on success and 1 on failure. If there is a process 2011 * running under the specified id, success is returned, and 2012 * Pr is pointed to the process. Success will be returned and Pr 2013 * set to NULL if the matching process is our own. 2014 * If success is returned, psinfo will be valid, and pid will 2015 * be the process number. The process will also be held at the 2016 * end, so release_process should be used by the caller. 2017 * 2018 * This function assumes that signals are caught already so that libproc 2019 * can be safely used. 2020 * 2021 * Return Values 2022 * pid - Process found and grabbed 2023 * -1 - Error 2024 */ 2025 pid_t 2026 grab_process_by_id(char *idname, rctl_entity_t type, pr_info_handle_t *p, 2027 int priv, int *gret) 2028 { 2029 char prbuf[PROJECT_BUFSZ]; 2030 projid_t projid; 2031 taskid_t taskid; 2032 zoneid_t zoneid; 2033 zoneid_t zone_self; 2034 struct project proj; 2035 DIR *dirp; 2036 struct dirent *dentp; 2037 int found = 0; 2038 int pid_self; 2039 int ret; 2040 int gret_in; 2041 int intidname; 2042 char *end; 2043 prpriv_t *prpriv; 2044 priv_set_t *prset; 2045 2046 gret_in = *gret; 2047 2048 /* get our pid se we do not try to operate on self */ 2049 pid_self = getpid(); 2050 2051 /* Store integer version of id */ 2052 intidname = strtoul(idname, &end, 10); 2053 if (errno || *end != '\0' || end == idname) { 2054 intidname = -1; 2055 } 2056 2057 /* 2058 * get our zoneid so we don't try to operate on a project in 2059 * another zone 2060 */ 2061 zone_self = getzoneid(); 2062 2063 if (idname == NULL || strcmp(idname, "") == 0) { 2064 warn(gettext("id name cannot be nuint64\n")); 2065 return (-1); 2066 } 2067 /* 2068 * Set up zoneid, projid or taskid, as appropriate, so that comparisons 2069 * can be done later with the input. 2070 */ 2071 if (type == RCENTITY_ZONE) { 2072 if (zone_get_id(idname, &zoneid) != 0) { 2073 warn(gettext("%s: unknown zone\n"), idname); 2074 return (-1); 2075 } 2076 } else if (type == RCENTITY_PROJECT) { 2077 if (getprojbyname(idname, &proj, prbuf, PROJECT_BUFSZ) 2078 == NULL) { 2079 if (getprojbyid(intidname, &proj, prbuf, 2080 PROJECT_BUFSZ) == NULL) { 2081 warn(gettext("%s: cannot find project\n"), 2082 idname); 2083 return (-1); 2084 } 2085 } 2086 projid = proj.pj_projid; 2087 } else if (type == RCENTITY_TASK) { 2088 taskid = (taskid_t)atol(idname); 2089 } 2090 /* 2091 * Projects and tasks need to search through /proc for 2092 * a parent process. 2093 */ 2094 if (type == RCENTITY_ZONE || type == RCENTITY_PROJECT || 2095 type == RCENTITY_TASK) { 2096 if ((dirp = opendir("/proc")) == NULL) { 2097 warn(gettext("%s: cannot open /proc directory\n"), 2098 idname); 2099 return (-1); 2100 } 2101 /* 2102 * Look through all processes in /proc. For each process, 2103 * check if the pr_projid in their psinfo matches the 2104 * specified id. 2105 */ 2106 while (dentp = readdir(dirp)) { 2107 p->pid = atoi(dentp->d_name); 2108 2109 /* Skip self */ 2110 if (p->pid == pid_self) 2111 continue; 2112 2113 if (proc_get_psinfo(p->pid, &(p->psinfo)) != 0) 2114 continue; 2115 2116 /* Skip process if it is not what we are looking for */ 2117 if (type == RCENTITY_ZONE && 2118 (p->psinfo).pr_zoneid != zoneid) { 2119 continue; 2120 } else if (type == RCENTITY_PROJECT && 2121 ((p->psinfo).pr_projid != projid || 2122 (p->psinfo).pr_zoneid != zone_self)) { 2123 continue; 2124 } else if (type == RCENTITY_TASK && 2125 (p->psinfo).pr_taskid != taskid) { 2126 continue; 2127 } 2128 /* attempt to grab process */ 2129 if (grab_process(p, gret) != 0) 2130 continue; 2131 2132 /* 2133 * Re-confirm that this process is still running as 2134 * part of the specified project or task. If it 2135 * doesn't match, release the process and return an 2136 * error. This should only be done if the Pr struct is 2137 * not NULL. 2138 */ 2139 if (type == RCENTITY_PROJECT) { 2140 if (pr_getprojid(p->pr) != projid || 2141 pr_getzoneid(p->pr) != zone_self) { 2142 release_process(p->pr); 2143 continue; 2144 } 2145 } else if (type == RCENTITY_TASK) { 2146 if (pr_gettaskid(p->pr) != taskid) { 2147 release_process(p->pr); 2148 continue; 2149 } 2150 } else if (type == RCENTITY_ZONE) { 2151 if (pr_getzoneid(p->pr) != zoneid) { 2152 release_process(p->pr); 2153 continue; 2154 } 2155 } 2156 2157 /* 2158 * If we are setting a privileged resource control, 2159 * verify that process has PRIV_SYS_RESOURCE in it's 2160 * limit set. If it does not, then we will not be 2161 * able to give this process the privilege it needs 2162 * to set the resource control. 2163 */ 2164 if (priv != RCPRIV_BASIC) { 2165 prpriv = proc_get_priv(p->pid); 2166 if (prpriv == NULL) { 2167 release_process(p->pr); 2168 continue; 2169 } 2170 prset = (priv_set_t *) 2171 &prpriv->pr_sets[prpriv->pr_setsize * 2172 priv_getsetbyname(PRIV_LIMIT)]; 2173 if (!priv_ismember(prset, PRIV_SYS_RESOURCE)) { 2174 release_process(p->pr); 2175 continue; 2176 } 2177 } 2178 found = 1; 2179 2180 p->taskid = pr_gettaskid(p->pr); 2181 p->projid = pr_getprojid(p->pr); 2182 p->zoneid = pr_getzoneid(p->pr); 2183 2184 break; 2185 } 2186 (void) closedir(dirp); 2187 2188 if (found == 0) { 2189 warn(gettext("%s: No controllable process found in " 2190 "task, project, or zone.\n"), idname); 2191 return (-1); 2192 } 2193 return (p->pid); 2194 2195 } else if (type == RCENTITY_PROCESS) { 2196 2197 /* fail if self */ 2198 if (p->pid == pid_self) { 2199 2200 warn(gettext("%s: cannot control self"), idname); 2201 return (-1); 2202 } 2203 /* 2204 * Process types need to be set up with the correct pid 2205 * and psinfo structure. 2206 */ 2207 if ((p->pid = proc_arg_psinfo(idname, PR_ARG_PIDS, 2208 &(p->psinfo), gret)) == -1) { 2209 warn(gettext("%s: cannot examine: %s"), idname, 2210 Pgrab_error(*gret)); 2211 return (-1); 2212 } 2213 /* grab process */ 2214 ret = grab_process(p, gret); 2215 if (ret == 1) { 2216 /* Don't print error if G_SYS is allowed */ 2217 if (gret_in == G_SYS && *gret == G_SYS) { 2218 return (-1); 2219 } else { 2220 warn(gettext("%s: cannot control: %s"), idname, 2221 Pgrab_error(*gret)); 2222 return (-1); 2223 } 2224 } else if (ret == 2) { 2225 ret = errno; 2226 warn(gettext("%s: cannot control: %s"), idname, 2227 strerror(ret)); 2228 return (-1); 2229 } 2230 p->taskid = pr_gettaskid(p->pr); 2231 p->projid = pr_getprojid(p->pr); 2232 p->zoneid = pr_getzoneid(p->pr); 2233 2234 return (p->pid); 2235 2236 } else { 2237 warn(gettext("%s: unknown resource entity type %d\n"), idname, 2238 type); 2239 return (-1); 2240 } 2241 } 2242 2243 /* 2244 * Do the work required to manipulate a process through libproc. 2245 * If grab_process() returns no errors (0), then release_process() 2246 * must eventually be called. 2247 * 2248 * Return values: 2249 * 0 Successful creation of agent thread 2250 * 1 Error grabbing 2251 * 2 Error creating agent 2252 */ 2253 int 2254 grab_process(pr_info_handle_t *p, int *gret) 2255 { 2256 2257 if ((p->pr = Pgrab(p->pid, arg_force, gret)) != NULL) { 2258 2259 if (Psetflags(p->pr, PR_RLC) != 0) { 2260 Prelease(p->pr, 0); 2261 return (1); 2262 } 2263 if (Pcreate_agent(p->pr) == 0) { 2264 return (0); 2265 2266 } else { 2267 Prelease(p->pr, 0); 2268 return (2); 2269 } 2270 } else { 2271 return (1); 2272 } 2273 } 2274 2275 /* 2276 * Release the specified process. This destroys the agent 2277 * and releases the process. If the process is NULL, nothing 2278 * is done. This function should only be called if grab_process() 2279 * has previously been called and returned success. 2280 * 2281 * This function is Pgrab-safe. 2282 */ 2283 void 2284 release_process(struct ps_prochandle *Pr) 2285 { 2286 if (Pr == NULL) 2287 return; 2288 2289 Pdestroy_agent(Pr); 2290 Prelease(Pr, 0); 2291 } 2292 2293 /* 2294 * preserve_error(char *, ...) 2295 * 2296 * preserve_error() should be called rather than warn() by any 2297 * function that is called while the victim process is held by Pgrab. 2298 * It will save the error until the process has been un-controlled 2299 * and output is reasonable again. 2300 * 2301 * Note that multiple errors are not stored. Any error in these 2302 * sections should be critical and return immediately. 2303 * 2304 * This function is Pgrab-safe. 2305 * 2306 * Since this function may copy untrusted command line arguments to 2307 * global_error, security practices require that global_error never be 2308 * printed directly. Use printf("%s\n", global_error) or equivalent. 2309 */ 2310 /*PRINTFLIKE1*/ 2311 void 2312 preserve_error(char *format, ...) 2313 { 2314 va_list alist; 2315 2316 va_start(alist, format); 2317 2318 /* 2319 * GLOBAL_ERR_SZ is pretty big. If the error is longer 2320 * than that, just truncate it, rather than chance missing 2321 * the error altogether. 2322 */ 2323 (void) vsnprintf(global_error, GLOBAL_ERR_SZ-1, format, alist); 2324 2325 va_end(alist); 2326 } 2327