The 'nice' program should execute the given program even if the adjusted
niceness is too large. On GNU/Linux, for example, it is correctly
adjusted to the maximum niceness:

    $ /bin/nice -n +1000 /bin/nice
    19

On GNU/Hurd this does not occur, and a confusing error message is
printed instead:

     $ /bin/nice -n +100 /bin/nice 
     nice: cannot set niceness: No such process

This is because on GNU/Hurd the supported niceness ranges from 0 to 38
instead of -20 to 19 like on most other systems. This can be seen using
the following test program:

    $ cat main.c
    #define _GNU_SOURCE 1
    #include <stdio.h>
    #include <unistd.h>
    #include <errno.h>
    #include <string.h>
    #include <stdlib.h>
    int
    main (void)
    {
      errno = 0;
      int starting_nice = nice (0);
      if (starting_nice == -1 && errno != 0)
        {
          fprintf (stderr, "starting nice failed: %s\n",
                   strerror (errno));
          return EXIT_FAILURE;
        }
      int minimum_nice = starting_nice;
      for (;;)
        {
          errno = 0;
          int result = nice (-1);
          if (result == -1 && errno != 0)
            break;
          minimum_nice = result;
        }
      int minimum_errno = errno;
      int maximum_nice = minimum_nice;
      for (;;)
        {
          errno = 0;
          int result = nice (1);
          if (result == -1 && errno != 0)
            break;
          maximum_nice = result;
        }
      int maximum_errno = errno;
      printf ("starting nice: %d\n", starting_nice);
      printf ("minimum nice: %d\n", minimum_nice);
      printf ("maximum nice: %d\n", maximum_nice);
      printf ("minimum errno: %s\n", strerrorname_np (minimum_errno));
      printf ("maximum errno: %s\n", strerrorname_np (maximum_errno));
      return EXIT_FAILURE;
    }

That test program assumes that nice() does not clamp the niceness to the
supported range as it is supposed to [1]. This is the case on GNU/Hurd,
so I will submit a bug report for that later.

The output is the same on a normal and privileged user:

    $ gcc main.c ./a.out 
    starting nice: 0
    minimum nice: 0
    maximum nice: 38
    minimum errno: EPERM
    maximum errno: ESRCH

This patch clamps it to the supported range and adds some tests. Here is
the corrected behavior:

    $ ./src/nice -n +100 ./src/nice
    38

Collin

[1] https://pubs.opengroup.org/onlinepubs/9799919799/functions/nice.html

>From ee66dca4af75493687d3fc831d2cd0dea9451728 Mon Sep 17 00:00:00 2001
Message-ID: <ee66dca4af75493687d3fc831d2cd0dea9451728.1762665726.git.collin.fu...@gmail.com>
From: Collin Funk <[email protected]>
Date: Sat, 8 Nov 2025 20:30:08 -0800
Subject: [PATCH] nice: clamp the niceness correctly on GNU/Hurd

* NEWS: Mention the bug fix.
* src/nice.c (MIN_ADJUSTMENT): Set to 0 on the Hurd.
(MAX_ADJUSTMENT): Set to 38 on the Hurd.
* tests/nice/nice.sh: Add some tests for the Hurd's ranges.
---
 NEWS               |  4 ++++
 src/nice.c         |  5 +++++
 tests/nice/nice.sh | 32 ++++++++++++++++++++++----------
 3 files changed, 31 insertions(+), 10 deletions(-)

diff --git a/NEWS b/NEWS
index 7e7dc6376..46df91b62 100644
--- a/NEWS
+++ b/NEWS
@@ -26,6 +26,10 @@ GNU coreutils NEWS                                    -*- outline -*-
   will no longer always set a __CF_USER_TEXT_ENCODING environment variable.
   [bug introduced in coreutils-9.8]
 
+  'nice' now limits the adjusted niceness value to its supported range on
+  GNU/Hurd.
+  [This bug was present in "the beginning".]
+
   'numfmt' no longer reads out-of-bounds memory with trailing blanks in input.
   [bug introduced with numfmt in coreutils-8.21]
 
diff --git a/src/nice.c b/src/nice.c
index 1c3f2a038..a7cdbbdc2 100644
--- a/src/nice.c
+++ b/src/nice.c
@@ -167,7 +167,12 @@ main (int argc, char **argv)
       /* If the requested adjustment is outside the valid range,
          silently bring it to just within range; this mimics what
          "setpriority" and "nice" do.  */
+#ifdef __gnu_hurd__
+      /* GNU/Hurd's range is 0 to 38.  */
+      enum { MIN_ADJUSTMENT = 0, MAX_ADJUSTMENT = 38 };
+#else
       enum { MIN_ADJUSTMENT = 1 - 2 * NZERO, MAX_ADJUSTMENT = 2 * NZERO - 1 };
+#endif
       long int tmp;
       if (LONGINT_OVERFLOW < xstrtol (adjustment_given, nullptr, 10, &tmp, ""))
         error (EXIT_CANCELED, 0, _("invalid adjustment %s"),
diff --git a/tests/nice/nice.sh b/tests/nice/nice.sh
index 7e274ca0d..9c42e3054 100755
--- a/tests/nice/nice.sh
+++ b/tests/nice/nice.sh
@@ -71,16 +71,28 @@ done
 
 # Test negative niceness - command must be run whether or not change happens.
 if test x$(nice -n -1 nice 2> /dev/null) = x0 ; then
-  # unprivileged user - warn about failure to change
-  nice -n -1 true 2> err || fail=1
-  compare /dev/null err && fail=1
-  mv err exp || framework_failure_
-  nice --1 true 2> err || fail=1
-  compare exp err || fail=1
-  # Failure to write advisory message is fatal.  Buggy through coreutils 8.0.
-  if test -w /dev/full && test -c /dev/full; then
-    returns_ 125 nice -n -1 nice > out 2> /dev/full || fail=1
-    compare /dev/null out || fail=1
+  # GNU/Hurd does not allow negative niceness even if we are privileged user.
+  if test "$(uname)" = GNU; then
+    # Check that the lowest niceness is 0.
+    nice -n -1 nice > out || fail=1
+    echo '0' > exp || framework_failure_
+    compare exp out || fail=1
+    # Check that the highest niceness is 38.
+    nice -n 39 nice > out || fail=1
+    echo '38' > exp || framework_failure_
+    compare exp out || fail=1
+  else
+    # unprivileged user - warn about failure to change
+    nice -n -1 true 2> err || fail=1
+    compare /dev/null err && fail=1
+    mv err exp || framework_failure_
+    nice --1 true 2> err || fail=1
+    compare exp err || fail=1
+    # Failure to write advisory message is fatal.  Buggy through coreutils 8.0.
+    if test "$(uname)" != GNU && test -w /dev/full && test -c /dev/full; then
+      returns_ 125 nice -n -1 nice > out 2> /dev/full || fail=1
+      compare /dev/null out || fail=1
+    fi
   fi
 else
   # superuser - change succeeds
-- 
2.51.1

Reply via email to