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 (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #pragma ident   "%Z%%M% %I%     %E% SMI"
  27 
  28 #include <errno.h>
  29 #include <strings.h>
  30 #include <sys/types.h>
  31 #include <sys/systm.h>
  32 #include <sys/resource.h>
  33 #include <sys/sysconfig.h>
  34 #include <sys/lx_types.h>
  35 #include <sys/lx_misc.h>
  36 
  37 #define LX_RLIMIT_RSS           5
  38 #define LX_RLIMIT_NPROC         6
  39 #define LX_RLIMIT_MEMLOCK       8
  40 #define LX_RLIMIT_LOCKS         10
  41 #define LX_RLIMIT_NLIMITS       11
  42 
  43 /*
  44  * Linux supports many of the same resources that we do, but the numbering
  45  * is slightly different.  This table is used to translate Linux resource
  46  * limit keys into their Solaris equivalents.
  47  */
  48 static int ltos_resource[LX_RLIMIT_NLIMITS] = {
  49         RLIMIT_CPU,
  50         RLIMIT_FSIZE,
  51         RLIMIT_DATA,
  52         RLIMIT_STACK,
  53         RLIMIT_CORE,
  54         -1,                     /* RSS */
  55         -1,                     /* NPROC */
  56         RLIMIT_NOFILE,
  57         -1,                     /* MEMLOCK */
  58         RLIMIT_AS,
  59         -1                      /* LOCKS */
  60 };
  61 
  62 #define NLIMITS (sizeof (ltos_resource) / sizeof (int))
  63 
  64 /*
  65  * Magic values Linux uses to indicate infinity
  66  */
  67 #define LX_RLIM_INFINITY_O      (0x7fffffffUL)
  68 #define LX_RLIM_INFINITY_N      (0xffffffffUL)
  69 
  70 /*
  71  * Array to store the rlimits that we track but do not enforce.
  72  */
  73 static struct rlimit fake_limits[NLIMITS] = {
  74         0, 0,
  75         0, 0,
  76         0, 0,
  77         0, 0,
  78         0, 0,
  79         RLIM_INFINITY, RLIM_INFINITY,   /* LX_RLIM_RSS */
  80         RLIM_INFINITY, RLIM_INFINITY,   /* LX_RLIM_NPROC */
  81         0, 0,
  82         RLIM_INFINITY, RLIM_INFINITY,   /* LX_RLIM_MEMLOCK */
  83         0, 0,
  84         RLIM_INFINITY, RLIM_INFINITY    /* LX_RLIM_LOCKS */
  85 };
  86 
  87 static int
  88 lx_getrlimit_common(int resource, struct rlimit *rlp, int inf)
  89 {
  90         int rv;
  91         int sresource;
  92         struct rlimit rl;
  93 
  94         if (resource < 0 || resource >= LX_RLIMIT_NLIMITS)
  95                 return (-EINVAL);
  96 
  97         sresource = ltos_resource[resource];
  98 
  99         if (sresource == -1) {
 100                 switch (resource) {
 101                 case LX_RLIMIT_MEMLOCK:
 102                 case LX_RLIMIT_RSS:
 103                 case LX_RLIMIT_LOCKS:
 104                 case LX_RLIMIT_NPROC:
 105                         rl.rlim_max = fake_limits[resource].rlim_max;
 106                         rl.rlim_cur = fake_limits[resource].rlim_cur;
 107                         if (rl.rlim_cur == RLIM_INFINITY)
 108                                 rl.rlim_cur = inf;
 109                         if (rl.rlim_max == RLIM_INFINITY)
 110                                 rl.rlim_max = inf;
 111                         if ((uucopy(&rl, rlp, sizeof (rl))) != 0)
 112                                 return (-errno);
 113                         return (0);
 114                 default:
 115                         lx_unsupported("Unsupported resource type %d\n",
 116                             resource);
 117                         return (-ENOTSUP);
 118                 }
 119         } else {
 120                 rv = getrlimit(sresource, rlp);
 121         }
 122 
 123         if (rv < 0)
 124                 return (-errno);
 125 
 126         if (rlp->rlim_cur == RLIM_INFINITY)
 127                 rlp->rlim_cur = inf;
 128 
 129         if (rlp->rlim_max == RLIM_INFINITY)
 130                 rlp->rlim_max = inf;
 131 
 132         return (0);
 133 }
 134 
 135 /*
 136  * This is the 'new' getrlimit, variously called getrlimit or ugetrlimit
 137  * in Linux headers and code.  The only difference between this and the old
 138  * getrlimit (variously called getrlimit or old_getrlimit) is the value of
 139  * RLIM_INFINITY, which is smaller for the older version.  Modern code will
 140  * use this version by default.
 141  */
 142 int
 143 lx_getrlimit(uintptr_t p1, uintptr_t p2)
 144 {
 145         int resource = (int)p1;
 146         struct rlimit *rlp = (struct rlimit *)p2;
 147 
 148         return (lx_getrlimit_common(resource, rlp, LX_RLIM_INFINITY_N));
 149 }
 150 
 151 /*
 152  * This is the 'old' getrlimit, variously called getrlimit or old_getrlimit
 153  * in Linux headers and code.  The only difference between this and the new
 154  * getrlimit (variously called getrlimit or ugetrlimit) is the value of
 155  * RLIM_INFINITY, which is smaller for the older version.
 156  */
 157 int
 158 lx_oldgetrlimit(uintptr_t p1, uintptr_t p2)
 159 {
 160         int resource = (int)p1;
 161         struct rlimit *rlp = (struct rlimit *)p2;
 162 
 163         return (lx_getrlimit_common(resource, rlp, LX_RLIM_INFINITY_O));
 164 }
 165 
 166 int
 167 lx_setrlimit(uintptr_t p1, uintptr_t p2)
 168 {
 169         int resource = (int)p1;
 170         struct rlimit *rlp = (struct rlimit *)p2;
 171         struct rlimit rl;
 172         int rv, sresource;
 173 
 174         if (resource < 0 || resource >= LX_RLIMIT_NLIMITS)
 175                 return (-EINVAL);
 176 
 177         sresource = ltos_resource[resource];
 178 
 179         if (sresource == -1) {
 180                 if (uucopy((void *)p2, &rl, sizeof (rl)) != 0)
 181                         return (-errno);
 182 
 183                 switch (resource) {
 184                 case LX_RLIMIT_MEMLOCK:
 185                 case LX_RLIMIT_RSS:
 186                 case LX_RLIMIT_LOCKS:
 187                 case LX_RLIMIT_NPROC:
 188                         if (rl.rlim_max != LX_RLIM_INFINITY_N &&
 189                             (rl.rlim_cur == LX_RLIM_INFINITY_N ||
 190                             rl.rlim_cur > rl.rlim_max))
 191                                 return (-EINVAL);
 192                         if (rl.rlim_max == LX_RLIM_INFINITY_N)
 193                                 fake_limits[resource].rlim_max = RLIM_INFINITY;
 194                         else
 195                                 fake_limits[resource].rlim_max = rl.rlim_max;
 196                         if (rl.rlim_cur == LX_RLIM_INFINITY_N)
 197                                 fake_limits[resource].rlim_cur = RLIM_INFINITY;
 198                         else
 199                                 fake_limits[resource].rlim_cur = rl.rlim_cur;
 200                         return (0);
 201                 }
 202 
 203                 lx_unsupported("Unsupported resource type %d\n", resource);
 204                 return (-ENOTSUP);
 205         }
 206 
 207         rv = setrlimit(sresource, rlp);
 208 
 209         return (rv < 0 ? -errno : 0);
 210 }
 211 
 212 /*
 213  * We lucked out here.  Linux and Solaris have exactly the same
 214  * rusage structures.
 215  */
 216 int
 217 lx_getrusage(uintptr_t p1, uintptr_t p2)
 218 {
 219         int who = (int)p1;
 220         struct rusage *rup = (struct rusage *)p2;
 221         int rv, swho;
 222 
 223         if (who == LX_RUSAGE_SELF)
 224                 swho = _RUSAGESYS_GETRUSAGE;
 225         else if (who == LX_RUSAGE_CHILDREN)
 226                 swho = _RUSAGESYS_GETRUSAGE_CHLD;
 227         else
 228                 return (-EINVAL);
 229 
 230         rv = getrusage(swho, rup);
 231 
 232         return (rv < 0 ? -errno : 0);
 233 }