sysdep.c (__gnat_has_cap_sys_nice): New function to determine whether the current...
authorBob Duff <duff@adacore.com>
Wed, 6 Sep 2017 10:49:05 +0000 (10:49 +0000)
committerArnaud Charlet <charlet@gcc.gnu.org>
Wed, 6 Sep 2017 10:49:05 +0000 (12:49 +0200)
2017-09-06  Bob Duff  <duff@adacore.com>

* sysdep.c (__gnat_has_cap_sys_nice): New function to determine
whether the current process has the CAP_SYS_NICE capability.
* s-taprop-linux.adb (Get_Ceiling_Support): Update this to allow
ceiling priorities if the current process has the CAP_SYS_NICE
capability.

From-SVN: r251777

gcc/ada/ChangeLog
gcc/ada/s-taprop-linux.adb
gcc/ada/sysdep.c

index 7a146be789c4a37b158a78e301ab90591d09b944..f914d23890113d249b8e2fa8711024ec6dd157ba 100644 (file)
@@ -1,3 +1,11 @@
+2017-09-06  Bob Duff  <duff@adacore.com>
+
+       * sysdep.c (__gnat_has_cap_sys_nice): New function to determine
+       whether the current process has the CAP_SYS_NICE capability.
+       * s-taprop-linux.adb (Get_Ceiling_Support): Update this to allow
+       ceiling priorities if the current process has the CAP_SYS_NICE
+       capability.
+
 2017-09-06  Bob Duff  <duff@adacore.com>
 
        * a-comlin.ads, a-comlin.adb (Argument): Move the constraint
index 1d829de6ee023d45e5af11bd975ea98183a33e20..cc49205cf0a5b769957f4e1e2a1af85102765ca8 100644 (file)
@@ -165,6 +165,13 @@ package body System.Task_Primitives.Operations is
    pragma Import
      (C, GNAT_pthread_condattr_setup, "__gnat_pthread_condattr_setup");
 
+   function GNAT_has_cap_sys_nice return C.int;
+   pragma Import
+     (C, GNAT_has_cap_sys_nice, "__gnat_has_cap_sys_nice");
+   --  We do not have pragma Linker_Options ("-lcap"); here, because this
+   --  library is not present on many Linux systems. 'libcap' is the Linux
+   --  "capabilities" library, called by __gnat_has_cap_sys_nice.
+
    function Prio_To_Linux_Prio (Prio : Any_Priority) return C.int is
      (C.int (Prio) + 1);
    --  Convert Ada priority to Linux priority. Priorities are 1 .. 99 on
@@ -172,24 +179,26 @@ package body System.Task_Primitives.Operations is
 
    function Get_Ceiling_Support return Boolean;
    --  Get the value of the Ceiling_Support constant (see below).
-   --  ???For now, we're returning True only if running as superuser,
-   --  and ignore capabilities.
+   --  Note well: If this function or related code is modified, it should be
+   --  tested by hand, because automated testing doesn't exercise it.
 
    function Get_Ceiling_Support return Boolean is
       Ceiling_Support : Boolean := False;
    begin
-      if Locking_Policy = 'C' then
-         declare
-            function geteuid return Integer;
-            pragma Import (C, geteuid, "geteuid");
-            Superuser : constant Boolean := geteuid = 0;
-         begin
-            if Superuser then
-               Ceiling_Support := True;
-            end if;
-         end;
+      if Locking_Policy /= 'C' then
+         return False;
       end if;
 
+      declare
+         function geteuid return Integer;
+         pragma Import (C, geteuid, "geteuid");
+         Superuser : constant Boolean := geteuid = 0;
+         Has_Cap : constant C.int := GNAT_has_cap_sys_nice;
+         pragma Assert (Has_Cap in 0 | 1);
+      begin
+         Ceiling_Support := Superuser or else Has_Cap = 1;
+      end;
+
       return Ceiling_Support;
    end Get_Ceiling_Support;
 
index 679c70a77f788eaff32233eb210805858b281342..64278fd8f38a3f8c3f0679379d614488112cd8a6 100644 (file)
@@ -6,7 +6,7 @@
  *                                                                          *
  *                          C Implementation File                           *
  *                                                                          *
- *         Copyright (C) 1992-2016, Free Software Foundation, Inc.          *
+ *         Copyright (C) 1992-2017, Free Software Foundation, Inc.          *
  *                                                                          *
  * GNAT is free software;  you can  redistribute it  and/or modify it under *
  * terms of the  GNU General Public License as published  by the Free Soft- *
@@ -919,6 +919,76 @@ __gnat_is_file_not_found_error (int errno_val) {
    }
 }
 
+#if defined (__linux__)
+
+/* HAVE_CAPABILITY is defined if sys/capability.h exists on the system where
+   this is being compiled.
+*/
+
+#if defined (HAVE_CAPABILITY)
+#include <sys/capability.h>
+
+/* Note well: If this code is modified, it should be tested by hand,
+   because automated testing doesn't exercise it.
+*/
+
+/* __gnat_has_cap_sys_nice returns 1 if the current process has the
+   CAP_SYS_NICE capability. This capability is necessary to use the
+   Ceiling_Locking policy. Returns 0 otherwise. Note that this is
+   defined only for Linux.
+*/
+
+/* Define these as weak symbols, so if support for capabilities is not present,
+   programs can still link. On Ubuntu, support for capabilities can be
+   installed via "sudo apt-get --assume-yes install libcap-dev".
+   In addition, the user must link with "-lcap", or else these
+   symbols will be 0, and __gnat_has_cap_sys_nice will return 0.
+*/
+
+static cap_t cap_get_proc_weak() __attribute__ ((weakref ("cap_get_proc")));
+static int cap_get_flag_weak() __attribute__ ((weakref ("cap_get_flag")));
+static int cap_free_weak() __attribute__ ((weakref ("cap_free")));
+
+int
+__gnat_has_cap_sys_nice () {
+  /* If the address of cap_get_proc_weak is 0, this means support for
+     capabilities is not present, so we return 0. */
+  if (&cap_get_proc_weak == 0)
+    return 0;
+
+  cap_t caps = cap_get_proc_weak();
+  cap_flag_value_t value;
+
+  if (caps == NULL)
+    return 0;
+
+  if (cap_get_flag_weak(caps, CAP_SYS_NICE, CAP_EFFECTIVE, &value) == -1)
+    return 0;
+
+  if (cap_free_weak(caps) == -1)
+    return 0;
+
+  if (value == CAP_SET)
+    return 1;
+
+  return 0;
+}
+
+#else
+
+/* HAVE_CAPABILITY is not defined, so sys/capability.h does not exist, so
+   simply indicate that the current process does not have the CAP_SYS_NICE
+   capability.
+*/
+
+int
+__gnat_has_cap_sys_nice () {
+  return 0;
+}
+
+#endif
+#endif
+
 #ifdef __ANDROID__
 
 /* Provide extern symbols for sig* as needed by the tasking run-time, instead