Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

PATCH: setting unknown resource limits, again



This is an improved patch to handle unknown limits better.

The shell usually manages limits by keeping a record of the current
values, so doesn't need to use getrlimit()/setrlimit() unless the limits
are actually changed.  This isn't possible with unknown limits, so I had
to work round that.

The code was a bit complicated (bet you're surprised) and I've moved
code common to limit/unlimit and ulimit into separate functions to
reduce duplication.

One nice side effect of the new code is that there is a simple way of
using ulimit with limits that don't have option letters, and running
ulimit -a will show you how:

-t: cpu time (seconds)         unlimited
-f: file size (blocks)         unlimited
-d: data seg size (kbytes)     unlimited
-s: stack size (kbytes)        10240
-c: core file size (blocks)    0
-m: resident set size (kbytes) unlimited
-u: processes                  4074
-n: file descriptors           1024
-l: locked-in-memory size (kb) unlimited
-v: address space (kb)         unlimited
-N 10: file locks              unlimited

so you can limit file locks by using `-N 10' as the option.

The code wasn't completely (ha!) consistent about its behaviour if it
detected an error when looping over multiple limits: sometimes it
aborted at that point, sometimes it skipped to the next limit.  I've
tried to make this a bit more consistent and document the behaviour.

I tried a few simple tests, but there may be things I've missed.  It's
difficult, but not impossible, to construct scripts in the test suite
for limits and is probably worth doing.  The biggest problems are
working round existing hard limits, finding a good subset of limits
which work on a lot of systems, and taking care of variant output for
similar limits conditionally compiled into the code.

Index: Doc/Zsh/builtins.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/builtins.yo,v
retrieving revision 1.69
diff -u -r1.69 builtins.yo
--- Doc/Zsh/builtins.yo	22 Jun 2004 07:02:35 -0000	1.69
+++ Doc/Zsh/builtins.yo	30 Jun 2004 10:01:32 -0000
@@ -649,6 +649,10 @@
 is given, use hard limits instead of soft limits.
 If no var(resource) is given, print all limits.
 
+When looping over multiple resources, the shell will abort immediately if
+it detects a badly formed argument.  However, if it fails to set a limit
+for some other reason it will continue trying to set the remaining limits.
+
 var(resource) can be one of:
 
 startsitem()
@@ -672,7 +676,15 @@
 endsitem()
 
 Which of these resource limits are available depends on the system.
-var(resource) can be abbreviated to any unambiguous prefix.
+var(resource) can be abbreviated to any unambiguous prefix.  It
+can also be an integer, which corresponds to the integer defined
+for the resource by the operating system.
+
+If argument corresponds to a number which is out of the range of the
+resources configured into the shell, the shell will try to read or write
+the limit anyway, and will report an error if this fails.  As the shell
+does not store such resources internally, an attempt to set the limit will
+fail unless the tt(-s) option is present.
 
 var(limit) is a number, with an optional scaling factor, as follows:
 
@@ -1403,7 +1415,7 @@
 findex(ulimit)
 cindex(resource limits)
 cindex(limits, resource)
-item(tt(ulimit) [ tt(-SHacdflmnpstv) [ var(limit) ] ... ])(
+item(tt(ulimit) [ [ tt(-SHacdflmnpstv) | tt(-N) var(resource) [ var(limit) ] ... ])(
 Set or display resource limits of the shell and the processes started by
 the shell.  The value of var(limit) can be a number in the unit specified
 below or the value `tt(unlimited)'.  By default, only soft limits are
@@ -1415,6 +1427,10 @@
 printed.  When more than one resource values are printed the limit name and
 unit is printed before each value.
 
+When looping over multiple resources, the shell will abort immediately if
+it detects a badly formed argument.  However, if it fails to set a limit
+for some other reson it will continue trying to set the remaining limits.
+
 startsitem()
 sitem(tt(-a))(Lists all of the current resource limits.)
 sitem(tt(-c))(512-byte blocks on the size of core dumps.)
@@ -1429,6 +1445,16 @@
 sitem(tt(-v))(K-bytes on the size of virtual memory.  On some systems this
 refers to the limit called `address space'.)
 endsitem()
+
+A resource may also be specified by integer in the form `tt(-N)
+var(resource)', where var(resource) corresponds to the integer defined for
+the resource by the operating system.  This may be used to set the limits
+for resources known to the shell which do not correspond to option letters.
+Such limits will be shown by number in the output of `tt(ulimit -a)'.
+
+The number may alternatively be out of the range of limits compiled into
+the shell.  The shell will try to read or write the limit anyway, and
+will report an error if this fails.
 )
 findex(umask)
 cindex(umask)
Index: Src/Builtins/rlimits.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Builtins/rlimits.c,v
retrieving revision 1.11
diff -u -r1.11 rlimits.c
--- Src/Builtins/rlimits.c	2 Jun 2004 22:14:47 -0000	1.11
+++ Src/Builtins/rlimits.c	30 Jun 2004 10:01:32 -0000
@@ -78,57 +78,108 @@
     return ret;
 }
 
-/* Display resource limits.  hard indicates whether `hard' or `soft'  *
- * limits should be displayed.  lim specifies the limit, or may be -1 *
- * to show all.                                                       */
-
 /**/
 static void
-showlimits(int hard, int lim)
+showlimitvalue(int lim, rlim_t val)
 {
-    int rt;
-    rlim_t val;
-
-    /* main loop over resource types */
-    for (rt = 0; rt != ZSH_NLIMITS; rt++)
-	if (rt == lim || lim == -1) {
-	    /* display limit for resource number rt */
-	    printf("%-16s", recs[rt]);
-	    val = (hard) ? limits[rt].rlim_max : limits[rt].rlim_cur;
-	    if (val == RLIM_INFINITY)
-		printf("unlimited\n");
-	    else if (limtype[rt] == ZLIMTYPE_TIME) {
-		/* time-type resource -- display as hours, minutes and
-		seconds. */
-		printf("%d:%02d:%02d\n", (int)(val / 3600),
-		       (int)(val / 60) % 60, (int)(val % 60));
-	    } else if (limtype[rt] == ZLIMTYPE_NUMBER || limtype[rt] == ZLIMTYPE_UNKNOWN) {
-		/* pure numeric resource */
-		printf("%d\n", (int)val);
-	    } else if (val >= 1024L * 1024L)
-		/* memory resource -- display with `K' or `M' modifier */
+    /* display limit for resource number lim */
+    if (lim < ZSH_NLIMITS)
+	printf("%-16s", recs[lim]);
+    else
+    {
+	/* Unknown limit, hence unknown units. */
+	printf("%-16d", lim);
+    }
+    if (val == RLIM_INFINITY)
+	printf("unlimited\n");
+    else if (lim >= ZSH_NLIMITS)
+    {
 # ifdef RLIM_T_IS_QUAD_T
-		printf("%qdMB\n", val / (1024L * 1024L));
-	    else
-		printf("%qdkB\n", val / 1024L);
+	printf("%qd\n", val);
 # else
 #  ifdef RLIM_T_IS_LONG_LONG
-		printf("%lldMB\n", val / (1024L * 1024L));
-            else
-		printf("%lldkB\n", val / 1024L);
+	printf("%lld\n", val);
 #  else
 #   ifdef RLIM_T_IS_UNSIGNED
-		printf("%luMB\n", val / (1024L * 1024L));
-            else
-		printf("%lukB\n", val / 1024L);
+	printf("%lu\n", val);
 #   else
-		printf("%ldMB\n", val / (1024L * 1024L));
-            else
-		printf("%ldkB\n", val / 1024L);
+	printf("%ld\n", val);
 #   endif /* RLIM_T_IS_UNSIGNED */
 #  endif /* RLIM_T_IS_LONG_LONG */
 # endif /* RLIM_T_IS_QUAD_T */
+    }
+    else if (limtype[lim] == ZLIMTYPE_TIME) {
+	/* time-type resource -- display as hours, minutes and
+	   seconds. */
+	printf("%d:%02d:%02d\n", (int)(val / 3600),
+	       (int)(val / 60) % 60, (int)(val % 60));
+    } else if (limtype[lim] == ZLIMTYPE_NUMBER ||
+	       limtype[lim] == ZLIMTYPE_UNKNOWN) {
+	/* pure numeric resource */
+	printf("%d\n", (int)val);
+    } else if (val >= 1024L * 1024L)
+	/* memory resource -- display with `K' or `M' modifier */
+# ifdef RLIM_T_IS_QUAD_T
+	printf("%qdMB\n", val / (1024L * 1024L));
+    else
+	printf("%qdkB\n", val / 1024L);
+# else
+#  ifdef RLIM_T_IS_LONG_LONG
+    printf("%lldMB\n", val / (1024L * 1024L));
+    else
+	printf("%lldkB\n", val / 1024L);
+#  else
+#   ifdef RLIM_T_IS_UNSIGNED
+    printf("%luMB\n", val / (1024L * 1024L));
+    else
+	printf("%lukB\n", val / 1024L);
+#   else
+    printf("%ldMB\n", val / (1024L * 1024L));
+    else
+	printf("%ldkB\n", val / 1024L);
+#   endif /* RLIM_T_IS_UNSIGNED */
+#  endif /* RLIM_T_IS_LONG_LONG */
+# endif /* RLIM_T_IS_QUAD_T */
+}
+
+/* Display resource limits.  hard indicates whether `hard' or `soft'  *
+ * limits should be displayed.  lim specifies the limit, or may be -1 *
+ * to show all.                                                       */
+
+/**/
+static int
+showlimits(char *nam, int hard, int lim)
+{
+    int rt;
+
+    if (lim >= ZSH_NLIMITS)
+    {
+	/*
+	 * Not configured into the shell.  Ask the OS
+	 * explicitly for this limit.
+	 */
+	struct rlimit vals;
+	if (getrlimit(lim, &vals) < 0)
+	{
+	    zwarnnam(nam, "can't read limit: %e", NULL, errno);
+	    return 1;
 	}
+	showlimitvalue(lim, hard ? vals.rlim_max : vals.rlim_cur);
+    }
+    else if (lim != -1)
+    {
+	showlimitvalue(lim, hard ? limits[lim].rlim_max :
+		       limits[lim].rlim_cur);
+    }
+    else
+    {
+	/* main loop over resource types */
+	for (rt = 0; rt != ZSH_NLIMITS; rt++)
+	    showlimitvalue(rt, (hard) ? limits[rt].rlim_max :
+			   limits[rt].rlim_cur);
+    }
+
+    return 0;
 }
 
 /* Display a resource limit, in ulimit style.  lim specifies which   *
@@ -136,40 +187,52 @@
  * soft limit should be displayed.                                   */
 
 /**/
-static void
-printulimit(int lim, int hard, int head)
+static int
+printulimit(char *nam, int lim, int hard, int head)
 {
     rlim_t limit;
 
     /* get the limit in question */
-    limit = (hard) ? limits[lim].rlim_max : limits[lim].rlim_cur;
+    if (lim >= ZSH_NLIMITS)
+    {
+	struct rlimit vals;
+
+	if (getrlimit(lim, &vals) < 0)
+	{
+	    zwarnnam(nam, "can't read limit: %e", NULL, errno);
+	    return 1;
+	}
+	limit = (hard) ? vals.rlim_max : vals.rlim_cur;
+    }
+    else
+	limit = (hard) ? limits[lim].rlim_max : limits[lim].rlim_cur;
     /* display the appropriate heading */
     switch (lim) {
     case RLIMIT_CPU:
 	if (head)
-	    printf("cpu time (seconds)         ");
+	    printf("-t: cpu time (seconds)         ");
 	break;
     case RLIMIT_FSIZE:
 	if (head)
-	    printf("file size (blocks)         ");
+	    printf("-f: file size (blocks)         ");
 	if (limit != RLIM_INFINITY)
 	    limit /= 512;
 	break;
     case RLIMIT_DATA:
 	if (head)
-	    printf("data seg size (kbytes)     ");
+	    printf("-d: data seg size (kbytes)     ");
 	if (limit != RLIM_INFINITY)
 	    limit /= 1024;
 	break;
     case RLIMIT_STACK:
 	if (head)
-	    printf("stack size (kbytes)        ");
+	    printf("-s: stack size (kbytes)        ");
 	if (limit != RLIM_INFINITY)
 	    limit /= 1024;
 	break;
     case RLIMIT_CORE:
 	if (head)
-	    printf("core file size (blocks)    ");
+	    printf("-c: core file size (blocks)    ");
 	if (limit != RLIM_INFINITY)
 	    limit /= 512;
 	break;
@@ -178,7 +241,7 @@
 # if defined(HAVE_RLIMIT_RSS) && !defined(RLIMIT_VMEM_IS_RSS)
     case RLIMIT_RSS:
 	if (head)
-	    printf("resident set size (kbytes) ");
+	    printf("-m: resident set size (kbytes) ");
 	if (limit != RLIM_INFINITY)
 	    limit /= 1024;
 	break;
@@ -186,7 +249,7 @@
 # ifdef HAVE_RLIMIT_MEMLOCK
     case RLIMIT_MEMLOCK:
 	if (head)
-	    printf("locked-in-memory size (kb) ");
+	    printf("-l: locked-in-memory size (kb) ");
 	if (limit != RLIM_INFINITY)
 	    limit /= 1024;
 	break;
@@ -194,22 +257,22 @@
 # ifdef HAVE_RLIMIT_NPROC
     case RLIMIT_NPROC:
 	if (head)
-	    printf("processes                  ");
+	    printf("-u: processes                  ");
 	break;
 # endif /* HAVE_RLIMIT_NPROC */
 # ifdef HAVE_RLIMIT_NOFILE
     case RLIMIT_NOFILE:
 	if (head)
-	    printf("file descriptors           ");
+	    printf("-n: file descriptors           ");
 	break;
 # endif /* HAVE_RLIMIT_NOFILE */
 # ifdef HAVE_RLIMIT_VMEM
     case RLIMIT_VMEM:
 	if (head)
 #  if defined(HAVE_RLIMIT_RSS) && defined(RLIMIT_VMEM_IS_RSS)
-	    printf("memory size (kb)           ");
+	    printf("-m: memory size (kb)           ");
 #  else
-	    printf("virtual memory size (kb)   ");
+	    printf("-v: virtual memory size (kb)   ");
 #  endif
 	if (limit != RLIM_INFINITY)
 	    limit /= 1024;
@@ -218,7 +281,7 @@
 # if defined HAVE_RLIMIT_AS && !defined(RLIMIT_VMEM_IS_AS)
     case RLIMIT_AS:
 	if (head)
-	    printf("address space (kb)         ");
+	    printf("-v: address space (kb)         ");
 	if (limit != RLIM_INFINITY)
 	    limit /= 1024;
 	break;
@@ -226,19 +289,19 @@
 # ifdef HAVE_RLIMIT_TCACHE
     case RLIMIT_TCACHE:
 	if (head)
-	    printf("cached threads             ");
+	    printf("-N %2d: cached threads          ", RLIMIT_TCACHE);
 	break;
 # endif /* HAVE_RLIMIT_TCACHE */
 # ifdef HAVE_RLIMIT_AIO_OPS
     case RLIMIT_AIO_OPS:
 	if (head)
-	    printf("AIO operations             ");
+	    printf("-N %2d: AIO operations          ", RLIMIT_AIO_OPS);
 	break;
 # endif /* HAVE_RLIMIT_AIO_OPS */
 # ifdef HAVE_RLIMIT_AIO_MEM
     case RLIMIT_AIO_MEM:
 	if (head)
-	    printf("AIO locked-in-memory (kb)  ");
+	    printf("-N %2d: AIO locked-in-memory (kb) ", RLIMIT_AIO_MEM);
 	if (limit != RLIM_INFINITY)
 	    limit /= 1024;
 	break;
@@ -246,7 +309,7 @@
 # ifdef HAVE_RLIMIT_SBSIZE
     case RLIMIT_SBSIZE:
 	if (head)
-	    printf("socket buffer size (kb)    ");
+	    printf("-N %2d: socket buffer size (kb) ", RLIMIT_SBSIZE);
 	if (limit != RLIM_INFINITY)
 	    limit /= 1024;
 	break;
@@ -254,15 +317,19 @@
 # ifdef HAVE_RLIMIT_PTHREAD
     case RLIMIT_PTHREAD:
 	if (head)
-	    printf("threads per process        ");
+	    printf("-N %2d: threads per process     ", RLIMIT_PTHREAD);
 	break;
 # endif /* HAVE_RLIMIT_PTHREAD */
 # ifdef HAVE_RLIMIT_LOCKS
     case RLIMIT_LOCKS:
 	if (head)
-	    printf("file locks                 ");
+	    printf("-N %2d: file locks              ", RLIMIT_LOCKS);
 	break;
 # endif /* HAVE_RLIMIT_LOCKS */
+    default:
+	if (head)
+	    printf("-N %2d:                         ", lim);
+	break;
     }
     /* display the limit */
     if (limit == RLIM_INFINITY)
@@ -282,6 +349,93 @@
 #  endif /* RLIM_T_IS_LONG_LONG */
 # endif /* RLIM_T_IS_QUAD_T */
     }
+
+    return 0;
+}
+
+/**/
+static int
+do_limit(char *nam, int lim, rlim_t val, int hard, int soft, int set)
+{
+    if (lim >= ZSH_NLIMITS) {
+	struct rlimit vals;
+	if (getrlimit(lim, &vals) < 0)
+	{
+	    /* best guess about error */
+	    zwarnnam(nam, "can't read limit: %e", NULL, errno);
+	    return 1;
+	}
+	if (hard)
+	{
+	    if (val > vals.rlim_max && geteuid()) {
+		zwarnnam(nam, "can't raise hard limits", NULL, 0);
+		return 1;
+	    }
+	    vals.rlim_max = val;
+	    /*
+	     * not show if all systems will do this silently, but
+	     * best be safe...
+	     */
+	    if (val < vals.rlim_cur)
+		vals.rlim_cur = val;
+	}
+	if (soft || !hard) {
+	    if (val > vals.rlim_max) {
+		zwarnnam(nam, "limit exceeds hard limit", NULL, 0);
+		return 1;
+	    }
+	    else
+		vals.rlim_cur = val;
+	}
+	if (!set)
+	{
+	    zwarnnam(nam,
+		     "warning: unrecognised limit %d, use -s to set",
+		     NULL, lim);
+	    return 1;
+	}
+	else if (setrlimit(lim, &vals) < 0)
+	{
+	    zwarnnam(nam, "setrlimit failed: %e", NULL, errno);
+	    return 1;
+	}
+    } else {
+	/* new limit is valid and has been interpreted; apply it to the
+	specified resource */
+	if (hard) {
+	    /* can only raise hard limits if running as root */
+	    if (val > current_limits[lim].rlim_max && geteuid()) {
+		zwarnnam(nam, "can't raise hard limits", NULL, 0);
+		return 1;
+	    } else {
+		limits[lim].rlim_max = val;
+		if (val < limits[lim].rlim_cur)
+		    limits[lim].rlim_cur = val;
+	    }
+	}
+	if (soft || !hard) {
+	    if (val > limits[lim].rlim_max) {
+		/* no idea about this difference, don't intend to worry */
+		if (*nam == 'u')
+		{
+		    /* ulimit does this */
+		    if (val > current_limits[lim].rlim_max && geteuid()) {
+			zwarnnam(nam, "value exceeds hard limit", NULL, 0);
+			return 1;
+		    }
+		    limits[lim].rlim_max = limits[lim].rlim_cur = val;
+		} else {
+		    /* but limit does this */
+		    zwarnnam(nam, "limit exceeds hard limit", NULL, 0);
+		    return 1;
+		}
+	    } else
+		limits[lim].rlim_cur = val;
+	    if (set && zsetlimit(lim, "limit"))
+		return 1;
+	}
+    }
+    return 0;
 }
 
 /* limit: set or show resource limits.  The variable hard indicates *
@@ -289,7 +443,7 @@
 
 /**/
 static int
-bin_limit(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func))
+bin_limit(char *nam, char **argv, Options ops, UNUSED(int func))
 {
     char *s;
     int hard, limnum, lim;
@@ -300,35 +454,46 @@
     if (OPT_ISSET(ops,'s') && !*argv)
 	return setlimits(NULL);
     /* without arguments, display limits */
-    if (!*argv) {
-	showlimits(hard, -1);
-	return 0;
-    }
+    if (!*argv)
+	return showlimits(nam, hard, -1);
     while ((s = *argv++)) {
 	/* Search for the appropriate resource name.  When a name matches (i.e. *
 	 * starts with) the argument, the lim variable changes from -1 to the   *
 	 * number of the resource.  If another match is found, lim goes to -2.  */
-	for (lim = -1, limnum = 0; limnum < ZSH_NLIMITS; limnum++)
-	    if (!strncmp(recs[limnum], s, strlen(s))) {
-		if (lim != -1)
-		    lim = -2;
-		else
-		    lim = limnum;
-	    }
+	if (idigit(*s))
+	{
+	    lim = (int)zstrtol(s, NULL, 10);
+	}
+	else
+	    for (lim = -1, limnum = 0; limnum < ZSH_NLIMITS; limnum++)
+		if (!strncmp(recs[limnum], s, strlen(s))) {
+		    if (lim != -1)
+			lim = -2;
+		    else
+			lim = limnum;
+		}
 	/* lim==-1 indicates that no matches were found.       *
 	 * lim==-2 indicates that multiple matches were found. */
 	if (lim < 0) {
-	    zwarnnam("limit",
+	    zwarnnam(nam,
 		     (lim == -2) ? "ambiguous resource specification: %s"
 		     : "no such resource: %s", s, 0);
 	    return 1;
 	}
 	/* without value for limit, display the current limit */
-	if (!(s = *argv++)) {
-	    showlimits(hard, lim);
-	    return 0;
+	if (!(s = *argv++))
+	    return showlimits(nam, hard, lim);
+	if (lim >= ZSH_NLIMITS)
+	{
+	    val = zstrtorlimt(s, &s, 10);
+	    if (*s)
+	    {
+		/* unknown limit, no idea how to scale */
+		zwarnnam(nam, "unknown scaling factor: %s", s, 0);
+		return 1;
+	    }
 	}
-	if (limtype[lim] == ZLIMTYPE_TIME) {
+	else if (limtype[lim] == ZLIMTYPE_TIME) {
 	    /* time-type resource -- may be specified as seconds, or minutes or *
 	     * hours with the `m' and `h' modifiers, and `:' may be used to add *
 	     * together more than one of these.  It's easier to understand from *
@@ -342,7 +507,7 @@
 		else if (*s == ':')
 		    val = val * 60 + zstrtorlimt(s + 1, &s, 10);
 		else {
-		    zwarnnam("limit", "unknown scaling factor: %s", s, 0);
+		    zwarnnam(nam, "unknown scaling factor: %s", s, 0);
 		    return 1;
 		}
 	    }
@@ -352,7 +517,7 @@
 	    char *t = s;
 	    val = zstrtorlimt(t, &s, 10);
 	    if (s == t) {
-		zwarnnam("limit", "limit must be a number", NULL, 0);
+		zwarnnam(nam, "limit must be a number", NULL, 0);
 		return 1;
 	    }
 	} else {
@@ -365,31 +530,60 @@
 	    } else if ((*s == 'M' || *s == 'm') && !s[1])
 		val *= 1024L * 1024;
 	    else {
-		zwarnnam("limit", "unknown scaling factor: %s", s, 0);
+		zwarnnam(nam, "unknown scaling factor: %s", s, 0);
 		return 1;
 	    }
 	}
-	/* new limit is valid and has been interpreted; apply it to the
-	specified resource */
+	if (do_limit(nam, lim, val, hard, !hard, OPT_ISSET(ops, 's')))
+	    ret++;
+    }
+    return ret;
+}
+
+/**/
+static int
+do_unlimit(char *nam, int lim, int hard, int soft, int set, int euid)
+{
+    /* remove specified limit */
+    if (lim >= ZSH_NLIMITS) {
+	struct rlimit vals;
+	if (getrlimit(lim, &vals) < 0)
+	{
+	    zwarnnam(nam, "can't read limit: %e", NULL, errno);
+	    return 1;
+	}
 	if (hard) {
-	    /* can only raise hard limits if running as root */
-	    if (val > current_limits[lim].rlim_max && geteuid()) {
-		zwarnnam("limit", "can't raise hard limits", NULL, 0);
+	    if (euid && vals.rlim_max != RLIM_INFINITY) {
+		zwarnnam(nam, "can't remove hard limits", NULL, 0);
 		return 1;
-	    } else {
-		limits[lim].rlim_max = val;
-		if (val < limits[lim].rlim_cur)
-		    limits[lim].rlim_cur = val;
-	    }
-	} else if (val > limits[lim].rlim_max) {
-	    zwarnnam("limit", "limit exceeds hard limit", NULL, 0);
+	    } else
+		vals.rlim_max = RLIM_INFINITY;
+	}
+	if (!hard || soft)
+	    vals.rlim_cur = vals.rlim_max;
+	if (!set) {
+	    zwarnnam(nam,
+		     "warning: unrecognised limit %d, use -s to set",
+		     NULL, lim);
+	    return 1;
+	} else if (setrlimit(lim, &vals) < 0) {
+	    zwarnnam(nam, "setrlimit failed: %e", NULL, errno);
+	    return 1;
+	}
+    } else {
+	if (hard) {
+	    if (euid && current_limits[lim].rlim_max != RLIM_INFINITY) {
+		zwarnnam(nam, "can't remove hard limits", NULL, 0);
+		return 1;
+	    } else
+		limits[lim].rlim_max = RLIM_INFINITY;
+	}
+	if (!hard || soft)
+	    limits[lim].rlim_cur = limits[lim].rlim_max;
+	if (set && zsetlimit(lim, nam))
 	    return 1;
-	} else
-	    limits[lim].rlim_cur = val;
-	if (OPT_ISSET(ops,'s') && zsetlimit(lim, "limit"))
-	    ret++;
     }
-    return ret;
+    return 0;
 }
 
 /* unlimit: remove resource limits.  Much of this code is the same as *
@@ -425,13 +619,17 @@
 	     * matches (i.e. starts with) the argument, the lim variable  *
 	     * changes from -1 to the number of the resource.  If another *
 	     * match is found, lim goes to -2.                            */
-	    for (lim = -1, limnum = 0; limnum < ZSH_NLIMITS; limnum++)
-		if (!strncmp(recs[limnum], *argv, strlen(*argv))) {
-		    if (lim != -1)
-			lim = -2;
-		    else
-			lim = limnum;
-		}
+	    if (idigit(**argv)) {
+		lim = (int)zstrtol(*argv, NULL, 10);
+	    } else {
+		for (lim = -1, limnum = 0; limnum < ZSH_NLIMITS; limnum++)
+		    if (!strncmp(recs[limnum], *argv, strlen(*argv))) {
+			if (lim != -1)
+			    lim = -2;
+			else
+			    lim = limnum;
+		    }
+	    }
 	    /* lim==-1 indicates that no matches were found.       *
 	     * lim==-2 indicates that multiple matches were found. */
 	    if (lim < 0) {
@@ -440,16 +638,8 @@
 			 : "no such resource: %s", *argv, 0);
 		return 1;
 	    }
-	    /* remove specified limit */
-	    if (hard) {
-		if (euid && current_limits[lim].rlim_max != RLIM_INFINITY) {
-		    zwarnnam(nam, "can't remove hard limits", NULL, 0);
-		    ret++;
-		} else
-		    limits[lim].rlim_max = RLIM_INFINITY;
-	    } else
-		limits[lim].rlim_cur = limits[lim].rlim_max;
-	    if (OPT_ISSET(ops,'s') && zsetlimit(lim, nam))
+	    else if (do_unlimit(nam, lim, hard, !hard, OPT_ISSET(ops, 's'),
+				euid))
 		ret++;
 	}
     }
@@ -462,7 +652,7 @@
 static int
 bin_ulimit(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
 {
-    int res, resmask = 0, hard = 0, soft = 0, nres = 0, all = 0;
+    int res, resmask = 0, hard = 0, soft = 0, nres = 0, all = 0, ret = 0;
     char *options;
 
     do {
@@ -485,6 +675,22 @@
 		case 'S':
 		    soft = 1;
 		    continue;
+		case 'N':
+		    if (options[1]) {
+			res = (int)zstrtol(options+1, NULL, 10);
+		    } else if (*argv) {
+			res = (int)zstrtol(*argv++, NULL, 10);
+		    } else {
+			zwarnnam(name, "number required after -N",
+				 NULL, 0);
+			return 1;
+		    }
+		    /*
+		     * fake it so it looks like we just finished an option...
+		     */
+		    while (options[1])
+			options++;
+		    break;
 		case 'a':
 		    if (resmask) {
 			zwarnnam(name, "no limits allowed with -a",
@@ -606,50 +812,18 @@
 		limit *= 1024;
 		break;
 	    }
-	    if (hard) {
-		/* can't raise hard limit unless running as root */
-		if (limit > current_limits[res].rlim_max && geteuid()) {
-		    zwarnnam(name, "can't raise hard limits", NULL, 0);
-		    return 1;
-		}
-		limits[res].rlim_max = limit;
-		if (limit < limits[res].rlim_cur)
-		    limits[res].rlim_cur = limit;
-	    }
-	    if (!hard || soft) {
-		/* can't raise soft limit above hard limit */
-		if (limit > limits[res].rlim_max) {
-		    if (limit > current_limits[res].rlim_max && geteuid()) {
-			zwarnnam(name, "value exceeds hard limit", NULL, 0);
-			return 1;
-		    }
-		    limits[res].rlim_max = limits[res].rlim_cur = limit;
-		} else
-		    limits[res].rlim_cur = limit;
-	    }
+	    if (do_limit(name, res, limit, hard, soft, 1))
+		ret++;
 	} else {
-	    /* remove specified limit */
-	    if (hard) {
-		/* can't remove hard limit unless running as root */
-		if (current_limits[res].rlim_max != RLIM_INFINITY && geteuid()) {
-		    zwarnnam(name, "can't remove hard limits", NULL, 0);
-		    return 1;
-		}
-		limits[res].rlim_max = RLIM_INFINITY;
-	    }
-	    if (!hard || soft)
-		/* `removal' of soft limit means setting it equal to the
-		   corresponding hard limit */
-		limits[res].rlim_cur = limits[res].rlim_max;
+	    if (do_unlimit(name, res, hard, soft, 1, geteuid()))
+		ret++;
 	}
-	if (zsetlimit(res, name))
-	    return 1;
 	argv++;
     } while (*argv);
-    for (res = 0; res < RLIM_NLIMITS; res++, resmask >>= 1)
-	if (resmask & 1)
-	    printulimit(res, hard, nres > 1);
-    return 0;
+    for (res = 0; resmask; res++, resmask >>= 1)
+	if ((resmask & 1) && printulimit(name, res, hard, nres > 1))
+	    ret++;
+    return ret;
 }
 
 #else /* !HAVE_GETRLIMIT || !RLIM_INFINITY */

-- 
Peter Stephenson <pws@xxxxxxx>                  Software Engineer
CSR Ltd., Science Park, Milton Road,
Cambridge, CB4 0WH, UK                          Tel: +44 (0)1223 692070


**********************************************************************
This email and any files transmitted with it are confidential and
intended solely for the use of the individual or entity to whom they
are addressed. If you have received this email in error please notify
the system manager.

This footnote also confirms that this email message has been swept by
MIMEsweeper for the presence of computer viruses.

www.mimesweeper.com
**********************************************************************



Messages sorted by: Reverse Date, Date, Thread, Author