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 }