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