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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 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 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) setprogname(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 free(rblk1); 1224 free(rblk2); 1225 return (0); 1226 } 1227 1228 /* 1229 * store_value_entry(rctlblk_t *, prctl_list_t *) 1230 * 1231 * Store an rblk for a given resource control into the global list. 1232 * 1233 * This function is Pgrab-safe. 1234 */ 1235 prctl_value_t * 1236 store_value_entry(rctlblk_t *rblk, prctl_list_t *list) 1237 { 1238 prctl_value_t *e = calloc(1, sizeof (prctl_value_t)); 1239 rctlblk_t *store_blk = calloc(1, rctlblk_size()); 1240 prctl_value_t *iter = list->val_list; 1241 1242 if (e == NULL || store_blk == NULL) { 1243 preserve_error(gettext("malloc failed %s"), 1244 strerror(errno)); 1245 if (e != NULL) 1246 free(e); 1247 if (store_blk != NULL) 1248 free(store_blk); 1249 return (NULL); 1250 } 1251 if (iter == NULL) 1252 list->val_list = e; 1253 else { 1254 while (iter->next != NULL) { 1255 iter = iter->next; 1256 } 1257 iter->next = e; 1258 } 1259 bcopy(rblk, store_blk, rctlblk_size()); 1260 1261 e->rblk = store_blk; 1262 e->next = NULL; 1263 return (e); 1264 } 1265 1266 /* 1267 * store_list_entry(const char *) 1268 * 1269 * Store a new resource control value in the global list. No checking 1270 * for duplicates done. 1271 * 1272 * This function is Pgrab-safe. 1273 */ 1274 prctl_list_t * 1275 store_list_entry(const char *name) 1276 { 1277 prctl_list_t *e = calloc(1, sizeof (prctl_list_t)); 1278 1279 if (e == NULL) { 1280 preserve_error(gettext("malloc failed %s"), 1281 strerror(errno)); 1282 return (NULL); 1283 } 1284 if ((e->name = calloc(1, strlen(name) + 1)) == NULL) { 1285 preserve_error(gettext("malloc failed %s"), 1286 strerror(errno)); 1287 free(e); 1288 return (NULL); 1289 } 1290 (void) strcpy(e->name, name); 1291 e->val_list = NULL; 1292 1293 if (global_rctl_list_head == NULL) { 1294 global_rctl_list_head = e; 1295 global_rctl_list_tail = e; 1296 } else { 1297 global_rctl_list_tail->next = e; 1298 global_rctl_list_tail = e; 1299 } 1300 e->next = NULL; 1301 return (e); 1302 } 1303 1304 /* 1305 * free_lists() 1306 * 1307 * Free all resource control blocks and values from the global lists. 1308 * 1309 * This function is Pgrab-safe. 1310 */ 1311 void 1312 free_lists() 1313 { 1314 prctl_list_t *new_list, *old_list = global_rctl_list_head; 1315 prctl_value_t *old_val, *new_val; 1316 1317 while (old_list != NULL) { 1318 old_val = old_list->val_list; 1319 while (old_val != NULL) { 1320 free(old_val->rblk); 1321 new_val = old_val->next; 1322 free(old_val); 1323 old_val = new_val; 1324 } 1325 free(old_list->name); 1326 new_list = old_list->next; 1327 free(old_list); 1328 old_list = new_list; 1329 } 1330 global_rctl_list_head = NULL; 1331 global_rctl_list_tail = NULL; 1332 } 1333 1334 void 1335 print_heading() 1336 { 1337 1338 /* print headings */ 1339 (void) fprintf(stdout, "%-8s%-16s%-9s%-7s%-28s%10s\n", 1340 "NAME", "PRIVILEGE", "VALUE", 1341 "FLAG", "ACTION", "RECIPIENT"); 1342 } 1343 1344 /* 1345 * print_rctls() 1346 * 1347 * Print all resource controls from the global list that was 1348 * previously populated by store_rctls. 1349 */ 1350 void 1351 print_rctls(pr_info_handle_t *p) 1352 { 1353 prctl_list_t *iter_list = global_rctl_list_head; 1354 prctl_value_t *iter_val; 1355 rctl_qty_t rblk_value; 1356 rctl_priv_t rblk_priv; 1357 uint_t local_action; 1358 int signal, local_flags, global_flags; 1359 pid_t pid; 1360 char rctl_valuestring[SCALED_STRLEN]; 1361 char *unit = NULL; 1362 scale_t *scale; 1363 char *string; 1364 int doneheading = 0; 1365 1366 if (iter_list == NULL) 1367 return; 1368 1369 while (iter_list != NULL) { 1370 1371 if (doneheading == 0 && 1372 arg_entity_type == RCENTITY_PROCESS) { 1373 proc_unctrl_psinfo(&(p->psinfo)); 1374 doneheading = 1; 1375 (void) fprintf(stdout, 1376 "process: %d: %.70s\n", (int)p->pid, 1377 p->psinfo.pr_psargs); 1378 if (!arg_parseable_mode) 1379 print_heading(); 1380 } 1381 if (doneheading == 0 && 1382 arg_entity_type == RCENTITY_TASK) { 1383 doneheading = 1; 1384 (void) fprintf(stdout, "task: %d\n", (int)p->taskid); 1385 if (!arg_parseable_mode) 1386 print_heading(); 1387 } 1388 if (doneheading == 0 && 1389 arg_entity_type == RCENTITY_PROJECT) { 1390 if (!arg_parseable_mode && doneheading) 1391 (void) fprintf(stdout, "\n"); 1392 doneheading = 1; 1393 (void) fprintf(stdout, 1394 "project: %d: %.70s\n", (int)p->projid, 1395 p->projname); 1396 if (!arg_parseable_mode) 1397 print_heading(); 1398 } 1399 if (doneheading == 0 && 1400 arg_entity_type == RCENTITY_ZONE) { 1401 doneheading = 1; 1402 (void) fprintf(stdout, 1403 "zone: %d: %.70s\n", (int)p->zoneid, 1404 p->zonename); 1405 if (!arg_parseable_mode) 1406 print_heading(); 1407 } 1408 /* only print name once in normal output */ 1409 if (!arg_parseable_mode) 1410 (void) fprintf(stdout, "%s\n", iter_list->name); 1411 1412 iter_val = iter_list->val_list; 1413 1414 /* if for some reason there are no values, skip */ 1415 if (iter_val == 0) 1416 continue; 1417 1418 1419 /* get the global flags the first rctl only */ 1420 global_flags = rctlblk_get_global_flags(iter_val->rblk); 1421 1422 1423 if (global_flags & RCTL_GLOBAL_BYTES) { 1424 unit = SCALED_UNIT_BYTES; 1425 scale = scale_binary; 1426 1427 } else if (global_flags & RCTL_GLOBAL_SECONDS) { 1428 unit = SCALED_UNIT_SECONDS; 1429 scale = scale_metric; 1430 1431 } else { 1432 unit = SCALED_UNIT_NONE; 1433 scale = scale_metric; 1434 } 1435 /* iterate over an print all control values */ 1436 while (iter_val != NULL) { 1437 1438 /* print name or empty name field */ 1439 if (!arg_parseable_mode) 1440 (void) fprintf(stdout, "%8s", ""); 1441 else 1442 (void) fprintf(stdout, "%s ", iter_list->name); 1443 1444 1445 rblk_priv = rctlblk_get_privilege(iter_val->rblk); 1446 if (!arg_parseable_mode) 1447 print_priv(rblk_priv, "%-16s"); 1448 else 1449 print_priv(rblk_priv, "%s "); 1450 1451 rblk_value = rctlblk_get_value(iter_val->rblk); 1452 if (arg_parseable_mode) { 1453 (void) fprintf(stdout, "%llu ", rblk_value); 1454 1455 } else { 1456 1457 (void) uint64toscaled(rblk_value, 4, "E", 1458 rctl_valuestring, NULL, NULL, 1459 scale, NULL, 0); 1460 1461 (void) fprintf(stdout, "%5s", 1462 rctl_valuestring); 1463 (void) fprintf(stdout, "%-4s", unit); 1464 } 1465 local_flags = rctlblk_get_local_flags(iter_val->rblk); 1466 1467 if (local_flags & RCTL_LOCAL_MAXIMAL) { 1468 1469 if (global_flags & RCTL_GLOBAL_INFINITE) { 1470 string = "inf"; 1471 } else { 1472 string = "max"; 1473 } 1474 } else { 1475 string = "-"; 1476 } 1477 if (arg_parseable_mode) 1478 (void) fprintf(stdout, "%s ", string); 1479 else 1480 (void) fprintf(stdout, "%4s%3s", 1481 string, ""); 1482 1483 1484 local_action = rctlblk_get_local_action(iter_val->rblk, 1485 &signal); 1486 1487 if (arg_parseable_mode) 1488 print_local_action(local_action, &signal, 1489 "%s "); 1490 else 1491 print_local_action(local_action, &signal, 1492 "%-28s"); 1493 1494 pid = rctlblk_get_recipient_pid(iter_val->rblk); 1495 1496 if (arg_parseable_mode) { 1497 if (pid < 0) { 1498 (void) fprintf(stdout, "%s\n", "-"); 1499 } else { 1500 (void) fprintf(stdout, "%d\n", 1501 (int)pid); 1502 } 1503 } else { 1504 if (pid < 0) { 1505 (void) fprintf(stdout, "%10s\n", "-"); 1506 } else { 1507 (void) fprintf(stdout, "%10d\n", 1508 (int)pid); 1509 } 1510 } 1511 iter_val = iter_val->next; 1512 } 1513 iter_list = iter_list->next; 1514 } 1515 } 1516 1517 /* 1518 * 1519 * match_rctl 1520 * 1521 * find the first rctl with matching name, value, priv, and recipient pid 1522 */ 1523 int 1524 match_rctl(struct ps_prochandle *Pr, rctlblk_t **rctl, char *name, 1525 char *valuestringin, int valuein, rctl_priv_t privin, int pidin) 1526 { 1527 rctlblk_t *next; 1528 rctlblk_t *last; 1529 rctlblk_t *tmp; 1530 1531 *rctl = NULL; 1532 1533 next = calloc(1, rctlblk_size()); 1534 last = calloc(1, rctlblk_size()); 1535 1536 if ((last == NULL) || (next == NULL)) { 1537 preserve_error(gettext("malloc failed"), strerror(errno)); 1538 return (-1); 1539 } 1540 /* 1541 * For this resource name, now iterate through all 1542 * the controls, looking for a match to the 1543 * user-specified input. 1544 */ 1545 if (pr_getrctl(Pr, name, NULL, next, RCTL_FIRST)) { 1546 preserve_error(gettext("failed to get resource control " 1547 "for %s: %s"), name, strerror(errno)); 1548 return (-1); 1549 } 1550 if (match_rctl_blk(next, valuestringin, valuein, privin, pidin) == 1) { 1551 free(last); 1552 *rctl = next; 1553 return (0); 1554 } 1555 tmp = next; 1556 next = last; 1557 last = tmp; 1558 1559 while (pr_getrctl(Pr, name, last, next, RCTL_NEXT) == 0) { 1560 1561 /* allow user interrupt */ 1562 if (interrupt) 1563 break; 1564 1565 if (match_rctl_blk(next, valuestringin, valuein, privin, pidin) 1566 == 1) { 1567 free(last); 1568 *rctl = next; 1569 return (0); 1570 } 1571 tmp = next; 1572 next = last; 1573 last = tmp; 1574 } 1575 free(next); 1576 free(last); 1577 1578 return (1); 1579 } 1580 1581 /* 1582 * int match_rctl_blk(rctlblk_t *, char *, uint64, rctl_priv_t, int pid) 1583 * 1584 * Input 1585 * Must supply a valid rctl, value, privilege, and pid to match on. 1586 * If valuestring is NULL, then valuestring and valuein will not be used 1587 * If privilege type is 0 it will not be used. 1588 * If pid is -1 it will not be used. 1589 * 1590 * Return values 1591 * Returns 1 if a matching rctl given matches the parameters specified, and 1592 * 0 if they do not. 1593 * 1594 * This function is Pgrab-safe. 1595 */ 1596 int 1597 match_rctl_blk(rctlblk_t *rctl, char *valuestringin, 1598 uint64_t valuein, rctl_priv_t privin, int pidin) 1599 { 1600 1601 rctl_qty_t value; 1602 rctl_priv_t priv; 1603 pid_t pid; 1604 int valuematch = 1; 1605 int privmatch = 1; 1606 int pidmatch = 1; 1607 1608 value = rctlblk_get_value(rctl); 1609 priv = rctlblk_get_privilege(rctl); 1610 pid = rctlblk_get_recipient_pid(rctl); 1611 1612 if (valuestringin) { 1613 1614 if (arg_modifier == NULL) { 1615 valuematch = (valuein == value); 1616 } else { 1617 valuematch = scaledequint64(valuestringin, value, 1618 PRCTL_VALUE_WIDTH, 1619 arg_scale, arg_unit, 1620 SCALED_ALL_FLAGS); 1621 } 1622 } 1623 if (privin != 0) { 1624 privmatch = (privin == priv); 1625 } 1626 if (pidin != -1) { 1627 pidmatch = (pidin == pid); 1628 } 1629 return (valuematch && privmatch && pidmatch); 1630 } 1631 1632 static int 1633 change_action(rctlblk_t *blk) 1634 { 1635 int signal = 0; 1636 int action; 1637 1638 action = rctlblk_get_local_action(blk, &signal); 1639 1640 if (arg_operation & ACTION_ENABLE) { 1641 1642 if (arg_action & RCTL_LOCAL_SIGNAL) { 1643 signal = arg_signal; 1644 } 1645 action = action | arg_action; 1646 /* add local action */ 1647 rctlblk_set_local_action(blk, action, signal); 1648 1649 } else if (arg_operation & ACTION_DISABLE) { 1650 1651 /* 1652 * if deleting signal and signal number is specified, 1653 * then signal number must match 1654 */ 1655 if ((arg_action & RCTL_LOCAL_SIGNAL) && 1656 (arg_signal != -1)) { 1657 if (arg_signal != signal) { 1658 preserve_error(gettext("signal name or number " 1659 "does not match existing action")); 1660 return (-1); 1661 } 1662 } 1663 /* remove local action */ 1664 action = action & (~arg_action); 1665 rctlblk_set_local_action(blk, RCTL_LOCAL_NOACTION, 0); 1666 rctlblk_set_local_action(blk, action, signal); 1667 } 1668 /* enable deny if it must be enabled */ 1669 if (arg_global_flags & RCTL_GLOBAL_DENY_ALWAYS) { 1670 rctlblk_set_local_action(blk, RCTL_LOCAL_DENY | action, 1671 signal); 1672 } 1673 return (0); 1674 } 1675 1676 /* 1677 * prctl_setrctl 1678 * 1679 * Input 1680 * This function expects that input has been validated. In the 1681 * case of a replace operation, both old_rblk and new_rblk must 1682 * be valid resource controls. If a resource control is being 1683 * created, only new_rblk must be supplied. If a resource control 1684 * is being deleted, only new_rblk must be supplied. 1685 * 1686 * If the privilege is a priviliged type, at this time, the process 1687 * tries to take on superuser privileges. 1688 */ 1689 int 1690 prctl_setrctl(struct ps_prochandle *Pr, const char *name, 1691 rctlblk_t *old_rblk, rctlblk_t *new_rblk, uint_t flags) 1692 { 1693 int ret = 0; 1694 rctl_priv_t rblk_priv; 1695 psinfo_t psinfo; 1696 zoneid_t oldzoneid = GLOBAL_ZONEID; 1697 prpriv_t *old_prpriv = NULL, *new_prpriv = NULL; 1698 priv_set_t *eset, *pset; 1699 boolean_t relinquish_failed = B_FALSE; 1700 1701 rblk_priv = rctlblk_get_privilege(new_rblk); 1702 1703 if (rblk_priv == RCPRIV_SYSTEM) { 1704 preserve_error(gettext("cannot modify system values")); 1705 return (1); 1706 } 1707 if (rblk_priv == RCPRIV_PRIVILEGED) { 1708 new_prpriv = proc_get_priv(Pstatus(Pr)->pr_pid); 1709 if (new_prpriv == NULL) { 1710 preserve_error(gettext("cannot get process privileges " 1711 "for pid %d: %s"), Pstatus(Pr)->pr_pid, 1712 strerror(errno)); 1713 return (1); 1714 } 1715 /* 1716 * We only have to change the process privileges if it doesn't 1717 * already have PRIV_SYS_RESOURCE. In addition, we want to make 1718 * sure that we don't leave a process with elevated privileges, 1719 * so we make sure the process dies if we exit unexpectedly. 1720 */ 1721 eset = (priv_set_t *) 1722 &new_prpriv->pr_sets[new_prpriv->pr_setsize * 1723 priv_getsetbyname(PRIV_EFFECTIVE)]; 1724 pset = (priv_set_t *) 1725 &new_prpriv->pr_sets[new_prpriv->pr_setsize * 1726 priv_getsetbyname(PRIV_PERMITTED)]; 1727 if (!priv_ismember(eset, PRIV_SYS_RESOURCE)) { 1728 /* Keep track of original privileges */ 1729 old_prpriv = proc_get_priv(Pstatus(Pr)->pr_pid); 1730 if (old_prpriv == NULL) { 1731 preserve_error(gettext("cannot get process " 1732 "privileges for pid %d: %s"), 1733 Pstatus(Pr)->pr_pid, strerror(errno)); 1734 free(new_prpriv); 1735 return (1); 1736 } 1737 (void) priv_addset(eset, PRIV_SYS_RESOURCE); 1738 (void) priv_addset(pset, PRIV_SYS_RESOURCE); 1739 if (Psetflags(Pr, PR_KLC) != 0 || 1740 Psetpriv(Pr, new_prpriv) != 0) { 1741 preserve_error(gettext("cannot set process " 1742 "privileges for pid %d: %s"), 1743 Pstatus(Pr)->pr_pid, strerror(errno)); 1744 (void) Punsetflags(Pr, PR_KLC); 1745 free(new_prpriv); 1746 free(old_prpriv); 1747 return (1); 1748 } 1749 } 1750 /* 1751 * If this is a zone.* rctl, it requires more than 1752 * PRIV_SYS_RESOURCE: it wants the process to have global-zone 1753 * credentials. We temporarily grant non-global zone processes 1754 * these credentials, and make sure the process dies if we exit 1755 * unexpectedly. 1756 */ 1757 if (arg_name && 1758 arg_name_entity == RCENTITY_ZONE && 1759 getzoneid() == GLOBAL_ZONEID && 1760 proc_get_psinfo(Pstatus(Pr)->pr_pid, &psinfo) == 0 && 1761 (oldzoneid = psinfo.pr_zoneid) != GLOBAL_ZONEID) { 1762 /* 1763 * We need to give this process superuser 1764 * ("super-zone") privileges. 1765 * 1766 * Must never return without setting this back! 1767 */ 1768 if (Psetflags(Pr, PR_KLC) != 0 || 1769 Psetzoneid(Pr, GLOBAL_ZONEID) < 0) { 1770 preserve_error(gettext( 1771 "cannot set global-zone " 1772 "privileges for pid %d: %s"), 1773 Pstatus(Pr)->pr_pid, strerror(errno)); 1774 /* 1775 * We couldn't set the zoneid to begin with, so 1776 * there's no point in warning the user about 1777 * trying to un-set it. 1778 */ 1779 oldzoneid = GLOBAL_ZONEID; 1780 ret = 1; 1781 goto bail; 1782 } 1783 } 1784 } 1785 /* Now, actually populate the rctlblk in the kernel */ 1786 if (flags == RCTL_REPLACE) { 1787 /* 1788 * Replace should be a delete followed by an insert. This 1789 * allows us to replace rctl value blocks which match in 1790 * privilege and value, but have updated actions, etc. 1791 * setrctl() doesn't allow a direct replace, but we 1792 * should do the right thing for the user in the command. 1793 */ 1794 if (pr_setrctl(Pr, name, NULL, 1795 old_rblk, RCTL_DELETE)) { 1796 preserve_error(gettext("failed to delete resource " 1797 "control %s for pid %d: %s"), name, 1798 Pstatus(Pr)->pr_pid, strerror(errno)); 1799 ret = 1; 1800 goto bail; 1801 } 1802 if (pr_setrctl(Pr, name, NULL, 1803 new_rblk, RCTL_INSERT)) { 1804 preserve_error(gettext("failed to insert resource " 1805 "control %s for pid %d: %s"), name, 1806 Pstatus(Pr)->pr_pid, strerror(errno)); 1807 ret = 1; 1808 goto bail; 1809 } 1810 } else if (flags == RCTL_INSERT) { 1811 if (pr_setrctl(Pr, name, NULL, 1812 new_rblk, RCTL_INSERT)) { 1813 preserve_error(gettext("failed to create resource " 1814 "control %s for pid %d: %s"), name, 1815 Pstatus(Pr)->pr_pid, strerror(errno)); 1816 ret = 1; 1817 goto bail; 1818 } 1819 } else if (flags == RCTL_DELETE) { 1820 if (pr_setrctl(Pr, name, NULL, 1821 new_rblk, RCTL_DELETE)) { 1822 preserve_error(gettext("failed to delete resource " 1823 "control %s for pid %d: %s"), name, 1824 Pstatus(Pr)->pr_pid, strerror(errno)); 1825 ret = 1; 1826 goto bail; 1827 } 1828 } 1829 bail: 1830 if (oldzoneid != GLOBAL_ZONEID) { 1831 if (Psetzoneid(Pr, oldzoneid) != 0) 1832 relinquish_failed = B_TRUE; 1833 } 1834 if (old_prpriv != NULL) { 1835 if (Psetpriv(Pr, old_prpriv) != 0) 1836 relinquish_failed = B_TRUE; 1837 free(old_prpriv); 1838 } 1839 if (relinquish_failed) { 1840 /* 1841 * If this failed, we can't leave a process hanging 1842 * around with elevated privileges, so we'll have to 1843 * release the process from libproc, knowing that it 1844 * will be killed (since we set PR_KLC). 1845 */ 1846 Pdestroy_agent(Pr); 1847 preserve_error(gettext("cannot relinquish privileges " 1848 "for pid %d. The process was killed."), 1849 Pstatus(Pr)->pr_pid); 1850 } else { 1851 if (Punsetflags(Pr, PR_KLC) != 0) 1852 preserve_error(gettext("cannot relinquish privileges " 1853 "for pid %d. The process was killed."), 1854 Pstatus(Pr)->pr_pid); 1855 } 1856 if (new_prpriv != NULL) 1857 free(new_prpriv); 1858 1859 return (ret); 1860 } 1861 1862 void 1863 print_priv(rctl_priv_t local_priv, char *format) 1864 { 1865 char pstring[11]; 1866 1867 switch (local_priv) { 1868 case RCPRIV_BASIC: 1869 (void) strcpy(pstring, "basic"); 1870 break; 1871 case RCPRIV_PRIVILEGED: 1872 (void) strcpy(pstring, "privileged"); 1873 break; 1874 case RCPRIV_SYSTEM: 1875 (void) strcpy(pstring, "system"); 1876 break; 1877 default: 1878 (void) sprintf(pstring, "%d", local_priv); 1879 break; 1880 } 1881 /* LINTED */ 1882 (void) fprintf(stdout, format, pstring); 1883 } 1884 1885 void 1886 print_local_action(int action, int *signalp, char *format) 1887 { 1888 char sig[SIG2STR_MAX]; 1889 char sigstring[SIG2STR_MAX + 7]; 1890 char astring[5 + SIG2STR_MAX + 7]; 1891 int set = 0; 1892 1893 astring[0] = '\0'; 1894 1895 if (action == RCTL_LOCAL_NOACTION) { 1896 (void) strcat(astring, "none"); 1897 set++; 1898 } 1899 if (action & RCTL_LOCAL_DENY) { 1900 (void) strcat(astring, "deny"); 1901 set++; 1902 } 1903 if ((action & RCTL_LOCAL_DENY) && 1904 (action & RCTL_LOCAL_SIGNAL)) { 1905 (void) strcat(astring, ","); 1906 } 1907 if (action & RCTL_LOCAL_SIGNAL) { 1908 if (sig2str(*signalp, sig)) 1909 (void) snprintf(sigstring, sizeof (astring), 1910 "signal=%d", *signalp); 1911 else 1912 (void) snprintf(sigstring, sizeof (astring), 1913 "signal=%s", sig); 1914 1915 (void) strcat(astring, sigstring); 1916 set++; 1917 } 1918 if (set) 1919 /* LINTED */ 1920 (void) fprintf(stdout, format, astring); 1921 else 1922 /* LINTED */ 1923 (void) fprintf(stdout, format, action); 1924 } 1925 1926 /* 1927 * This function is used to grab the process matching the recipient pid 1928 */ 1929 pid_t 1930 regrab_process(pid_t pid, pr_info_handle_t *p, int priv, int *gret) 1931 { 1932 1933 char pidstring[24]; 1934 1935 gret = 0; 1936 if (pid == -1) 1937 return (p->pid); 1938 if (p->pid == pid) 1939 return (p->pid); 1940 1941 release_process(p->pr); 1942 (void) memset(p, 0, sizeof (*p)); 1943 1944 (void) snprintf(pidstring, 24, "%d", pid); 1945 return (grab_process_by_id( 1946 pidstring, RCENTITY_PROCESS, p, priv, gret)); 1947 } 1948 1949 /* 1950 * int grab_process_by_id(char *, rctl_entity_t, pr_info_handle_t *, int, int *) 1951 * 1952 * Input 1953 * Supply a non-NULL string containing: 1954 * - logical project/zone name or project/zone number if type is 1955 * RCENTITY_PROJECT or RCENTITY_ZONE 1956 * - task number if type is RCENTITY_TYPE 1957 * - a pid if type is RCENTITY_PID 1958 * Also supply an un-allocated prochandle, and an allocated info_handle. 1959 * This function assumes that the type is set. 1960 * If priv is not RCPRIV_BASIC, the grabbed process is required to have 1961 * PRIV_SYS_RESOURCE in it's limit set. 1962 * 1963 * Return Values 1964 * Returns 0 on success and 1 on failure. If there is a process 1965 * running under the specified id, success is returned, and 1966 * Pr is pointed to the process. Success will be returned and Pr 1967 * set to NULL if the matching process is our own. 1968 * If success is returned, psinfo will be valid, and pid will 1969 * be the process number. The process will also be held at the 1970 * end, so release_process should be used by the caller. 1971 * 1972 * This function assumes that signals are caught already so that libproc 1973 * can be safely used. 1974 * 1975 * Return Values 1976 * pid - Process found and grabbed 1977 * -1 - Error 1978 */ 1979 pid_t 1980 grab_process_by_id(char *idname, rctl_entity_t type, pr_info_handle_t *p, 1981 int priv, int *gret) 1982 { 1983 char prbuf[PROJECT_BUFSZ]; 1984 projid_t projid; 1985 taskid_t taskid; 1986 zoneid_t zoneid; 1987 zoneid_t zone_self; 1988 struct project proj; 1989 DIR *dirp; 1990 struct dirent *dentp; 1991 int found = 0; 1992 int pid_self; 1993 int ret; 1994 int gret_in; 1995 int intidname; 1996 char *end; 1997 prpriv_t *prpriv; 1998 priv_set_t *prset; 1999 2000 gret_in = *gret; 2001 2002 /* get our pid se we do not try to operate on self */ 2003 pid_self = getpid(); 2004 2005 /* Store integer version of id */ 2006 intidname = strtoul(idname, &end, 10); 2007 if (errno || *end != '\0' || end == idname) { 2008 intidname = -1; 2009 } 2010 2011 /* 2012 * get our zoneid so we don't try to operate on a project in 2013 * another zone 2014 */ 2015 zone_self = getzoneid(); 2016 2017 if (idname == NULL || strcmp(idname, "") == 0) { 2018 warn(gettext("id name cannot be nuint64\n")); 2019 return (-1); 2020 } 2021 /* 2022 * Set up zoneid, projid or taskid, as appropriate, so that comparisons 2023 * can be done later with the input. 2024 */ 2025 if (type == RCENTITY_ZONE) { 2026 if (zone_get_id(idname, &zoneid) != 0) { 2027 warn(gettext("%s: unknown zone\n"), idname); 2028 return (-1); 2029 } 2030 } else if (type == RCENTITY_PROJECT) { 2031 if (getprojbyname(idname, &proj, prbuf, PROJECT_BUFSZ) 2032 == NULL) { 2033 if (getprojbyid(intidname, &proj, prbuf, 2034 PROJECT_BUFSZ) == NULL) { 2035 warn(gettext("%s: cannot find project\n"), 2036 idname); 2037 return (-1); 2038 } 2039 } 2040 projid = proj.pj_projid; 2041 } else if (type == RCENTITY_TASK) { 2042 taskid = (taskid_t)atol(idname); 2043 } 2044 /* 2045 * Projects and tasks need to search through /proc for 2046 * a parent process. 2047 */ 2048 if (type == RCENTITY_ZONE || type == RCENTITY_PROJECT || 2049 type == RCENTITY_TASK) { 2050 if ((dirp = opendir("/proc")) == NULL) { 2051 warn(gettext("%s: cannot open /proc directory\n"), 2052 idname); 2053 return (-1); 2054 } 2055 /* 2056 * Look through all processes in /proc. For each process, 2057 * check if the pr_projid in their psinfo matches the 2058 * specified id. 2059 */ 2060 while (dentp = readdir(dirp)) { 2061 p->pid = atoi(dentp->d_name); 2062 2063 /* Skip self */ 2064 if (p->pid == pid_self) 2065 continue; 2066 2067 if (proc_get_psinfo(p->pid, &(p->psinfo)) != 0) 2068 continue; 2069 2070 /* Skip process if it is not what we are looking for */ 2071 if (type == RCENTITY_ZONE && 2072 (p->psinfo).pr_zoneid != zoneid) { 2073 continue; 2074 } else if (type == RCENTITY_PROJECT && 2075 ((p->psinfo).pr_projid != projid || 2076 (p->psinfo).pr_zoneid != zone_self)) { 2077 continue; 2078 } else if (type == RCENTITY_TASK && 2079 (p->psinfo).pr_taskid != taskid) { 2080 continue; 2081 } 2082 /* attempt to grab process */ 2083 if (grab_process(p, gret) != 0) 2084 continue; 2085 2086 /* 2087 * Re-confirm that this process is still running as 2088 * part of the specified project or task. If it 2089 * doesn't match, release the process and return an 2090 * error. This should only be done if the Pr struct is 2091 * not NULL. 2092 */ 2093 if (type == RCENTITY_PROJECT) { 2094 if (pr_getprojid(p->pr) != projid || 2095 pr_getzoneid(p->pr) != zone_self) { 2096 release_process(p->pr); 2097 continue; 2098 } 2099 } else if (type == RCENTITY_TASK) { 2100 if (pr_gettaskid(p->pr) != taskid) { 2101 release_process(p->pr); 2102 continue; 2103 } 2104 } else if (type == RCENTITY_ZONE) { 2105 if (pr_getzoneid(p->pr) != zoneid) { 2106 release_process(p->pr); 2107 continue; 2108 } 2109 } 2110 2111 /* 2112 * If we are setting a privileged resource control, 2113 * verify that process has PRIV_SYS_RESOURCE in it's 2114 * limit set. If it does not, then we will not be 2115 * able to give this process the privilege it needs 2116 * to set the resource control. 2117 */ 2118 if (priv != RCPRIV_BASIC) { 2119 prpriv = proc_get_priv(p->pid); 2120 if (prpriv == NULL) { 2121 release_process(p->pr); 2122 continue; 2123 } 2124 prset = (priv_set_t *) 2125 &prpriv->pr_sets[prpriv->pr_setsize * 2126 priv_getsetbyname(PRIV_LIMIT)]; 2127 if (!priv_ismember(prset, PRIV_SYS_RESOURCE)) { 2128 release_process(p->pr); 2129 continue; 2130 } 2131 } 2132 found = 1; 2133 2134 p->taskid = pr_gettaskid(p->pr); 2135 p->projid = pr_getprojid(p->pr); 2136 p->zoneid = pr_getzoneid(p->pr); 2137 2138 break; 2139 } 2140 (void) closedir(dirp); 2141 2142 if (found == 0) { 2143 warn(gettext("%s: No controllable process found in " 2144 "task, project, or zone.\n"), idname); 2145 return (-1); 2146 } 2147 return (p->pid); 2148 2149 } else if (type == RCENTITY_PROCESS) { 2150 2151 /* fail if self */ 2152 if (p->pid == pid_self) { 2153 2154 warn(gettext("%s: cannot control self"), idname); 2155 return (-1); 2156 } 2157 /* 2158 * Process types need to be set up with the correct pid 2159 * and psinfo structure. 2160 */ 2161 if ((p->pid = proc_arg_psinfo(idname, PR_ARG_PIDS, 2162 &(p->psinfo), gret)) == -1) { 2163 warn(gettext("%s: cannot examine: %s"), idname, 2164 Pgrab_error(*gret)); 2165 return (-1); 2166 } 2167 /* grab process */ 2168 ret = grab_process(p, gret); 2169 if (ret == 1) { 2170 /* Don't print error if G_SYS is allowed */ 2171 if (gret_in == G_SYS && *gret == G_SYS) { 2172 return (-1); 2173 } else { 2174 warn(gettext("%s: cannot control: %s"), idname, 2175 Pgrab_error(*gret)); 2176 return (-1); 2177 } 2178 } else if (ret == 2) { 2179 ret = errno; 2180 warn(gettext("%s: cannot control: %s"), idname, 2181 strerror(ret)); 2182 return (-1); 2183 } 2184 p->taskid = pr_gettaskid(p->pr); 2185 p->projid = pr_getprojid(p->pr); 2186 p->zoneid = pr_getzoneid(p->pr); 2187 2188 return (p->pid); 2189 2190 } else { 2191 warn(gettext("%s: unknown resource entity type %d\n"), idname, 2192 type); 2193 return (-1); 2194 } 2195 } 2196 2197 /* 2198 * Do the work required to manipulate a process through libproc. 2199 * If grab_process() returns no errors (0), then release_process() 2200 * must eventually be called. 2201 * 2202 * Return values: 2203 * 0 Successful creation of agent thread 2204 * 1 Error grabbing 2205 * 2 Error creating agent 2206 */ 2207 int 2208 grab_process(pr_info_handle_t *p, int *gret) 2209 { 2210 2211 if ((p->pr = Pgrab(p->pid, arg_force, gret)) != NULL) { 2212 2213 if (Psetflags(p->pr, PR_RLC) != 0) { 2214 Prelease(p->pr, 0); 2215 return (1); 2216 } 2217 if (Pcreate_agent(p->pr) == 0) { 2218 return (0); 2219 2220 } else { 2221 Prelease(p->pr, 0); 2222 return (2); 2223 } 2224 } else { 2225 return (1); 2226 } 2227 } 2228 2229 /* 2230 * Release the specified process. This destroys the agent 2231 * and releases the process. If the process is NULL, nothing 2232 * is done. This function should only be called if grab_process() 2233 * has previously been called and returned success. 2234 * 2235 * This function is Pgrab-safe. 2236 */ 2237 void 2238 release_process(struct ps_prochandle *Pr) 2239 { 2240 if (Pr == NULL) 2241 return; 2242 2243 Pdestroy_agent(Pr); 2244 Prelease(Pr, 0); 2245 } 2246 2247 /* 2248 * preserve_error(char *, ...) 2249 * 2250 * preserve_error() should be called rather than warn() by any 2251 * function that is called while the victim process is held by Pgrab. 2252 * It will save the error until the process has been un-controlled 2253 * and output is reasonable again. 2254 * 2255 * Note that multiple errors are not stored. Any error in these 2256 * sections should be critical and return immediately. 2257 * 2258 * This function is Pgrab-safe. 2259 * 2260 * Since this function may copy untrusted command line arguments to 2261 * global_error, security practices require that global_error never be 2262 * printed directly. Use printf("%s\n", global_error) or equivalent. 2263 */ 2264 /*PRINTFLIKE1*/ 2265 void 2266 preserve_error(char *format, ...) 2267 { 2268 va_list alist; 2269 2270 va_start(alist, format); 2271 2272 /* 2273 * GLOBAL_ERR_SZ is pretty big. If the error is longer 2274 * than that, just truncate it, rather than chance missing 2275 * the error altogether. 2276 */ 2277 (void) vsnprintf(global_error, GLOBAL_ERR_SZ-1, format, alist); 2278 2279 va_end(alist); 2280 } 2281