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 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 30 /* All Rights Reserved */ 31 32 33 #include <stdio.h> 34 #include <string.h> 35 #include <strings.h> 36 #include <stdlib.h> 37 #include <unistd.h> 38 #include <sys/types.h> 39 #include <limits.h> 40 #include <dirent.h> 41 #include <fcntl.h> 42 #include <sys/time.h> 43 #include <sys/procset.h> 44 #include <sys/priocntl.h> 45 #include <sys/task.h> 46 #include <procfs.h> 47 #include <project.h> 48 #include <errno.h> 49 #include <zone.h> 50 #include <libcontract_priv.h> 51 52 #include "priocntl.h" 53 54 /*LINTLIBRARY*/ 55 56 /* 57 * Utility functions for priocntl command. 58 */ 59 60 static char *procdir = "/proc"; 61 62 /*PRINTFLIKE1*/ 63 void 64 fatalerr(format, a1, a2, a3, a4, a5) 65 char *format; 66 int a1, a2, a3, a4, a5; 67 { 68 (void) fprintf(stderr, format, a1, a2, a3, a4, a5); 69 exit(1); 70 } 71 72 73 /* 74 * Structure defining idtypes known to the priocntl command 75 * along with the corresponding names and a liberal guess 76 * of the max number of procs sharing any given ID of that type. 77 * The idtype values themselves are defined in <sys/procset.h>. 78 */ 79 static struct idtypes { 80 idtype_t idtype; 81 char *idtypnm; 82 } idtypes [] = { 83 { P_PID, "pid" }, 84 { P_PPID, "ppid" }, 85 { P_PGID, "pgid" }, 86 { P_SID, "sid" }, 87 { P_CID, "class" }, 88 { P_UID, "uid" }, 89 { P_GID, "gid" }, 90 { P_PROJID, "projid" }, 91 { P_TASKID, "taskid" }, 92 { P_ZONEID, "zoneid" }, 93 { P_CTID, "ctid" }, 94 { P_ALL, "all" } 95 }; 96 97 #define IDCNT (sizeof (idtypes) / sizeof (struct idtypes)) 98 99 100 int 101 str2idtyp(idtypnm, idtypep) 102 char *idtypnm; 103 idtype_t *idtypep; 104 { 105 register struct idtypes *curp; 106 register struct idtypes *endp; 107 108 for (curp = idtypes, endp = &idtypes[IDCNT]; curp < endp; curp++) { 109 if (strcmp(curp->idtypnm, idtypnm) == 0) { 110 *idtypep = curp->idtype; 111 return (0); 112 } 113 } 114 return (-1); 115 } 116 117 118 int 119 idtyp2str(idtype, idtypnm) 120 idtype_t idtype; 121 char *idtypnm; 122 { 123 register struct idtypes *curp; 124 register struct idtypes *endp; 125 126 for (curp = idtypes, endp = &idtypes[IDCNT]; curp < endp; curp++) { 127 if (idtype == curp->idtype) { 128 (void) strncpy(idtypnm, curp->idtypnm, PC_IDTYPNMSZ); 129 return (0); 130 } 131 } 132 return (-1); 133 } 134 135 136 /* 137 * Compare two IDs for equality. 138 */ 139 int 140 idcompar(id1p, id2p) 141 id_t *id1p; 142 id_t *id2p; 143 { 144 if (*id1p == *id2p) 145 return (0); 146 else 147 return (-1); 148 } 149 150 151 id_t 152 clname2cid(clname) 153 char *clname; 154 { 155 pcinfo_t pcinfo; 156 157 (void) strncpy(pcinfo.pc_clname, clname, PC_CLNMSZ); 158 if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) 159 return ((id_t)-1); 160 return (pcinfo.pc_cid); 161 } 162 163 164 int 165 getmyid(idtype, idptr) 166 idtype_t idtype; 167 id_t *idptr; 168 { 169 pcinfo_t pcinfo; 170 171 switch (idtype) { 172 173 case P_PID: 174 *idptr = (id_t)getpid(); 175 break; 176 177 case P_PPID: 178 *idptr = (id_t)getppid(); 179 break; 180 181 case P_PGID: 182 *idptr = (id_t)getpgrp(); 183 break; 184 185 case P_SID: 186 *idptr = (id_t)getsid(getpid()); 187 break; 188 189 case P_CID: 190 if (priocntl(P_PID, P_MYID, PC_GETXPARMS, NULL, 191 PC_KY_CLNAME, pcinfo.pc_clname, 0) == -1 || 192 priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) 193 return (-1); 194 195 *idptr = pcinfo.pc_cid; 196 break; 197 198 case P_UID: 199 *idptr = (id_t)getuid(); 200 break; 201 202 case P_GID: 203 *idptr = (id_t)getgid(); 204 break; 205 206 case P_PROJID: 207 *idptr = (id_t)getprojid(); 208 break; 209 210 case P_TASKID: 211 *idptr = (id_t)gettaskid(); 212 break; 213 214 case P_ZONEID: 215 *idptr = (id_t)getzoneid(); 216 break; 217 218 case P_CTID: { 219 ctid_t id = getctid(); 220 if (id == -1) 221 return (-1); 222 *idptr = id; 223 break; 224 } 225 226 default: 227 return (-1); 228 } 229 return (0); 230 } 231 232 233 int 234 getmyidstr(idtype, idstr) 235 idtype_t idtype; 236 char *idstr; 237 { 238 char clname[PC_CLNMSZ]; 239 240 switch (idtype) { 241 242 case P_PID: 243 itoa((long)getpid(), idstr); 244 break; 245 246 case P_PPID: 247 itoa((long)getppid(), idstr); 248 break; 249 250 case P_PGID: 251 itoa((long)getpgrp(), idstr); 252 break; 253 case P_SID: 254 itoa((long)getsid(getpid()), idstr); 255 break; 256 257 case P_CID: 258 if (priocntl(P_PID, P_MYID, PC_GETXPARMS, NULL, 259 PC_KY_CLNAME, clname, 0) == -1) 260 return (-1); 261 (void) strncpy(idstr, clname, PC_CLNMSZ); 262 break; 263 264 case P_UID: 265 itoa((long)getuid(), idstr); 266 break; 267 268 case P_GID: 269 itoa((long)getgid(), idstr); 270 break; 271 272 case P_PROJID: 273 itoa((long)getprojid(), idstr); 274 break; 275 276 case P_TASKID: 277 itoa((long)gettaskid(), idstr); 278 break; 279 280 case P_ZONEID: 281 itoa((long)getzoneid(), idstr); 282 break; 283 284 case P_CTID: { 285 id_t id; 286 if ((id = getctid()) == -1) 287 return (-1); 288 itoa((long)id, idstr); 289 break; 290 } 291 292 default: 293 return (-1); 294 } 295 return (0); 296 } 297 298 /* 299 * Look for pids with "upri > uprilim" in the set specified by idtype/id. 300 * If upri exceeds uprilim then print a warning. 301 */ 302 int 303 verifyupri(idtype_t idtype, id_t id, char *clname, int key, 304 pri_t upri, char *basenm) 305 { 306 psinfo_t prinfo; 307 prcred_t prcred; 308 DIR *dirp; 309 struct dirent *dentp; 310 char pname[MAXNAMLEN]; 311 char *fname; 312 int procfd; 313 int saverr; 314 pri_t uprilim; 315 int verify; 316 int error = 0; 317 318 if (idtype == P_PID) { 319 if (priocntl(P_PID, id, PC_GETXPARMS, clname, key, 320 &uprilim, 0) == -1) 321 error = -1; 322 else if (upri > uprilim) 323 (void) fprintf(stderr, 324 "%s: Specified user priority %d exceeds" 325 " limit %d; set to %d (pid %d)\n", 326 basenm, upri, uprilim, uprilim, (int)id); 327 328 return (error); 329 } 330 331 /* 332 * Look for the processes in the set specified by idtype/id. 333 * We read the /proc/<pid>/psinfo file to get the necessary 334 * process information. 335 */ 336 337 if ((dirp = opendir(procdir)) == NULL) 338 fatalerr("%s: Can't open PROC directory %s\n", 339 basenm, procdir); 340 341 while ((dentp = readdir(dirp)) != NULL) { 342 if (dentp->d_name[0] == '.') /* skip . and .. */ 343 continue; 344 345 (void) snprintf(pname, MAXNAMLEN, "%s/%s/", 346 procdir, dentp->d_name); 347 fname = pname + strlen(pname); 348 retry: 349 (void) strncpy(fname, "psinfo", strlen("psinfo") + 1); 350 if ((procfd = open(pname, O_RDONLY)) < 0) 351 continue; 352 if (read(procfd, &prinfo, sizeof (prinfo)) != sizeof (prinfo)) { 353 saverr = errno; 354 (void) close(procfd); 355 if (saverr == EAGAIN) 356 goto retry; 357 continue; 358 } 359 (void) close(procfd); 360 361 if (idtype == P_UID || idtype == P_GID) { 362 (void) strncpy(fname, "cred", strlen("cred") + 1); 363 if ((procfd = open(pname, O_RDONLY)) < 0 || 364 read(procfd, &prcred, sizeof (prcred)) != 365 sizeof (prcred)) { 366 saverr = errno; 367 (void) close(procfd); 368 if (saverr == EAGAIN) 369 goto retry; 370 continue; 371 } 372 (void) close(procfd); 373 } 374 375 if (prinfo.pr_lwp.pr_state == 0 || prinfo.pr_nlwp == 0) 376 continue; 377 378 /* 379 * The lwp must be in the correct class. 380 */ 381 if (strncmp(clname, prinfo.pr_lwp.pr_clname, PC_CLNMSZ) != 0) 382 continue; 383 384 verify = 0; 385 switch (idtype) { 386 387 case P_PPID: 388 if (id == (id_t)prinfo.pr_ppid) 389 verify++; 390 break; 391 392 case P_PGID: 393 if (id == (id_t)prinfo.pr_pgid) 394 verify++; 395 break; 396 397 case P_SID: 398 if (id == (id_t)prinfo.pr_sid) 399 verify++; 400 break; 401 402 case P_UID: 403 if (id == (id_t)prcred.pr_euid) 404 verify++; 405 break; 406 407 case P_GID: 408 if (id == (id_t)prcred.pr_egid) 409 verify++; 410 break; 411 412 case P_PROJID: 413 if (id == (id_t)prinfo.pr_projid) 414 verify++; 415 break; 416 417 case P_TASKID: 418 if (id == (id_t)prinfo.pr_taskid) 419 verify++; 420 break; 421 422 case P_ZONEID: 423 if (id == (id_t)prinfo.pr_zoneid) 424 verify++; 425 break; 426 427 case P_CTID: 428 if (id == (id_t)prinfo.pr_contract) 429 verify++; 430 break; 431 432 case P_CID: 433 case P_ALL: 434 verify++; 435 break; 436 437 default: 438 fatalerr("%s: Bad idtype %d in verifyupri()\n", 439 basenm, idtype); 440 } 441 442 if (verify) { 443 if (priocntl(P_PID, prinfo.pr_pid, PC_GETXPARMS, 444 clname, key, &uprilim, 0) == -1) 445 error = -1; 446 else if (upri > uprilim) 447 (void) fprintf(stderr, 448 "%s: Specified user priority %d exceeds" 449 " limit %d; set to %d (pid %d)\n", 450 basenm, upri, uprilim, uprilim, 451 (int)prinfo.pr_pid); 452 } 453 } 454 (void) closedir(dirp); 455 456 return (error); 457 } 458 459 460 /* 461 * Read a list of pids from a stream. 462 */ 463 pid_t * 464 read_pidlist(size_t *npidsp, FILE *filep) 465 { 466 size_t nitems; 467 pid_t *pidlist = NULL; 468 469 *npidsp = 0; 470 471 do { 472 if ((pidlist = (pid_t *)realloc(pidlist, 473 (*npidsp + NPIDS) * sizeof (pid_t))) == NULL) 474 return (NULL); 475 476 nitems = fread(pidlist + *npidsp, sizeof (pid_t), NPIDS, filep); 477 if (ferror(filep)) 478 return (NULL); 479 480 *npidsp += nitems; 481 } while (nitems == NPIDS); 482 483 return (pidlist); 484 } 485 486 487 void 488 free_pidlist(pid_t *pidlist) 489 { 490 free(pidlist); 491 } 492 493 494 long 495 str2num(char *p, long min, long max) 496 { 497 long val; 498 char *q; 499 errno = 0; 500 501 val = strtol(p, &q, 10); 502 if (errno != 0 || q == p || *q != '\0' || val < min || val > max) 503 errno = EINVAL; 504 505 return (val); 506 } 507 508 509 /* 510 * itoa() and reverse() taken almost verbatim from K & R Chapter 3. 511 */ 512 static void reverse(); 513 514 /* 515 * itoa(): Convert n to characters in s. 516 */ 517 void 518 itoa(n, s) 519 long n; 520 char *s; 521 { 522 long i, sign; 523 524 if ((sign = n) < 0) /* record sign */ 525 n = -n; /* make sign positive */ 526 i = 0; 527 do { /* generate digits in reverse order */ 528 s[i++] = n % 10 + '0'; /* get next digit */ 529 } while ((n /= 10) > 0); /* delete it */ 530 if (sign < 0) 531 s[i++] = '-'; 532 s[i] = '\0'; 533 reverse(s); 534 } 535 536 537 /* 538 * reverse(): Reverse string s in place. 539 */ 540 static void 541 reverse(s) 542 char *s; 543 { 544 int c, i, j; 545 546 for (i = 0, j = strlen(s) - 1; i < j; i++, j--) { 547 c = s[i]; 548 s[i] = s[j]; 549 s[j] = (char)c; 550 } 551 } 552 553 554 /* 555 * The following routine was removed from libc (libc/port/gen/hrtnewres.c). 556 * It has also been added to disadmin, so if you fix it here, you should 557 * also probably fix it there. In the long term, this should be recoded to 558 * not be hrt'ish. 559 */ 560 561 /* 562 * Convert interval expressed in htp->hrt_res to new_res. 563 * 564 * Calculate: (interval * new_res) / htp->hrt_res rounding off as 565 * specified by round. 566 * 567 * Note: All args are assumed to be positive. If 568 * the last divide results in something bigger than 569 * a long, then -1 is returned instead. 570 */ 571 572 int 573 _hrtnewres(htp, new_res, round) 574 register hrtimer_t *htp; 575 register ulong_t new_res; 576 long round; 577 { 578 register long interval; 579 longlong_t dint; 580 longlong_t dto_res; 581 longlong_t drem; 582 longlong_t dfrom_res; 583 longlong_t prod; 584 longlong_t quot; 585 register long numerator; 586 register long result; 587 ulong_t modulus; 588 ulong_t twomodulus; 589 long temp; 590 591 if (new_res > NANOSEC || htp->hrt_rem < 0) 592 return (-1); 593 594 if (htp->hrt_rem >= htp->hrt_res) { 595 htp->hrt_secs += htp->hrt_rem / htp->hrt_res; 596 htp->hrt_rem = htp->hrt_rem % htp->hrt_res; 597 } 598 599 interval = htp->hrt_rem; 600 if (interval == 0) { 601 htp->hrt_res = new_res; 602 return (0); 603 } 604 605 /* 606 * Try to do the calculations in single precision first 607 * (for speed). If they overflow, use double precision. 608 * What we want to compute is: 609 * 610 * (interval * new_res) / hrt->hrt_res 611 */ 612 613 numerator = interval * new_res; 614 615 if (numerator / new_res == interval) { 616 617 /* 618 * The above multiply didn't give overflow since 619 * the division got back the original number. Go 620 * ahead and compute the result. 621 */ 622 623 result = numerator / htp->hrt_res; 624 625 /* 626 * For HRT_RND, compute the value of: 627 * 628 * (interval * new_res) % htp->hrt_res 629 * 630 * If it is greater than half of the htp->hrt_res, 631 * then rounding increases the result by 1. 632 * 633 * For HRT_RNDUP, we increase the result by 1 if: 634 * 635 * result * htp->hrt_res != numerator 636 * 637 * because this tells us we truncated when calculating 638 * result above. 639 * 640 * We also check for overflow when incrementing result 641 * although this is extremely rare. 642 */ 643 644 if (round == HRT_RND) { 645 modulus = numerator - result * htp->hrt_res; 646 if ((twomodulus = 2 * modulus) / 2 == modulus) { 647 648 /* 649 * No overflow (if we overflow in calculation 650 * of twomodulus we fall through and use 651 * double precision). 652 */ 653 if (twomodulus >= htp->hrt_res) { 654 temp = result + 1; 655 if (temp - 1 == result) 656 result++; 657 else 658 return (-1); 659 } 660 htp->hrt_res = new_res; 661 htp->hrt_rem = result; 662 return (0); 663 } 664 } else if (round == HRT_RNDUP) { 665 if (result * htp->hrt_res != numerator) { 666 temp = result + 1; 667 if (temp - 1 == result) 668 result++; 669 else 670 return (-1); 671 } 672 htp->hrt_res = new_res; 673 htp->hrt_rem = result; 674 return (0); 675 } else { /* round == HRT_TRUNC */ 676 htp->hrt_res = new_res; 677 htp->hrt_rem = result; 678 return (0); 679 } 680 } 681 682 /* 683 * We would get overflow doing the calculation is 684 * single precision so do it the slow but careful way. 685 * 686 * Compute the interval times the resolution we are 687 * going to. 688 */ 689 690 dint = interval; 691 dto_res = new_res; 692 prod = dint * dto_res; 693 694 /* 695 * For HRT_RND the result will be equal to: 696 * 697 * ((interval * new_res) + htp->hrt_res / 2) / htp->hrt_res 698 * 699 * and for HRT_RNDUP we use: 700 * 701 * ((interval * new_res) + htp->hrt_res - 1) / htp->hrt_res 702 * 703 * This is a different but equivalent way of rounding. 704 */ 705 706 if (round == HRT_RND) { 707 drem = htp->hrt_res / 2; 708 prod = prod + drem; 709 } else if (round == HRT_RNDUP) { 710 drem = htp->hrt_res - 1; 711 prod = prod + drem; 712 } 713 714 dfrom_res = htp->hrt_res; 715 quot = prod / dfrom_res; 716 717 /* 718 * If the quotient won't fit in a long, then we have 719 * overflow. Otherwise, return the result. 720 */ 721 722 if (quot > UINT_MAX) { 723 return (-1); 724 } else { 725 htp->hrt_res = new_res; 726 htp->hrt_rem = (int)quot; 727 return (0); 728 } 729 } 730