openenvutils/commandshell/shell/src/builtins/rlimits.c
changeset 0 2e3d3ce01487
child 4 0fdb7f6b0309
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 //rlimits.c - resource limit builtins
       
     2 //
       
     3 // © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved.
       
     4 //
       
     5 /*
       
     6  * This file is part of zsh, the Z shell.
       
     7  *
       
     8  * Copyright (c) 1992-1997 Paul Falstad
       
     9  * All rights reserved.
       
    10  *
       
    11  * Permission is hereby granted, without written agreement and without
       
    12  * license or royalty fees, to use, copy, modify, and distribute this
       
    13  * software and to distribute modified versions of this software for any
       
    14  * purpose, provided that the above copyright notice and the following
       
    15  * two paragraphs appear in all copies of this software.
       
    16  *
       
    17  * In no event shall Paul Falstad or the Zsh Development Group be liable
       
    18  * to any party for direct, indirect, special, incidental, or consequential
       
    19  * damages arising out of the use of this software and its documentation,
       
    20  * even if Paul Falstad and the Zsh Development Group have been advised of
       
    21  * the possibility of such damage.
       
    22  *
       
    23  * Paul Falstad and the Zsh Development Group specifically disclaim any
       
    24  * warranties, including, but not limited to, the implied warranties of
       
    25  * merchantability and fitness for a particular purpose.  The software
       
    26  * provided hereunder is on an "as is" basis, and Paul Falstad and the
       
    27  * Zsh Development Group have no obligation to provide maintenance,
       
    28  * support, updates, enhancements, or modifications.
       
    29  *
       
    30  */
       
    31 #include "rlimits.mdh"
       
    32 #include "rlimits.pro"
       
    33 
       
    34 #ifdef __SYMBIAN32__
       
    35 #include "dummy.h"
       
    36 #endif //__SYMBIAN32__
       
    37 
       
    38 #ifdef __SYMBIAN32__
       
    39 #ifdef __WINSCW__
       
    40 #pragma warn_unusedarg off
       
    41 #endif//__WINSCW__
       
    42 #endif//__SYMBIAN32__
       
    43 
       
    44 #if defined(HAVE_GETRLIMIT) && defined(RLIM_INFINITY)
       
    45 
       
    46 enum {
       
    47     ZLIMTYPE_MEMORY,
       
    48     ZLIMTYPE_NUMBER,
       
    49     ZLIMTYPE_TIME,
       
    50     ZLIMTYPE_UNKNOWN
       
    51 };
       
    52 
       
    53 /* Generated rec array containing limits required for the limit builtin.     *
       
    54  * They must appear in this array in numerical order of the RLIMIT_* macros. */
       
    55 
       
    56 # include "rlimits.h"
       
    57 
       
    58 static rlim_t
       
    59 zstrtorlimt(const char *s, char **t, int base)
       
    60 {
       
    61     rlim_t ret = 0;
       
    62 
       
    63     if (strcmp(s, "unlimited") == 0) {
       
    64 	if (t)
       
    65 	    *t = (char *) s + 9;
       
    66 	return RLIM_INFINITY;
       
    67     }
       
    68 # if defined(RLIM_T_IS_QUAD_T) || defined(RLIM_T_IS_LONG_LONG) || defined(RLIM_T_IS_UNSIGNED)
       
    69     if (!base) {
       
    70 	if (*s != '0')
       
    71 	    base = 10;
       
    72 	else if (*++s == 'x' || *s == 'X')
       
    73 	    base = 16, s++;
       
    74 	else
       
    75 	    base = 8;
       
    76     } 
       
    77     if (base <= 10)
       
    78 	for (; *s >= '0' && *s < ('0' + base); s++)
       
    79 	    ret = ret * base + *s - '0';
       
    80     else
       
    81 	for (; idigit(*s) || (*s >= 'a' && *s < ('a' + base - 10))
       
    82 	     || (*s >= 'A' && *s < ('A' + base - 10)); s++)
       
    83 	    ret = ret * base + (idigit(*s) ? (*s - '0') : (*s & 0x1f) + 9);
       
    84     if (t)
       
    85 	*t = (char *)s;
       
    86 # else /* !RLIM_T_IS_QUAD_T && !RLIM_T_IS_LONG_LONG && !RLIM_T_IS_UNSIGNED */
       
    87     ret = zstrtol(s, t, base);
       
    88 # endif /* !RLIM_T_IS_QUAD_T && !RLIM_T_IS_LONG_LONG && !RLIM_T_IS_UNSIGNED */
       
    89     return ret;
       
    90 }
       
    91 
       
    92 /**/
       
    93 static void
       
    94 showlimitvalue(int lim, rlim_t val)
       
    95 {
       
    96     /* display limit for resource number lim */
       
    97     if (lim < ZSH_NLIMITS)
       
    98 	printf("%-16s", recs[lim]);
       
    99     else
       
   100     {
       
   101 	/* Unknown limit, hence unknown units. */
       
   102 	printf("%-16d", lim);
       
   103     }
       
   104     if (val == RLIM_INFINITY)
       
   105 	printf("unlimited\n");
       
   106     else if (lim >= ZSH_NLIMITS)
       
   107     {
       
   108 # ifdef RLIM_T_IS_QUAD_T
       
   109 	printf("%qd\n", val);
       
   110 # else
       
   111 #  ifdef RLIM_T_IS_LONG_LONG
       
   112 	printf("%lld\n", val);
       
   113 #  else
       
   114 #   ifdef RLIM_T_IS_UNSIGNED
       
   115 	printf("%lu\n", val);
       
   116 #   else
       
   117 	printf("%ld\n", val);
       
   118 #   endif /* RLIM_T_IS_UNSIGNED */
       
   119 #  endif /* RLIM_T_IS_LONG_LONG */
       
   120 # endif /* RLIM_T_IS_QUAD_T */
       
   121     }
       
   122     else if (limtype[lim] == ZLIMTYPE_TIME) {
       
   123 	/* time-type resource -- display as hours, minutes and
       
   124 	   seconds. */
       
   125 	printf("%d:%02d:%02d\n", (int)(val / 3600),
       
   126 	       (int)(val / 60) % 60, (int)(val % 60));
       
   127     } else if (limtype[lim] == ZLIMTYPE_NUMBER ||
       
   128 	       limtype[lim] == ZLIMTYPE_UNKNOWN) {
       
   129 	/* pure numeric resource */
       
   130 	printf("%d\n", (int)val);
       
   131     } else if (val >= 1024L * 1024L)
       
   132 	/* memory resource -- display with `K' or `M' modifier */
       
   133 # ifdef RLIM_T_IS_QUAD_T
       
   134 	printf("%qdMB\n", val / (1024L * 1024L));
       
   135     else
       
   136 	printf("%qdkB\n", val / 1024L);
       
   137 # else
       
   138 #  ifdef RLIM_T_IS_LONG_LONG
       
   139     printf("%lldMB\n", val / (1024L * 1024L));
       
   140     else
       
   141 	printf("%lldkB\n", val / 1024L);
       
   142 #  else
       
   143 #   ifdef RLIM_T_IS_UNSIGNED
       
   144     printf("%luMB\n", val / (1024L * 1024L));
       
   145     else
       
   146 	printf("%lukB\n", val / 1024L);
       
   147 #   else
       
   148     printf("%ldMB\n", val / (1024L * 1024L));
       
   149     else
       
   150 	printf("%ldkB\n", val / 1024L);
       
   151 #   endif /* RLIM_T_IS_UNSIGNED */
       
   152 #  endif /* RLIM_T_IS_LONG_LONG */
       
   153 # endif /* RLIM_T_IS_QUAD_T */
       
   154 }
       
   155 
       
   156 /* Display resource limits.  hard indicates whether `hard' or `soft'  *
       
   157  * limits should be displayed.  lim specifies the limit, or may be -1 *
       
   158  * to show all.                                                       */
       
   159 
       
   160 /**/
       
   161 static int
       
   162 showlimits(char *nam, int hard, int lim)
       
   163 {
       
   164     int rt;
       
   165 
       
   166     if (lim >= ZSH_NLIMITS)
       
   167     {
       
   168 	/*
       
   169 	 * Not configured into the shell.  Ask the OS
       
   170 	 * explicitly for this limit.
       
   171 	 */
       
   172 	struct rlimit vals;
       
   173 	if (getrlimit(lim, &vals) < 0)
       
   174 	{
       
   175 	    zwarnnam(nam, "can't read limit: %e", NULL, errno);
       
   176 	    return 1;
       
   177 	}
       
   178 	showlimitvalue(lim, hard ? vals.rlim_max : vals.rlim_cur);
       
   179     }
       
   180     else if (lim != -1)
       
   181     {
       
   182 	showlimitvalue(lim, hard ? limits[lim].rlim_max :
       
   183 		       limits[lim].rlim_cur);
       
   184     }
       
   185     else
       
   186     {
       
   187 	/* main loop over resource types */
       
   188 	for (rt = 0; rt != ZSH_NLIMITS; rt++)
       
   189 	    showlimitvalue(rt, (hard) ? limits[rt].rlim_max :
       
   190 			   limits[rt].rlim_cur);
       
   191     }
       
   192 
       
   193     return 0;
       
   194 }
       
   195 
       
   196 /* Display a resource limit, in ulimit style.  lim specifies which   *
       
   197  * limit should be displayed, and hard indicates whether the hard or *
       
   198  * soft limit should be displayed.                                   */
       
   199 
       
   200 /**/
       
   201 static int
       
   202 printulimit(char *nam, int lim, int hard, int head)
       
   203 {
       
   204     rlim_t limit;
       
   205 
       
   206     /* get the limit in question */
       
   207     if (lim >= ZSH_NLIMITS)
       
   208     {
       
   209 	struct rlimit vals;
       
   210 
       
   211 	if (getrlimit(lim, &vals) < 0)
       
   212 	{
       
   213 	    zwarnnam(nam, "can't read limit: %e", NULL, errno);
       
   214 	    return 1;
       
   215 	}
       
   216 	limit = (hard) ? vals.rlim_max : vals.rlim_cur;
       
   217     }
       
   218     else
       
   219 	limit = (hard) ? limits[lim].rlim_max : limits[lim].rlim_cur;
       
   220     /* display the appropriate heading */
       
   221     switch (lim) {
       
   222     case RLIMIT_CORE:
       
   223 	if (head)
       
   224 	    printf("-c: core file size (blocks)    ");
       
   225 	if (limit != RLIM_INFINITY)
       
   226 	    limit /= 512;
       
   227 	break;
       
   228     case RLIMIT_DATA:
       
   229 	if (head)
       
   230 	    printf("-d: data seg size (kbytes)     ");
       
   231 	if (limit != RLIM_INFINITY)
       
   232 	    limit /= 1024;
       
   233 	break;
       
   234     case RLIMIT_FSIZE:
       
   235 	if (head)
       
   236 	    printf("-f: file size (blocks)         ");
       
   237 	if (limit != RLIM_INFINITY)
       
   238 	    limit /= 512;
       
   239 	break;
       
   240 # ifdef HAVE_RLIMIT_SIGPENDING
       
   241     case RLIMIT_SIGPENDING:
       
   242 	if (head)
       
   243 	    printf("-i: pending signals            ");
       
   244 	break;
       
   245 # endif
       
   246 # ifdef HAVE_RLIMIT_MEMLOCK
       
   247     case RLIMIT_MEMLOCK:
       
   248 	if (head)
       
   249 	    printf("-l: locked-in-memory size (kb) ");
       
   250 	if (limit != RLIM_INFINITY)
       
   251 	    limit /= 1024;
       
   252 	break;
       
   253 # endif /* HAVE_RLIMIT_MEMLOCK */
       
   254 /* If RLIMIT_VMEM and RLIMIT_RSS are defined and equal, avoid *
       
   255  * duplicate case statement.  Observed on QNX Neutrino 6.1.0. */
       
   256 # if defined(HAVE_RLIMIT_RSS) && !defined(RLIMIT_VMEM_IS_RSS) && !defined(RLIMIT_RSS_IS_AS)
       
   257     case RLIMIT_RSS:
       
   258 	if (head)
       
   259 	    printf("-m: resident set size (kbytes) ");
       
   260 	if (limit != RLIM_INFINITY)
       
   261 	    limit /= 1024;
       
   262 	break;
       
   263 # endif /* HAVE_RLIMIT_RSS */
       
   264 # if defined(HAVE_RLIMIT_VMEM) && defined(HAVE_RLIMIT_RSS) && defined(RLIMIT_VMEM_IS_RSS)
       
   265     case RLIMIT_VMEM:
       
   266 	if (head)
       
   267 	    printf("-m: memory size (kb)           ");
       
   268 	if (limit != RLIM_INFINITY)
       
   269 	    limit /= 1024;
       
   270 	break;
       
   271 # endif /* HAVE_RLIMIT_VMEM */
       
   272 # ifdef HAVE_RLIMIT_NOFILE
       
   273     case RLIMIT_NOFILE:
       
   274 	if (head)
       
   275 	    printf("-n: file descriptors           ");
       
   276 	break;
       
   277 # endif /* HAVE_RLIMIT_NOFILE */
       
   278 # ifdef HAVE_RLIMIT_MSGQUEUE
       
   279     case RLIMIT_MSGQUEUE:
       
   280 	if (head)
       
   281 	    printf("-q: bytes in POSIX msg queues  ");
       
   282 	break;
       
   283 # endif
       
   284     case RLIMIT_STACK:
       
   285 	if (head)
       
   286 	    printf("-s: stack size (kbytes)        ");
       
   287 	if (limit != RLIM_INFINITY)
       
   288 	    limit /= 1024;
       
   289 	break;
       
   290     case RLIMIT_CPU:
       
   291 	if (head)
       
   292 	    printf("-t: cpu time (seconds)         ");
       
   293 	break;
       
   294 # ifdef HAVE_RLIMIT_NPROC
       
   295     case RLIMIT_NPROC:
       
   296 	if (head)
       
   297 	    printf("-u: processes                  ");
       
   298 	break;
       
   299 # endif /* HAVE_RLIMIT_NPROC */
       
   300 # if defined(HAVE_RLIMIT_VMEM) && (!defined(HAVE_RLIMIT_RSS) || !defined(RLIMIT_VMEM_IS_RSS))
       
   301     case RLIMIT_VMEM:
       
   302 	if (head)
       
   303 	    printf("-v: virtual memory size (kb)   ");
       
   304 	if (limit != RLIM_INFINITY)
       
   305 	    limit /= 1024;
       
   306 	break;
       
   307 # endif /* HAVE_RLIMIT_VMEM */
       
   308 # if defined HAVE_RLIMIT_AS && !defined(RLIMIT_VMEM_IS_AS)
       
   309     case RLIMIT_AS:
       
   310 	if (head)
       
   311 	    printf("-v: address space (kb)         ");
       
   312 	if (limit != RLIM_INFINITY)
       
   313 	    limit /= 1024;
       
   314 	break;
       
   315 # endif /* HAVE_RLIMIT_AS */
       
   316 # ifdef HAVE_RLIMIT_LOCKS
       
   317     case RLIMIT_LOCKS:
       
   318 	if (head)
       
   319 	    printf("-x: file locks                 ");
       
   320 	break;
       
   321 # endif /* HAVE_RLIMIT_LOCKS */
       
   322 # ifdef HAVE_RLIMIT_AIO_MEM
       
   323     case RLIMIT_AIO_MEM:
       
   324 	if (head)
       
   325 	    printf("-N %2d: AIO locked-in-memory (kb) ", RLIMIT_AIO_MEM);
       
   326 	if (limit != RLIM_INFINITY)
       
   327 	    limit /= 1024;
       
   328 	break;
       
   329 # endif /* HAVE_RLIMIT_AIO_MEM */
       
   330 # ifdef HAVE_RLIMIT_AIO_OPS
       
   331     case RLIMIT_AIO_OPS:
       
   332 	if (head)
       
   333 	    printf("-N %2d: AIO operations          ", RLIMIT_AIO_OPS);
       
   334 	break;
       
   335 # endif /* HAVE_RLIMIT_AIO_OPS */
       
   336 # ifdef HAVE_RLIMIT_TCACHE
       
   337     case RLIMIT_TCACHE:
       
   338 	if (head)
       
   339 	    printf("-N %2d: cached threads          ", RLIMIT_TCACHE);
       
   340 	break;
       
   341 # endif /* HAVE_RLIMIT_TCACHE */
       
   342 # ifdef HAVE_RLIMIT_SBSIZE
       
   343     case RLIMIT_SBSIZE:
       
   344 	if (head)
       
   345 	    printf("-N %2d: socket buffer size (kb) ", RLIMIT_SBSIZE);
       
   346 	if (limit != RLIM_INFINITY)
       
   347 	    limit /= 1024;
       
   348 	break;
       
   349 # endif /* HAVE_RLIMIT_SBSIZE */
       
   350 # ifdef HAVE_RLIMIT_PTHREAD
       
   351     case RLIMIT_PTHREAD:
       
   352 	if (head)
       
   353 	    printf("-N %2d: threads per process     ", RLIMIT_PTHREAD);
       
   354 	break;
       
   355 # endif /* HAVE_RLIMIT_PTHREAD */
       
   356     default:
       
   357 	if (head)
       
   358 	    printf("-N %2d:                         ", lim);
       
   359 	break;
       
   360     }
       
   361     /* display the limit */
       
   362     if (limit == RLIM_INFINITY)
       
   363 	printf("unlimited\n");
       
   364     else {
       
   365 # ifdef RLIM_T_IS_QUAD_T
       
   366 	printf("%qd\n", limit);
       
   367 # else
       
   368 #  ifdef RLIM_T_IS_LONG_LONG
       
   369 	printf("%lld\n", limit);
       
   370 #  else
       
   371 #   ifdef RLIM_T_IS_UNSIGNED
       
   372 	printf("%lu\n", limit);
       
   373 #   else
       
   374 	printf("%ld\n", limit);
       
   375 #   endif /* RLIM_T_IS_UNSIGNED */
       
   376 #  endif /* RLIM_T_IS_LONG_LONG */
       
   377 # endif /* RLIM_T_IS_QUAD_T */
       
   378     }
       
   379 
       
   380     return 0;
       
   381 }
       
   382 
       
   383 /**/
       
   384 static int
       
   385 do_limit(char *nam, int lim, rlim_t val, int hard, int soft, int set)
       
   386 {
       
   387     if (lim >= ZSH_NLIMITS) {
       
   388 	struct rlimit vals;
       
   389 	if (getrlimit(lim, &vals) < 0)
       
   390 	{
       
   391 	    /* best guess about error */
       
   392 	    zwarnnam(nam, "can't read limit: %e", NULL, errno);
       
   393 	    return 1;
       
   394 	}
       
   395 	if (hard)
       
   396 	{
       
   397 	    if (val > vals.rlim_max && geteuid()) {
       
   398 		zwarnnam(nam, "can't raise hard limits", NULL, 0);
       
   399 		return 1;
       
   400 	    }
       
   401 	    vals.rlim_max = val;
       
   402 	    /*
       
   403 	     * not show if all systems will do this silently, but
       
   404 	     * best be safe...
       
   405 	     */
       
   406 	    if (val < vals.rlim_cur)
       
   407 		vals.rlim_cur = val;
       
   408 	}
       
   409 	if (soft || !hard) {
       
   410 	    if (val > vals.rlim_max) {
       
   411 		zwarnnam(nam, "limit exceeds hard limit", NULL, 0);
       
   412 		return 1;
       
   413 	    }
       
   414 	    else
       
   415 		vals.rlim_cur = val;
       
   416 	}
       
   417 	if (!set)
       
   418 	{
       
   419 	    zwarnnam(nam,
       
   420 		     "warning: unrecognised limit %d, use -s to set",
       
   421 		     NULL, lim);
       
   422 	    return 1;
       
   423 	}
       
   424 	else if (setrlimit(lim, &vals) < 0)
       
   425 	{
       
   426 	    zwarnnam(nam, "setrlimit failed: %e", NULL, errno);
       
   427 	    return 1;
       
   428 	}
       
   429     } else {
       
   430 	/* new limit is valid and has been interpreted; apply it to the
       
   431 	specified resource */
       
   432 	if (hard) {
       
   433 	    /* can only raise hard limits if running as root */
       
   434 	    if (val > current_limits[lim].rlim_max && geteuid()) {
       
   435 		zwarnnam(nam, "can't raise hard limits", NULL, 0);
       
   436 		return 1;
       
   437 	    } else {
       
   438 		limits[lim].rlim_max = val;
       
   439 		if (val < limits[lim].rlim_cur)
       
   440 		    limits[lim].rlim_cur = val;
       
   441 	    }
       
   442 	}
       
   443 	if (soft || !hard) {
       
   444 	    if (val > limits[lim].rlim_max) {
       
   445 		/* no idea about this difference, don't intend to worry */
       
   446 		if (*nam == 'u')
       
   447 		{
       
   448 		    /* ulimit does this */
       
   449 		    if (val > current_limits[lim].rlim_max && geteuid()) {
       
   450 			zwarnnam(nam, "value exceeds hard limit", NULL, 0);
       
   451 			return 1;
       
   452 		    }
       
   453 		    limits[lim].rlim_max = limits[lim].rlim_cur = val;
       
   454 		} else {
       
   455 		    /* but limit does this */
       
   456 		    zwarnnam(nam, "limit exceeds hard limit", NULL, 0);
       
   457 		    return 1;
       
   458 		}
       
   459 	    } else
       
   460 		limits[lim].rlim_cur = val;
       
   461 	    if (set && zsetlimit(lim, "limit"))
       
   462 		return 1;
       
   463 	}
       
   464     }
       
   465     return 0;
       
   466 }
       
   467 
       
   468 /* limit: set or show resource limits.  The variable hard indicates *
       
   469  * whether `hard' or `soft' resource limits are being set/shown.    */
       
   470 
       
   471 /**/
       
   472 static int
       
   473 bin_limit(char *nam, char **argv, Options ops, UNUSED(int func))
       
   474 {
       
   475     char *s;
       
   476     int hard, limnum, lim;
       
   477     rlim_t val;
       
   478     int ret = 0;
       
   479 
       
   480     hard = OPT_ISSET(ops,'h');
       
   481     if (OPT_ISSET(ops,'s') && !*argv)
       
   482 	return setlimits(NULL);
       
   483     /* without arguments, display limits */
       
   484     if (!*argv)
       
   485 	return showlimits(nam, hard, -1);
       
   486     while ((s = *argv++)) {
       
   487 	/* Search for the appropriate resource name.  When a name matches (i.e. *
       
   488 	 * starts with) the argument, the lim variable changes from -1 to the   *
       
   489 	 * number of the resource.  If another match is found, lim goes to -2.  */
       
   490 	if (idigit(*s))
       
   491 	{
       
   492 	    lim = (int)zstrtol(s, NULL, 10);
       
   493 	}
       
   494 	else
       
   495 	    for (lim = -1, limnum = 0; limnum < ZSH_NLIMITS; limnum++)
       
   496 		if (!strncmp(recs[limnum], s, strlen(s))) {
       
   497 		    if (lim != -1)
       
   498 			lim = -2;
       
   499 		    else
       
   500 			lim = limnum;
       
   501 		}
       
   502 	/* lim==-1 indicates that no matches were found.       *
       
   503 	 * lim==-2 indicates that multiple matches were found. */
       
   504 	if (lim < 0) {
       
   505 	    zwarnnam(nam,
       
   506 		     (lim == -2) ? "ambiguous resource specification: %s"
       
   507 		     : "no such resource: %s", s, 0);
       
   508 	    return 1;
       
   509 	}
       
   510 	/* without value for limit, display the current limit */
       
   511 	if (!(s = *argv++))
       
   512 	    return showlimits(nam, hard, lim);
       
   513 	if (lim >= ZSH_NLIMITS)
       
   514 	{
       
   515 	    val = zstrtorlimt(s, &s, 10);
       
   516 	    if (*s)
       
   517 	    {
       
   518 		/* unknown limit, no idea how to scale */
       
   519 		zwarnnam(nam, "unknown scaling factor: %s", s, 0);
       
   520 		return 1;
       
   521 	    }
       
   522 	}
       
   523 	else if (limtype[lim] == ZLIMTYPE_TIME) {
       
   524 	    /* time-type resource -- may be specified as seconds, or minutes or *
       
   525 	     * hours with the `m' and `h' modifiers, and `:' may be used to add *
       
   526 	     * together more than one of these.  It's easier to understand from *
       
   527 	     * the code:                                                        */
       
   528 	    val = zstrtorlimt(s, &s, 10);
       
   529 	    if (*s) {
       
   530 		if ((*s == 'h' || *s == 'H') && !s[1])
       
   531 		    val *= 3600L;
       
   532 		else if ((*s == 'm' || *s == 'M') && !s[1])
       
   533 		    val *= 60L;
       
   534 		else if (*s == ':')
       
   535 		    val = val * 60 + zstrtorlimt(s + 1, &s, 10);
       
   536 		else {
       
   537 		    zwarnnam(nam, "unknown scaling factor: %s", s, 0);
       
   538 		    return 1;
       
   539 		}
       
   540 	    }
       
   541 	} else if (limtype[lim] == ZLIMTYPE_NUMBER || limtype[lim] == ZLIMTYPE_UNKNOWN) {
       
   542 	    /* pure numeric resource -- only a straight decimal number is
       
   543 	    permitted. */
       
   544 	    char *t = s;
       
   545 	    val = zstrtorlimt(t, &s, 10);
       
   546 	    if (s == t) {
       
   547 		zwarnnam(nam, "limit must be a number", NULL, 0);
       
   548 		return 1;
       
   549 	    }
       
   550 	} else {
       
   551 	    /* memory-type resource -- `k' and `M' modifiers are permitted,
       
   552 	    meaning (respectively) 2^10 and 2^20. */
       
   553 	    val = zstrtorlimt(s, &s, 10);
       
   554 	    if (!*s || ((*s == 'k' || *s == 'K') && !s[1])) {
       
   555 		if (val != RLIM_INFINITY)
       
   556 		    val *= 1024L;
       
   557 	    } else if ((*s == 'M' || *s == 'm') && !s[1])
       
   558 		val *= 1024L * 1024;
       
   559 	    else {
       
   560 		zwarnnam(nam, "unknown scaling factor: %s", s, 0);
       
   561 		return 1;
       
   562 	    }
       
   563 	}
       
   564 	if (do_limit(nam, lim, val, hard, !hard, OPT_ISSET(ops, 's')))
       
   565 	    ret++;
       
   566     }
       
   567     return ret;
       
   568 }
       
   569 
       
   570 /**/
       
   571 static int
       
   572 do_unlimit(char *nam, int lim, int hard, int soft, int set, int euid)
       
   573 {
       
   574     /* remove specified limit */
       
   575     if (lim >= ZSH_NLIMITS) {
       
   576 	struct rlimit vals;
       
   577 	if (getrlimit(lim, &vals) < 0)
       
   578 	{
       
   579 	    zwarnnam(nam, "can't read limit: %e", NULL, errno);
       
   580 	    return 1;
       
   581 	}
       
   582 	if (hard) {
       
   583 	    if (euid && vals.rlim_max != RLIM_INFINITY) {
       
   584 		zwarnnam(nam, "can't remove hard limits", NULL, 0);
       
   585 		return 1;
       
   586 	    } else
       
   587 		vals.rlim_max = RLIM_INFINITY;
       
   588 	}
       
   589 	if (!hard || soft)
       
   590 	    vals.rlim_cur = vals.rlim_max;
       
   591 	if (!set) {
       
   592 	    zwarnnam(nam,
       
   593 		     "warning: unrecognised limit %d, use -s to set",
       
   594 		     NULL, lim);
       
   595 	    return 1;
       
   596 	} else if (setrlimit(lim, &vals) < 0) {
       
   597 	    zwarnnam(nam, "setrlimit failed: %e", NULL, errno);
       
   598 	    return 1;
       
   599 	}
       
   600     } else {
       
   601 	if (hard) {
       
   602 	    if (euid && current_limits[lim].rlim_max != RLIM_INFINITY) {
       
   603 		zwarnnam(nam, "can't remove hard limits", NULL, 0);
       
   604 		return 1;
       
   605 	    } else
       
   606 		limits[lim].rlim_max = RLIM_INFINITY;
       
   607 	}
       
   608 	if (!hard || soft)
       
   609 	    limits[lim].rlim_cur = limits[lim].rlim_max;
       
   610 	if (set && zsetlimit(lim, nam))
       
   611 	    return 1;
       
   612     }
       
   613     return 0;
       
   614 }
       
   615 
       
   616 /* unlimit: remove resource limits.  Much of this code is the same as *
       
   617  * that in bin_limit().                                               */
       
   618 
       
   619 /**/
       
   620 static int
       
   621 bin_unlimit(char *nam, char **argv, Options ops, UNUSED(int func))
       
   622 {
       
   623     int hard, limnum, lim;
       
   624     int ret = 0;
       
   625     uid_t euid = geteuid();
       
   626 
       
   627     hard = OPT_ISSET(ops,'h');
       
   628     /* Without arguments, remove all limits. */
       
   629     if (!*argv) {
       
   630 	for (limnum = 0; limnum != RLIM_NLIMITS; limnum++) {
       
   631 	    if (hard) {
       
   632 		if (euid && current_limits[limnum].rlim_max != RLIM_INFINITY)
       
   633 		    ret++;
       
   634 		else
       
   635 		    limits[limnum].rlim_max = RLIM_INFINITY;
       
   636 	    } else
       
   637 		limits[limnum].rlim_cur = limits[limnum].rlim_max;
       
   638 	}
       
   639 	if (OPT_ISSET(ops,'s'))
       
   640 	    ret += setlimits(nam);
       
   641 	if (ret)
       
   642 	    zwarnnam(nam, "can't remove hard limits", NULL, 0);
       
   643     } else {
       
   644 	for (; *argv; argv++) {
       
   645 	    /* Search for the appropriate resource name.  When a name     *
       
   646 	     * matches (i.e. starts with) the argument, the lim variable  *
       
   647 	     * changes from -1 to the number of the resource.  If another *
       
   648 	     * match is found, lim goes to -2.                            */
       
   649 	    if (idigit(**argv)) {
       
   650 		lim = (int)zstrtol(*argv, NULL, 10);
       
   651 	    } else {
       
   652 		for (lim = -1, limnum = 0; limnum < ZSH_NLIMITS; limnum++)
       
   653 		    if (!strncmp(recs[limnum], *argv, strlen(*argv))) {
       
   654 			if (lim != -1)
       
   655 			    lim = -2;
       
   656 			else
       
   657 			    lim = limnum;
       
   658 		    }
       
   659 	    }
       
   660 	    /* lim==-1 indicates that no matches were found.       *
       
   661 	     * lim==-2 indicates that multiple matches were found. */
       
   662 	    if (lim < 0) {
       
   663 		zwarnnam(nam,
       
   664 			 (lim == -2) ? "ambiguous resource specification: %s"
       
   665 			 : "no such resource: %s", *argv, 0);
       
   666 		return 1;
       
   667 	    }
       
   668 	    else if (do_unlimit(nam, lim, hard, !hard, OPT_ISSET(ops, 's'),
       
   669 				euid))
       
   670 		ret++;
       
   671 	}
       
   672     }
       
   673     return ret;
       
   674 }
       
   675 
       
   676 /* ulimit: set or display resource limits */
       
   677 
       
   678 /**/
       
   679 static int
       
   680 bin_ulimit(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
       
   681 {
       
   682     int res, resmask = 0, hard = 0, soft = 0, nres = 0, all = 0, ret = 0;
       
   683     char *options;
       
   684 
       
   685     do {
       
   686 	options = *argv;
       
   687 	if (options && *options == '-' && !options[1]) {
       
   688 	    zwarnnam(name, "missing option letter", NULL, 0);
       
   689 	    return 1;
       
   690 	}
       
   691 	res = -1;
       
   692 	if (options && *options == '-') {
       
   693 	    argv++;
       
   694 	    while (*++options) {
       
   695 		if(*options == Meta)
       
   696 		    *++options ^= 32;
       
   697 		res = -1;
       
   698 		switch (*options) {
       
   699 		case 'H':
       
   700 		    hard = 1;
       
   701 		    continue;
       
   702 		case 'S':
       
   703 		    soft = 1;
       
   704 		    continue;
       
   705 		case 'N':
       
   706 		    if (options[1]) {
       
   707 			res = (int)zstrtol(options+1, NULL, 10);
       
   708 		    } else if (*argv) {
       
   709 			res = (int)zstrtol(*argv++, NULL, 10);
       
   710 		    } else {
       
   711 			zwarnnam(name, "number required after -N",
       
   712 				 NULL, 0);
       
   713 			return 1;
       
   714 		    }
       
   715 		    /*
       
   716 		     * fake it so it looks like we just finished an option...
       
   717 		     */
       
   718 		    while (options[1])
       
   719 			options++;
       
   720 		    break;
       
   721 		case 'a':
       
   722 		    if (resmask) {
       
   723 			zwarnnam(name, "no limits allowed with -a",
       
   724 				 NULL, 0);
       
   725 			return 1;
       
   726 		    }
       
   727 		    all = 1;
       
   728 		    resmask = (1 << RLIM_NLIMITS) - 1;
       
   729 		    nres = RLIM_NLIMITS;
       
   730 		    continue;
       
   731 		case 't':
       
   732 		    res = RLIMIT_CPU;
       
   733 		    break;
       
   734 		case 'f':
       
   735 		    res = RLIMIT_FSIZE;
       
   736 		    break;
       
   737 		case 'd':
       
   738 		    res = RLIMIT_DATA;
       
   739 		    break;
       
   740 		case 's':
       
   741 		    res = RLIMIT_STACK;
       
   742 		    break;
       
   743 		case 'c':
       
   744 		    res = RLIMIT_CORE;
       
   745 		    break;
       
   746 # ifdef HAVE_RLIMIT_RSS
       
   747 		case 'm':
       
   748 		    res = RLIMIT_RSS;
       
   749 		    break;
       
   750 # endif /* HAVE_RLIMIT_RSS */
       
   751 # ifdef HAVE_RLIMIT_MEMLOCK
       
   752 		case 'l':
       
   753 		    res = RLIMIT_MEMLOCK;
       
   754 		    break;
       
   755 # endif /* HAVE_RLIMIT_MEMLOCK */
       
   756 # ifdef HAVE_RLIMIT_NOFILE
       
   757 		case 'n':
       
   758 		    res = RLIMIT_NOFILE;
       
   759 		    break;
       
   760 # endif /* HAVE_RLIMIT_NOFILE */
       
   761 # ifdef HAVE_RLIMIT_NPROC
       
   762 		case 'u':
       
   763 		    res = RLIMIT_NPROC;
       
   764 		    break;
       
   765 # endif /* HAVE_RLIMIT_NPROC */
       
   766 # if defined(HAVE_RLIMIT_VMEM) || defined(HAVE_RLIMIT_AS)
       
   767 		case 'v':
       
   768 #  ifdef HAVE_RLIMIT_VMEM
       
   769 		    res = RLIMIT_VMEM;
       
   770 #  else
       
   771 		    res = RLIMIT_AS;
       
   772 #  endif
       
   773 		    break;
       
   774 # endif /* HAVE_RLIMIT_VMEM */
       
   775 # ifdef HAVE_RLIMIT_LOCKS
       
   776 		case 'x':
       
   777 		    res = RLIMIT_LOCKS;
       
   778 		    break;
       
   779 # endif
       
   780 # ifdef HAVE_RLIMIT_SIGPENDING
       
   781 		case 'i':
       
   782 		    res = RLIMIT_SIGPENDING;
       
   783 		    break;
       
   784 # endif
       
   785 # ifdef HAVE_RLIMIT_MSGQUEUE
       
   786 		case 'q':
       
   787 		    res = RLIMIT_MSGQUEUE;
       
   788 		    break;
       
   789 # endif
       
   790 		default:
       
   791 		    /* unrecognised limit */
       
   792 		    zwarnnam(name, "bad option: -%c", NULL, *options);
       
   793 		    return 1;
       
   794 		}
       
   795 		if (options[1]) {
       
   796 		    resmask |= 1 << res;
       
   797 		    nres++;
       
   798 		}
       
   799 		if (all && res != -1) {
       
   800 		    zwarnnam(name, "no limits allowed with -a",
       
   801 			     NULL, 0);
       
   802 		    return 1;
       
   803 		}
       
   804 	    }
       
   805 	}
       
   806 	if (!*argv || **argv == '-') {
       
   807 	    if (res < 0) {
       
   808 		if (*argv || nres)
       
   809 		    continue;
       
   810 		else
       
   811 		    res = RLIMIT_FSIZE;
       
   812 	    }
       
   813 	    resmask |= 1 << res;
       
   814 	    nres++;
       
   815 	    continue;
       
   816 	}
       
   817 	if (all) {
       
   818 	    zwarnnam(name, "no arguments allowed after -a", NULL, 0);
       
   819 	    return 1;
       
   820 	}
       
   821 	if (res < 0)
       
   822 	    res = RLIMIT_FSIZE;
       
   823 	if (strcmp(*argv, "unlimited")) {
       
   824 	    /* set limit to specified value */
       
   825 	    rlim_t limit;
       
   826 
       
   827 	    limit = zstrtorlimt(*argv, NULL, 10);
       
   828 	    /* scale appropriately */
       
   829 	    switch (res) {
       
   830 	    case RLIMIT_FSIZE:
       
   831 	    case RLIMIT_CORE:
       
   832 		limit *= 512;
       
   833 		break;
       
   834 	    case RLIMIT_DATA:
       
   835 	    case RLIMIT_STACK:
       
   836 # ifdef HAVE_RLIMIT_RSS
       
   837 	    case RLIMIT_RSS:
       
   838 # endif /* HAVE_RLIMIT_RSS */
       
   839 # ifdef HAVE_RLIMIT_MEMLOCK
       
   840 	    case RLIMIT_MEMLOCK:
       
   841 # endif /* HAVE_RLIMIT_MEMLOCK */
       
   842 /* If RLIMIT_VMEM and RLIMIT_RSS are defined and equal, avoid *
       
   843  * duplicate case statement.  Observed on QNX Neutrino 6.1.0. */
       
   844 # if defined(HAVE_RLIMIT_VMEM) && !defined(RLIMIT_VMEM_IS_RSS)
       
   845 	    case RLIMIT_VMEM:
       
   846 # endif /* HAVE_RLIMIT_VMEM */
       
   847 /* ditto RLIMIT_VMEM and RLIMIT_AS */
       
   848 # if defined(HAVE_RLIMIT_AS) && !defined(RLIMIT_VMEM_IS_AS) && !defined(RLIMIT_RSS_IS_AS)
       
   849 	    case RLIMIT_AS:
       
   850 # endif /* HAVE_RLIMIT_AS */
       
   851 # ifdef HAVE_RLIMIT_AIO_MEM
       
   852 	    case RLIMIT_AIO_MEM:
       
   853 # endif /* HAVE_RLIMIT_AIO_MEM */
       
   854 		limit *= 1024;
       
   855 		break;
       
   856 	    }
       
   857 	    if (do_limit(name, res, limit, hard, soft, 1))
       
   858 		ret++;
       
   859 	} else {
       
   860 	    if (do_unlimit(name, res, hard, soft, 1, geteuid()))
       
   861 		ret++;
       
   862 	}
       
   863 	argv++;
       
   864     } while (*argv);
       
   865     for (res = 0; resmask; res++, resmask >>= 1)
       
   866 	if ((resmask & 1) && printulimit(name, res, hard, nres > 1))
       
   867 	    ret++;
       
   868     return ret;
       
   869 }
       
   870 
       
   871 #else /* !HAVE_GETRLIMIT || !RLIM_INFINITY */
       
   872 
       
   873 # define bin_limit   bin_notavail
       
   874 # define bin_ulimit  bin_notavail
       
   875 # define bin_unlimit bin_notavail
       
   876 
       
   877 #endif /* !HAVE_GETRLIMIT || !RLIM_INFINITY */
       
   878 
       
   879 static struct builtin bintab[] = {
       
   880     BUILTIN("limit",   0, bin_limit,   0, -1, 0, "sh", NULL),
       
   881     BUILTIN("ulimit",  0, bin_ulimit,  0, -1, 0, NULL, NULL),
       
   882     BUILTIN("unlimit", 0, bin_unlimit, 0, -1, 0, "hs", NULL),
       
   883 };
       
   884 
       
   885 /**/
       
   886 int
       
   887 setup_(UNUSED(Module m))
       
   888 {
       
   889     return 0;
       
   890 }
       
   891 
       
   892 /**/
       
   893 int
       
   894 boot_(Module m)
       
   895 {
       
   896     return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
       
   897 }
       
   898 
       
   899 /**/
       
   900 int
       
   901 cleanup_(Module m)
       
   902 {
       
   903     deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
       
   904     return 0;
       
   905 }
       
   906 
       
   907 /**/
       
   908 int
       
   909 finish_(UNUSED(Module m))
       
   910 {
       
   911     return 0;
       
   912 }