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 }