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