[PATCH 2/3] exporting capability code/name pairs (try 2nd)

From: Kohei KaiGai
Date: Fri Jan 25 2008 - 00:19:35 EST


We can apply this patch to libcap.
It enables to obtain the list of capabilities running kernel
supported dynamically, from /sys/kernel/capability.

When we use libcap with this patch on the previous kernel,
it apply static list of capabilities instead.

Thanks,
----
Signed-off-by: KaiGai Kohei <kaigai@xxxxxxxxxxxxx>

diff --git a/libcap/_makenames.c b/libcap/_makenames.c
index 212f0b4..c57e940 100644
--- a/libcap/_makenames.c
+++ b/libcap/_makenames.c
@@ -43,7 +43,7 @@ int main(void)
"#define __CAP_BITS %d\n"
"\n"
"#ifdef LIBCAP_PLEASE_INCLUDE_ARRAY\n"
- " char const *_cap_names[__CAP_BITS] = {\n", maxcaps);
+ " static const char *_cap_names_fallback[__CAP_BITS] = {\n", maxcaps);

for (i=0; i<maxcaps; ++i) {
if (pointers[i])
diff --git a/libcap/cap_flag.c b/libcap/cap_flag.c
index e521fcd..f490b29 100644
--- a/libcap/cap_flag.c
+++ b/libcap/cap_flag.c
@@ -21,7 +21,7 @@ int cap_get_flag(cap_t cap_d, cap_value_t value, cap_flag_t set,
* Is it a known capability?
*/

- if (raised && good_cap_t(cap_d) && value >= 0 && value < __CAP_BITS
+ if (raised && good_cap_t(cap_d) && value >= 0 && value < _cap_names_num
&& set >= 0 && set < NUMBER_OF_CAP_SETS) {
*raised = isset_cap(cap_d,value,set) ? CAP_SET:CAP_CLEAR;
return 0;
@@ -45,12 +45,12 @@ int cap_set_flag(cap_t cap_d, cap_flag_t set,
* Is it a known capability?
*/

- if (good_cap_t(cap_d) && no_values > 0 && no_values <= __CAP_BITS
+ if (good_cap_t(cap_d) && no_values > 0 && no_values <= _cap_names_num
&& (set >= 0) && (set < NUMBER_OF_CAP_SETS)
&& (raise == CAP_SET || raise == CAP_CLEAR) ) {
int i;
for (i=0; i<no_values; ++i) {
- if (array_values[i] < 0 || array_values[i] >= __CAP_BITS) {
+ if (array_values[i] < 0 || array_values[i] >= _cap_names_num) {
_cap_debug("weird capability (%d) - skipped", array_values[i]);
} else {
int value = array_values[i];
diff --git a/libcap/cap_text.c b/libcap/cap_text.c
index 06f61d9..7337bca 100644
--- a/libcap/cap_text.c
+++ b/libcap/cap_text.c
@@ -8,9 +8,11 @@

#define LIBCAP_PLEASE_INCLUDE_ARRAY
#include "libcap.h"
+#include "cap_names.h"

#include <ctype.h>
#include <stdio.h>
+#include <dirent.h>

/* Maximum output text length (16 per cap) */
#define CAP_TEXT_SIZE (16*__CAP_BITS)
@@ -19,6 +21,10 @@
#define LIBCAP_INH 02
#define LIBCAP_PER 04

+/* array of capability names initialized at _init() */
+int _cap_names_num = __CAP_BITS;
+char **_cap_names = _cap_names_fallback;
+
/*
* Parse a textual representation of capabilities, returning an internal
* representation.
@@ -71,14 +77,14 @@ static int lookupname(char const **strp)
str.constp = *strp;
if (isdigit(*str.constp)) {
unsigned long n = strtoul(str.constp, &str.p, 0);
- if (n >= __CAP_BITS)
+ if (n >= _cap_names_num)
return -1;
*strp = str.constp;
return n;
} else {
char const *s;
int n;
- for (n = __CAP_BITS; n--; )
+ for (n = _cap_names_num; n--; )
if (_cap_names[n] && (s = namcmp(str.constp, _cap_names[n]))) {
*strp = s;
return n;
@@ -270,7 +276,7 @@ char *cap_to_text(cap_t caps, ssize_t *length_p)
_cap_debugcap("i = ", *caps, CAP_INHERITABLE);
_cap_debugcap("p = ", *caps, CAP_PERMITTED);

- for (n = __CAP_BITS; n--; )
+ for (n = _cap_names_num; n--; )
histo[getstateflags(caps, n)]++;

for (m=t=7; t--; )
@@ -286,7 +292,7 @@ char *cap_to_text(cap_t caps, ssize_t *length_p)
for (t = 8; t--; )
if (t != m && histo[t]) {
*p++ = ' ';
- for (n = 0; n != __CAP_BITS; n++)
+ for (n = 0; n != _cap_names_num; n++)
if (getstateflags(caps, n) == t) {
if (_cap_names[n])
p += sprintf(p, "%s,", _cap_names[n]);
@@ -323,3 +329,66 @@ char *cap_to_text(cap_t caps, ssize_t *length_p)

return (_libcap_strdup(buf));
}
+
+#define SYSFS_CAP_BASE "/sys/kernel/capability"
+void __cap_names_init(void);
+void __attribute__ ((constructor)) __cap_names_init(void)
+{
+ DIR *dirp;
+ FILE *filp;
+ struct dirent *dent;
+ char pathname[256];
+ char **local_cap_names;
+ unsigned int i, code, local_cap_names_num;
+
+ /* compute size of array */
+ filp = fopen(SYSFS_CAP_BASE "/index", "rb");
+ if (!filp)
+ return;
+ if (fscanf(filp, "%u", &local_cap_names_num) != 1) {
+ fclose(filp);
+ return;
+ }
+ fclose(filp);
+
+ local_cap_names_num++;
+ local_cap_names = malloc(sizeof(char *) * local_cap_names_num);
+ if (!local_cap_names)
+ return;
+ memset(local_cap_names, 0, sizeof(char *) * local_cap_names_num);
+
+ /* scan /sys/kernel/capability */
+ dirp = opendir(SYSFS_CAP_BASE);
+ if (!dirp)
+ goto error1;
+
+ while (!!(dent = readdir(dirp))) {
+ if (!!strncmp("cap_", dent->d_name, 4))
+ continue;
+
+ snprintf(pathname, sizeof(pathname), SYSFS_CAP_BASE "/%s", dent->d_name);
+ filp = fopen(pathname, "rb");
+ if (!filp)
+ goto error2;
+ if (fscanf(filp, "%u", &code) != 1 || code >= local_cap_names_num) {
+ fclose(filp);
+ goto error2;
+ }
+ fclose(filp);
+
+ local_cap_names[code] = strdup(dent->d_name);
+ if (!local_cap_names[code])
+ goto error2;
+ }
+ _cap_names = local_cap_names;
+ _cap_names_num = local_cap_names_num;
+
+ error2:
+ for (i=0; i < local_cap_names_num; i++)
+ free(local_cap_names[i]);
+ closedir(dirp);
+ error1:
+ free(local_cap_names);
+
+ return;
+}
diff --git a/libcap/libcap.h b/libcap/libcap.h
index 0e4a167..b5a5deb 100644
--- a/libcap/libcap.h
+++ b/libcap/libcap.h
@@ -22,8 +22,8 @@
#define __u32 unsigned int
#endif /* __u32 */

-/* include the names for the caps and a definition of __CAP_BITS */
-#include "cap_names.h"
+extern char **_cap_names;
+extern int _cap_names_num;

/*
* Do we match the local kernel?

--
OSS Platform Development Division, NEC
KaiGai Kohei <kaigai@xxxxxxxxxxxxx>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/