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