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