summaryrefslogtreecommitdiff
path: root/src/procenv.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/procenv.c')
-rw-r--r--src/procenv.c7909
1 files changed, 6839 insertions, 1070 deletions
diff --git a/src/procenv.c b/src/procenv.c
index a1c17cc..966eef5 100644
--- a/src/procenv.c
+++ b/src/procenv.c
@@ -4,12 +4,12 @@
*
* Date: 24 October 2012.
*
- * Author: James Hunt <james.hunt@ubuntu.com>.
+ * Author: James Hunt <jamesodhunt@ubuntu.com>.
*
* Licence: GPLv3. See below...
*--------------------------------------------------------------------
*
- * Copyright 2012-2013 James Hunt.
+ * Copyright © 2012-2015 James Hunt <jamesodhunt@ubuntu.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,7 +28,12 @@
#include <procenv.h>
-extern char **environ;
+/**
+ * doc:
+ *
+ * The output document in wide-character format.
+ **/
+pstring *doc = NULL;
/**
* output:
@@ -38,6 +43,13 @@ extern char **environ;
Output output = OUTPUT_STDOUT;
/**
+ * output_format:
+ *
+ * Format output will be displayed in.
+ **/
+OutputFormat output_format = OUTPUT_FORMAT_TEXT;
+
+/**
* output_file:
*
* Name or output file to send output to if not NULL.
@@ -45,6 +57,22 @@ Output output = OUTPUT_STDOUT;
const char *output_file = NULL;
/**
+ * text_separator:
+ *
+ * Separator used for text output format to separate a name from a
+ * value.
+ **/
+const char *text_separator = PROCENV_DEFAULT_TEXT_SEPARATOR;
+
+/**
+ * crumb_separator:
+ *
+ * Separator used for text output format to separate a name from a
+ * value.
+ **/
+const char *crumb_separator = PROCENV_DEFAULT_CRUMB_SEPARATOR;
+
+/**
* output_fd:
*
* File descriptor associated with output_file.
@@ -70,11 +98,26 @@ int selected_option = 0;
/**
* indent:
*
- * Number of spaces to indent output.
+ * Current output indent value.
**/
int indent = 0;
/**
+ * indent_amount:
+ *
+ * Number of INDENT_CHARs to emit for an indent.
+ **/
+int indent_amount = DEFAULT_INDENT_AMOUNT;
+
+/**
+ * indent_char, wide_indent_char:
+ *
+ * Character to use for indenting and wide-char equivalent.
+ **/
+const char *indent_char = DEFAULT_INDENT_CHAR;
+wchar_t wide_indent_char;
+
+/**
* program_name:
*
* Name of program.
@@ -94,13 +137,35 @@ char **exec_args = NULL;
char **argvp = NULL;
int argvc = 0;
+/**
+ * Locale in effect at program startup.
+ **/
+char *saved_locale = NULL;
+
+/**
+ * last_element: Type of previous element handled.
+ **/
+ElementType last_element = ELEMENT_TYPE_NONE;
+
+/**
+ * current_element: Type of element currently being handled.
+ **/
+ElementType current_element = ELEMENT_TYPE_NONE;
+
+/**
+ * crumb_list:
+ *
+ * List used to store breadcrumbs when OUTPUT_FORMAT_CRUMB being used.
+ **/
+static PRList *crumb_list = NULL;
+
struct procenv_user user;
struct procenv_misc misc;
struct procenv_priority priority;
struct utsname uts;
-#if defined (PROCENV_BSD) || defined (__FreeBSD_kernel__)
+#if defined (PROCENV_BSD) || defined (PROCENV_GNU_BSD)
struct mntopt_map {
uint64_t flag;
char *name;
@@ -112,7 +177,7 @@ struct mntopt_map {
{ MNT_GJOURNAL , "gjournal" },
{ MNT_LOCAL , "local" },
{ MNT_MULTILABEL , "multilabel" },
-#ifndef __FreeBSD_kernel__
+#ifndef PROCENV_GNU_BSD
{ MNT_NFS4ACLS , "nfsv4acls" },
#endif
{ MNT_NOATIME , "noatime" },
@@ -125,7 +190,7 @@ struct mntopt_map {
{ MNT_RDONLY , "read-only" },
{ MNT_SOFTDEP , "soft-updates" },
{ MNT_SUIDDIR , "suiddir" },
-#ifndef __FreeBSD_kernel__
+#if ! defined (PROCENV_GNU_BSD) && defined (MNT_SUJ)
{ MNT_SUJ , "journaled soft-updates" },
#endif
{ MNT_SYNCHRONOUS , "synchronous" },
@@ -145,6 +210,15 @@ struct procenv_map output_map[] = {
{ 0, NULL }
};
+struct procenv_map output_format_map[] = {
+ { OUTPUT_FORMAT_TEXT, "text" },
+ { OUTPUT_FORMAT_CRUMB, "crumb" },
+ { OUTPUT_FORMAT_JSON, "json" },
+ { OUTPUT_FORMAT_XML, "xml" },
+
+ { 0, NULL }
+};
+
struct baud_speed baud_speeds[] = {
SPEED (B0),
SPEED (B50),
@@ -194,7 +268,7 @@ struct if_flag_map {
mk_map_entry (IFF_SLAVE),
#endif
-#if defined (PROCENV_BSD) || defined (__FreeBSD_kernel__)
+#if defined (PROCENV_BSD) || defined (PROCENV_GNU_BSD)
mk_map_entry (IFF_SIMPLEX),
#endif
@@ -206,30 +280,149 @@ struct if_flag_map {
mk_map_entry (IFF_DYNAMIC),
mk_map_entry (IFF_LOWER_UP),
mk_map_entry (IFF_DORMANT),
+# ifdef IFF_ECHO
mk_map_entry (IFF_ECHO),
+# endif
#endif
{ 0, NULL }
};
+/*
+ * Note the gross hack to avoid need for flexible arrays.
+ */
+TranslateTable translate_table[] = {
+ {
+ OUTPUT_FORMAT_XML,
+ {
+ { L'\'', L"&apos;" },
+ { L'"', L"&quot;" },
+ { L'&', L"&amp;" },
+ { L'<', L"&lt;" },
+ { L'>', L"&gt;" },
+
+ /* terminator */
+ { L'\0', NULL }
+ }
+ },
+ {
+ OUTPUT_FORMAT_JSON,
+ {
+ { L'"', L"\\\"" },
+ { L'\\', L"\\\\" },
+
+ /* hack! */
+ { L'\0', NULL },
+ { L'\0', NULL },
+ { L'\0', NULL },
+
+ /* terminator */
+ { L'\0', NULL }
+ }
+ },
+};
+
#if defined (PROCENV_LINUX)
struct if_extended_flag_map {
unsigned int flag;
char *name;
} if_extended_flag_map[] = {
+#if defined (IFF_802_1Q_VLAN)
mk_map_entry (IFF_802_1Q_VLAN),
+#endif
+#if defined (IFF_EBRIDGE)
mk_map_entry (IFF_EBRIDGE),
+#endif
+#if defined (IFF_SLAVE_INACTIVE)
mk_map_entry (IFF_SLAVE_INACTIVE),
+#endif
+#if defined (IFF_MASTER_8023AD)
mk_map_entry (IFF_MASTER_8023AD),
+#endif
+#if defined (IFF_MASTER_ALB)
mk_map_entry (IFF_MASTER_ALB),
+#endif
+#if defined (IFF_BONDING)
mk_map_entry (IFF_BONDING),
+#endif
+#if defined (IFF_SLAVE_NEEDARP)
mk_map_entry (IFF_SLAVE_NEEDARP),
+#endif
+#if defined (IFF_ISATAP)
mk_map_entry (IFF_ISATAP),
+#endif
+ { 0, NULL }
+};
+
+struct personality_map {
+ unsigned int personality;
+ char *name;
+} personality_map[] = {
+ mk_map_entry (PER_LINUX),
+ mk_map_entry (PER_LINUX_32BIT),
+ mk_map_entry (PER_SVR4),
+ mk_map_entry (PER_SVR3),
+ mk_map_entry (PER_SCOSVR3),
+ mk_map_entry (PER_OSR5),
+ mk_map_entry (PER_WYSEV386),
+ mk_map_entry (PER_ISCR4),
+ mk_map_entry (PER_BSD),
+ mk_map_entry (PER_SUNOS),
+ mk_map_entry (PER_XENIX),
+#if defined (PER_LINUX32)
+ mk_map_entry (PER_LINUX32),
+#endif
+#if defined (PER_LINUX32_3GB)
+ mk_map_entry (PER_LINUX32_3GB),
+#endif
+ mk_map_entry (PER_IRIX32),
+ mk_map_entry (PER_IRIXN32),
+ mk_map_entry (PER_IRIX64),
+ mk_map_entry (PER_RISCOS),
+ mk_map_entry (PER_SOLARIS),
+ mk_map_entry (PER_UW7),
+ mk_map_entry (PER_OSF4),
+ mk_map_entry (PER_HPUX),
{ 0, NULL }
};
+
+struct personality_flag_map {
+ unsigned int flag;
+ char *name;
+} personality_flag_map[] = {
+#if defined (ADDR_COMPAT_LAYOUT)
+ mk_map_entry (ADDR_COMPAT_LAYOUT),
+#endif
+#if defined (ADDR_LIMIT_32BIT)
+ mk_map_entry (ADDR_LIMIT_32BIT),
+#endif
+#if defined (ADDR_LIMIT_3GB)
+ mk_map_entry (ADDR_LIMIT_3GB),
+#endif
+#if defined (ADDR_NO_RANDOMIZE)
+ mk_map_entry (ADDR_NO_RANDOMIZE),
+#endif
+#if defined (MMAP_PAGE_ZERO)
+ mk_map_entry (MMAP_PAGE_ZERO),
+#endif
+#if defined (READ_IMPLIES_EXEC)
+ mk_map_entry (READ_IMPLIES_EXEC),
+#endif
+#if defined (SHORT_INODE)
+ mk_map_entry (SHORT_INODE),
#endif
+#if defined (STICKY_TIMEOUTS)
+ mk_map_entry (STICKY_TIMEOUTS),
+#endif
+#if defined (WHOLE_SECONDS)
+ mk_map_entry (WHOLE_SECONDS),
+#endif
+
+ { 0, NULL }
+};
+#endif
/* Really, every single sysconf variable should be ifdef'ed since it
* may not exist on a particular system, but that makes the code look
@@ -240,160 +433,850 @@ struct if_extended_flag_map {
* sigh...
*/
struct procenv_map sysconf_map[] = {
- mk_posix_sysconf_map_entry (ARG_MAX),
- mk_posix_sysconf_map_entry (BC_BASE_MAX),
- mk_posix_sysconf_map_entry (BC_DIM_MAX),
- mk_posix_sysconf_map_entry (BC_SCALE_MAX),
- mk_posix_sysconf_map_entry (BC_STRING_MAX),
- mk_posix_sysconf_map_entry (CHILD_MAX),
- mk_sysconf_map_entry (_SC_CLK_TCK),
- mk_posix_sysconf_map_entry (COLL_WEIGHTS_MAX),
- mk_posix_sysconf_map_entry (EXPR_NEST_MAX),
-#if defined (_SC_HOST_NAME_MAX)
- mk_posix_sysconf_map_entry (HOST_NAME_MAX),
-#endif
- mk_posix_sysconf_map_entry (LINE_MAX),
- mk_posix_sysconf_map_entry (LOGIN_NAME_MAX),
- mk_posix_sysconf_map_entry (OPEN_MAX),
- mk_posix_sysconf_map_entry (PAGESIZE),
- mk_posix_sysconf_map_entry (RE_DUP_MAX),
- mk_posix_sysconf_map_entry (STREAM_MAX),
-#if defined (_SC_SYMLOOP_MAX)
- mk_posix_sysconf_map_entry (SYMLOOP_MAX),
+
+#if defined (_SC_2_C_BIND)
+ mk_sysconf_map_entry (_SC_2_C_BIND),
#endif
- mk_posix_sysconf_map_entry (TTY_NAME_MAX),
- mk_posix_sysconf_map_entry (TZNAME_MAX),
- { _SC_VERSION, "_POSIX_VERSION(_SC_VERSION)" },
-#if defined (_SC_POSIX2_C_DEV)
- mk_posix_sysconf_map_entry (POSIX2_C_DEV),
-#endif
- mk_posix_sysconf_map_entry (BC_BASE_MAX),
- mk_posix_sysconf_map_entry (BC_DIM_MAX),
- mk_posix_sysconf_map_entry (BC_SCALE_MAX),
- mk_posix_sysconf_map_entry (BC_STRING_MAX),
- mk_posix_sysconf_map_entry (COLL_WEIGHTS_MAX),
- mk_posix_sysconf_map_entry (EXPR_NEST_MAX),
- mk_posix_sysconf_map_entry (LINE_MAX),
- mk_posix_sysconf_map_entry (RE_DUP_MAX),
- { _SC_2_VERSION, "POSIX2_VERSION(_SC_2_VERSION)" },
- { _SC_2_C_DEV, "POSIX2_C_DEV(_SC_2_C_DEV)" },
- { _SC_2_FORT_DEV, "POSIX2_FORT_DEV(_SC_2_FORT_DEV)" },
- { _SC_2_FORT_RUN, "POSIX2_FORT_RUN(_SC_2_FORT_RUN)" },
- { _SC_2_LOCALEDEF, "_POSIX2_LOCALEDEF(_SC_2_LOCALEDEF)" },
- { _SC_2_SW_DEV, "POSIX2_SW_DEV(_SC_2_SW_DEV)" },
- mk_sysconf_map_entry (_SC_PHYS_PAGES),
-#if defined (_SC_AVPHYS_PAGES)
- mk_sysconf_map_entry (_SC_AVPHYS_PAGES),
+
+#if defined (_SC_2_C_DEV)
+ mk_sysconf_map_entry (_SC_2_C_DEV),
+#endif
+
+#if defined (_SC_2_CHAR_TERM)
+ mk_sysconf_map_entry (_SC_2_CHAR_TERM),
+#endif
+
+#if defined (_SC_2_C_VERSION)
+ mk_sysconf_map_entry (_SC_2_C_VERSION),
+#endif
+
+#if defined (_SC_2_FORT_DEV)
+ mk_sysconf_map_entry (_SC_2_FORT_DEV),
+#endif
+
+#if defined (_SC_2_FORT_RUN)
+ mk_sysconf_map_entry (_SC_2_FORT_RUN),
+#endif
+
+#if defined (_SC_2_LOCALEDEF)
+ mk_sysconf_map_entry (_SC_2_LOCALEDEF),
+#endif
+
+#if defined (_SC_2_PBS)
+ mk_sysconf_map_entry (_SC_2_PBS),
+#endif
+
+#if defined (_SC_2_PBS_ACCOUNTING)
+ mk_sysconf_map_entry (_SC_2_PBS_ACCOUNTING),
+#endif
+
+#if defined (_SC_2_PBS_LOCATE)
+ mk_sysconf_map_entry (_SC_2_PBS_LOCATE),
+#endif
+
+#if defined (_SC_2_PBS_MESSAGE)
+ mk_sysconf_map_entry (_SC_2_PBS_MESSAGE),
+#endif
+
+#if defined (_SC_2_PBS_TRACK)
+ mk_sysconf_map_entry (_SC_2_PBS_TRACK),
+#endif
+
+#if defined (_SC_2_SW_DEV)
+ mk_sysconf_map_entry (_SC_2_SW_DEV),
+#endif
+
+#if defined (_SC_2_UPE)
+ mk_sysconf_map_entry (_SC_2_UPE),
+#endif
+
+#if defined (_SC_2_VERSION)
+ mk_sysconf_map_entry (_SC_2_VERSION),
#endif
- mk_sysconf_map_entry (_SC_NPROCESSORS_CONF),
- mk_sysconf_map_entry (_SC_NPROCESSORS_ONLN),
#if defined (_SC_ADVISORY_INFO)
- mk_posixopt_sysconf_map_entry (ADVISORY_INFO),
+ mk_sysconf_map_entry (_SC_ADVISORY_INFO),
+#endif
+
+#if defined (_SC_AIO_LISTIO_MAX)
+ mk_sysconf_map_entry (_SC_AIO_LISTIO_MAX),
+#endif
+
+#if defined (_SC_AIO_MAX)
+ mk_sysconf_map_entry (_SC_AIO_MAX),
#endif
- mk_posixopt_sysconf_map_entry (ASYNCHRONOUS_IO),
+
+#if defined (_SC_AIO_PRIO_DELTA_MAX)
+ mk_sysconf_map_entry (_SC_AIO_PRIO_DELTA_MAX),
+#endif
+
+#if defined (_SC_ARG_MAX)
+ mk_sysconf_map_entry (_SC_ARG_MAX),
+#endif
+
+#if defined (_SC_ASYNCHRONOUS_IO)
+ mk_sysconf_map_entry (_SC_ASYNCHRONOUS_IO),
+#endif
+
+#if defined (_SC_ATEXIT_MAX)
+ mk_sysconf_map_entry (_SC_ATEXIT_MAX),
+#endif
+
+#if defined (_SC_AVPHYS_PAGES)
+ mk_sysconf_map_entry (_SC_AVPHYS_PAGES),
+#endif
+
#if defined (_SC_BARRIERS)
- mk_posixopt_sysconf_map_entry (BARRIERS),
+ mk_sysconf_map_entry (_SC_BARRIERS),
+#endif
+
+#if defined (_SC_BASE)
+ mk_sysconf_map_entry (_SC_BASE),
#endif
-#if defined (_POSIX_CHOWN_RESTRICTED)
- mk_sysconf_map_entry (_POSIX_CHOWN_RESTRICTED),
+
+#if defined (_SC_BC_BASE_MAX)
+ mk_sysconf_map_entry (_SC_BC_BASE_MAX),
+#endif
+
+#if defined (_SC_BC_DIM_MAX)
+ mk_sysconf_map_entry (_SC_BC_DIM_MAX),
#endif
+
+#if defined (_SC_BC_SCALE_MAX)
+ mk_sysconf_map_entry (_SC_BC_SCALE_MAX),
+#endif
+
+#if defined (_SC_BC_STRING_MAX)
+ mk_sysconf_map_entry (_SC_BC_STRING_MAX),
+#endif
+
+#if defined (_SC_CHAR_BIT)
+ mk_sysconf_map_entry (_SC_CHAR_BIT),
+#endif
+
+#if defined (_SC_CHARCLASS_NAME_MAX)
+ mk_sysconf_map_entry (_SC_CHARCLASS_NAME_MAX),
+#endif
+
+#if defined (_SC_CHAR_MAX)
+ mk_sysconf_map_entry (_SC_CHAR_MAX),
+#endif
+
+#if defined (_SC_CHAR_MIN)
+ mk_sysconf_map_entry (_SC_CHAR_MIN),
+#endif
+
+#if defined (_SC_CHILD_MAX)
+ mk_sysconf_map_entry (_SC_CHILD_MAX),
+#endif
+
+#if defined (_SC_C_LANG_SUPPORT)
+ mk_sysconf_map_entry (_SC_C_LANG_SUPPORT),
+#endif
+
+#if defined (_SC_C_LANG_SUPPORT_R)
+ mk_sysconf_map_entry (_SC_C_LANG_SUPPORT_R),
+#endif
+
+#if defined (_SC_CLK_TCK)
+ mk_sysconf_map_entry (_SC_CLK_TCK),
+#endif
+
#if defined (_SC_CLOCK_SELECTION)
- mk_posixopt_sysconf_map_entry (CLOCK_SELECTION),
+ mk_sysconf_map_entry (_SC_CLOCK_SELECTION),
#endif
+
+#if defined (_SC_COLL_WEIGHTS_MAX)
+ mk_sysconf_map_entry (_SC_COLL_WEIGHTS_MAX),
+#endif
+
#if defined (_SC_CPUTIME)
- mk_posixopt_sysconf_map_entry (CPUTIME),
+ mk_sysconf_map_entry (_SC_CPUTIME),
+#endif
+
+#if defined (_SC_DELAYTIMER_MAX)
+ mk_sysconf_map_entry (_SC_DELAYTIMER_MAX),
+#endif
+
+#if defined (_SC_DEVICE_IO)
+ mk_sysconf_map_entry (_SC_DEVICE_IO),
+#endif
+
+#if defined (_SC_DEVICE_SPECIFIC)
+ mk_sysconf_map_entry (_SC_DEVICE_SPECIFIC),
+#endif
+
+#if defined (_SC_DEVICE_SPECIFIC_R)
+ mk_sysconf_map_entry (_SC_DEVICE_SPECIFIC_R),
+#endif
+
+#if defined (_SC_EQUIV_CLASS_MAX)
+ mk_sysconf_map_entry (_SC_EQUIV_CLASS_MAX),
+#endif
+
+#if defined (_SC_EXPR_NEST_MAX)
+ mk_sysconf_map_entry (_SC_EXPR_NEST_MAX),
#endif
+
+#if defined (_SC_FD_MGMT)
+ mk_sysconf_map_entry (_SC_FD_MGMT),
+#endif
+
+#if defined (_SC_FIFO)
+ mk_sysconf_map_entry (_SC_FIFO),
+#endif
+
+#if defined (_SC_FILE_ATTRIBUTES)
+ mk_sysconf_map_entry (_SC_FILE_ATTRIBUTES),
+#endif
+
#if defined (_SC_FILE_LOCKING)
- mk_posixopt_sysconf_map_entry (FILE_LOCKING),
-#endif
- mk_posixopt_sysconf_map_entry (FSYNC),
- mk_posixopt_sysconf_map_entry (JOB_CONTROL),
- mk_posixopt_sysconf_map_entry (MAPPED_FILES),
- mk_posixopt_sysconf_map_entry (MEMLOCK),
- mk_posixopt_sysconf_map_entry (MEMLOCK_RANGE),
- mk_posixopt_sysconf_map_entry (MEMORY_PROTECTION),
- mk_posixopt_sysconf_map_entry (MESSAGE_PASSING),
+ mk_sysconf_map_entry (_SC_FILE_LOCKING),
+#endif
+
+#if defined (_SC_FILE_SYSTEM)
+ mk_sysconf_map_entry (_SC_FILE_SYSTEM),
+#endif
+
+#if defined (_SC_FSYNC)
+ mk_sysconf_map_entry (_SC_FSYNC),
+#endif
+
+#if defined (_SC_GETGR_R_SIZE_MAX)
+ mk_sysconf_map_entry (_SC_GETGR_R_SIZE_MAX),
+#endif
+
+#if defined (_SC_GETPW_R_SIZE_MAX)
+ mk_sysconf_map_entry (_SC_GETPW_R_SIZE_MAX),
+#endif
+
+#if defined (_SC_HOST_NAME_MAX)
+ mk_sysconf_map_entry (_SC_HOST_NAME_MAX),
+#endif
+
+#if defined (_SC_INT_MAX)
+ mk_sysconf_map_entry (_SC_INT_MAX),
+#endif
+
+#if defined (_SC_INT_MIN)
+ mk_sysconf_map_entry (_SC_INT_MIN),
+#endif
+
+#if defined (_SC_IOV_MAX)
+ mk_sysconf_map_entry (_SC_IOV_MAX),
+#endif
+
+#if defined (_SC_IPV6)
+ mk_sysconf_map_entry (_SC_IPV6),
+#endif
+
+#if defined (_SC_JOB_CONTROL)
+ mk_sysconf_map_entry (_SC_JOB_CONTROL),
+#endif
+
+#if defined (_SC_LEVEL1_DCACHE_ASSOC)
+ mk_sysconf_map_entry (_SC_LEVEL1_DCACHE_ASSOC),
+#endif
+
+#if defined (_SC_LEVEL1_DCACHE_LINESIZE)
+ mk_sysconf_map_entry (_SC_LEVEL1_DCACHE_LINESIZE),
+#endif
+
+#if defined (_SC_LEVEL1_DCACHE_SIZE)
+ mk_sysconf_map_entry (_SC_LEVEL1_DCACHE_SIZE),
+#endif
+
+#if defined (_SC_LEVEL1_ICACHE_ASSOC)
+ mk_sysconf_map_entry (_SC_LEVEL1_ICACHE_ASSOC),
+#endif
+
+#if defined (_SC_LEVEL1_ICACHE_LINESIZE)
+ mk_sysconf_map_entry (_SC_LEVEL1_ICACHE_LINESIZE),
+#endif
+
+#if defined (_SC_LEVEL1_ICACHE_SIZE)
+ mk_sysconf_map_entry (_SC_LEVEL1_ICACHE_SIZE),
+#endif
+
+#if defined (_SC_LEVEL2_CACHE_ASSOC)
+ mk_sysconf_map_entry (_SC_LEVEL2_CACHE_ASSOC),
+#endif
+
+#if defined (_SC_LEVEL2_CACHE_LINESIZE)
+ mk_sysconf_map_entry (_SC_LEVEL2_CACHE_LINESIZE),
+#endif
+
+#if defined (_SC_LEVEL2_CACHE_SIZE)
+ mk_sysconf_map_entry (_SC_LEVEL2_CACHE_SIZE),
+#endif
+
+#if defined (_SC_LEVEL3_CACHE_ASSOC)
+ mk_sysconf_map_entry (_SC_LEVEL3_CACHE_ASSOC),
+#endif
+
+#if defined (_SC_LEVEL3_CACHE_LINESIZE)
+ mk_sysconf_map_entry (_SC_LEVEL3_CACHE_LINESIZE),
+#endif
+
+#if defined (_SC_LEVEL3_CACHE_SIZE)
+ mk_sysconf_map_entry (_SC_LEVEL3_CACHE_SIZE),
+#endif
+
+#if defined (_SC_LEVEL4_CACHE_ASSOC)
+ mk_sysconf_map_entry (_SC_LEVEL4_CACHE_ASSOC),
+#endif
+
+#if defined (_SC_LEVEL4_CACHE_LINESIZE)
+ mk_sysconf_map_entry (_SC_LEVEL4_CACHE_LINESIZE),
+#endif
+
+#if defined (_SC_LEVEL4_CACHE_SIZE)
+ mk_sysconf_map_entry (_SC_LEVEL4_CACHE_SIZE),
+#endif
+
+#if defined (_SC_LINE_MAX)
+ mk_sysconf_map_entry (_SC_LINE_MAX),
+#endif
+
+#if defined (_SC_LOGIN_NAME_MAX)
+ mk_sysconf_map_entry (_SC_LOGIN_NAME_MAX),
+#endif
+
+#if defined (_SC_LONG_BIT)
+ mk_sysconf_map_entry (_SC_LONG_BIT),
+#endif
+
+#if defined (_SC_MAPPED_FILES)
+ mk_sysconf_map_entry (_SC_MAPPED_FILES),
+#endif
+
+#if defined (_SC_MB_LEN_MAX)
+ mk_sysconf_map_entry (_SC_MB_LEN_MAX),
+#endif
+
+#if defined (_SC_MEMLOCK)
+ mk_sysconf_map_entry (_SC_MEMLOCK),
+#endif
+
+#if defined (_SC_MEMLOCK_RANGE)
+ mk_sysconf_map_entry (_SC_MEMLOCK_RANGE),
+#endif
+
+#if defined (_SC_MEMORY_PROTECTION)
+ mk_sysconf_map_entry (_SC_MEMORY_PROTECTION),
+#endif
+
+#if defined (_SC_MESSAGE_PASSING)
+ mk_sysconf_map_entry (_SC_MESSAGE_PASSING),
+#endif
+
#if defined (_SC_MONOTONIC_CLOCK)
- mk_posixopt_sysconf_map_entry (MONOTONIC_CLOCK),
+ mk_sysconf_map_entry (_SC_MONOTONIC_CLOCK),
#endif
+
+#if defined (_SC_MQ_OPEN_MAX)
+ mk_sysconf_map_entry (_SC_MQ_OPEN_MAX),
+#endif
+
+#if defined (_SC_MQ_PRIO_MAX)
+ mk_sysconf_map_entry (_SC_MQ_PRIO_MAX),
+#endif
+
#ifdef _SC_MULTI_PROCESS
- mk_posixopt_sysconf_map_entry (MULTI_PROCESS),
+ mk_sysconf_map_entry (_SC_MULTI_PROCESS),
#endif
- mk_posixopt_sysconf_map_entry (PRIORITIZED_IO),
- mk_posixopt_sysconf_map_entry (PRIORITY_SCHEDULING),
-#if defined (_POSIX_RAW_SOCKETS)
- mk_sysconf_map_entry (_POSIX_RAW_SOCKETS),
+
+#if defined (_SC_NETWORKING)
+ mk_sysconf_map_entry (_SC_NETWORKING),
+#endif
+
+#if defined (_SC_NGROUPS_MAX)
+ mk_sysconf_map_entry (_SC_NGROUPS_MAX),
+#endif
+
+#if defined (_SC_NL_ARGMAX)
+ mk_sysconf_map_entry (_SC_NL_ARGMAX),
+#endif
+
+#if defined (_SC_NL_LANGMAX)
+ mk_sysconf_map_entry (_SC_NL_LANGMAX),
+#endif
+
+#if defined (_SC_NL_MSGMAX)
+ mk_sysconf_map_entry (_SC_NL_MSGMAX),
+#endif
+
+#if defined (_SC_NL_NMAX)
+ mk_sysconf_map_entry (_SC_NL_NMAX),
+#endif
+
+#if defined (_SC_NL_SETMAX)
+ mk_sysconf_map_entry (_SC_NL_SETMAX),
+#endif
+
+#if defined (_SC_NL_TEXTMAX)
+ mk_sysconf_map_entry (_SC_NL_TEXTMAX),
+#endif
+
+#if defined (_SC_NPROCESSORS_CONF)
+ mk_sysconf_map_entry (_SC_NPROCESSORS_CONF),
+#endif
+
+#if defined (_SC_NPROCESSORS_ONLN)
+ mk_sysconf_map_entry (_SC_NPROCESSORS_ONLN),
+#endif
+
+#if defined (_SC_NZERO)
+ mk_sysconf_map_entry (_SC_NZERO),
+#endif
+
+#if defined (_SC_OPEN_MAX)
+ mk_sysconf_map_entry (_SC_OPEN_MAX),
+#endif
+
+#if defined (_SC_PAGESIZE)
+ mk_sysconf_map_entry (_SC_PAGESIZE),
+#endif
+
+#if defined (_SC_PAGE_SIZE)
+ mk_sysconf_map_entry (_SC_PAGE_SIZE),
+#endif
+
+#if defined (_SC_PASS_MAX)
+ mk_sysconf_map_entry (_SC_PASS_MAX),
+#endif
+
+#if defined (_SC_PHYS_PAGES)
+ mk_sysconf_map_entry (_SC_PHYS_PAGES),
+#endif
+
+#if defined (_SC_PII)
+ mk_sysconf_map_entry (_SC_PII),
+#endif
+
+#if defined (_SC_PII_INTERNET)
+ mk_sysconf_map_entry (_SC_PII_INTERNET),
+#endif
+
+#if defined (_SC_PII_INTERNET_DGRAM)
+ mk_sysconf_map_entry (_SC_PII_INTERNET_DGRAM),
+#endif
+
+#if defined (_SC_PII_INTERNET_STREAM)
+ mk_sysconf_map_entry (_SC_PII_INTERNET_STREAM),
+#endif
+
+#if defined (_SC_PII_OSI)
+ mk_sysconf_map_entry (_SC_PII_OSI),
+#endif
+
+#if defined (_SC_PII_OSI_CLTS)
+ mk_sysconf_map_entry (_SC_PII_OSI_CLTS),
+#endif
+
+#if defined (_SC_PII_OSI_COTS)
+ mk_sysconf_map_entry (_SC_PII_OSI_COTS),
+#endif
+
+#if defined (_SC_PII_OSI_M)
+ mk_sysconf_map_entry (_SC_PII_OSI_M),
+#endif
+
+#if defined (_SC_PII_SOCKET)
+ mk_sysconf_map_entry (_SC_PII_SOCKET),
+#endif
+
+#if defined (_SC_PII_XTI)
+ mk_sysconf_map_entry (_SC_PII_XTI),
+#endif
+
+#if defined (_SC_PIPE)
+ mk_sysconf_map_entry (_SC_PIPE),
+#endif
+
+#if defined (_SC_POLL)
+ mk_sysconf_map_entry (_SC_POLL),
+#endif
+
+#if defined (_SC_SINGLE_PROCESS)
+ mk_sysconf_map_entry (_SC_SINGLE_PROCESS),
+#endif
+
+#if defined (_SC_SYSTEM_DATABASE)
+ mk_sysconf_map_entry (_SC_SYSTEM_DATABASE),
+#endif
+
+#if defined (_SC_SYSTEM_DATABASE_R)
+ mk_sysconf_map_entry (_SC_SYSTEM_DATABASE_R),
+#endif
+
+#if defined (_SC_THREAD_KEYS_MAX)
+ mk_sysconf_map_entry (_SC_THREAD_KEYS_MAX),
+#endif
+
+#if defined (_SC_THREAD_DESTRUCTOR_ITERATIONS)
+ mk_sysconf_map_entry (_SC_THREAD_DESTRUCTOR_ITERATIONS),
+#endif
+
+#if defined (_SC_THREAD_THREADS_MAX)
+ mk_sysconf_map_entry (_SC_THREAD_THREADS_MAX),
+#endif
+
+#if defined (_SC_STREAM_MAX)
+ mk_sysconf_map_entry (_SC_STREAM_MAX),
+#endif
+
+#if defined (_SC_SYMLOOP_MAX)
+ mk_sysconf_map_entry (_SC_SYMLOOP_MAX),
+#endif
+
+#if defined (_SC_TTY_NAME_MAX)
+ mk_sysconf_map_entry (_SC_TTY_NAME_MAX),
+#endif
+
+#if defined (_SC_TZNAME_MAX)
+ mk_sysconf_map_entry (_SC_TZNAME_MAX),
+#endif
+
+#if defined (_SC_TYPED_MEMORY_OBJECTS)
+ mk_sysconf_map_entry (_SC_TYPED_MEMORY_OBJECTS),
+#endif
+
+#if defined (_SC_USER_GROUPS)
+ mk_sysconf_map_entry (_SC_USER_GROUPS),
+#endif
+
+#if defined (_SC_USER_GROUPS_R)
+ mk_sysconf_map_entry (_SC_USER_GROUPS_R),
+#endif
+
+#if defined (_SC_VERSION)
+ mk_sysconf_map_entry (_SC_VERSION),
+#endif
+
+#if defined (_SC_POSIX2_C_DEV)
+ mk_sysconf_map_entry (_SC_POSIX2_C_DEV),
+#endif
+
+#if defined (_SC_SIGQUEUE_MAX)
+ mk_sysconf_map_entry (_SC_SIGQUEUE_MAX),
+#endif
+
+#if defined (_SC_T_IOV_MAX)
+ mk_sysconf_map_entry (_SC_T_IOV_MAX),
+#endif
+
+#if defined (_SC_THREAD_STACK_MIN)
+ mk_sysconf_map_entry (_SC_THREAD_STACK_MIN),
+#endif
+
+#if defined (_SC_SSIZE_MAX)
+ mk_sysconf_map_entry (_SC_SSIZE_MAX),
+#endif
+
+#if defined (_SC_TIMER_MAX)
+ mk_sysconf_map_entry (_SC_TIMER_MAX),
+#endif
+
+#if defined (_SC_UCHAR_MAX)
+ mk_sysconf_map_entry (_SC_UCHAR_MAX),
+#endif
+
+#if defined (_SC_UINT_MAX)
+ mk_sysconf_map_entry (_SC_UINT_MAX),
+#endif
+
+#if defined (_SC_UIO_MAXIOV)
+ mk_sysconf_map_entry (_SC_UIO_MAXIOV),
+#endif
+
+#if defined (_SC_ULONG_MAX)
+ mk_sysconf_map_entry (_SC_ULONG_MAX),
+#endif
+
+#if defined (_SC_USHRT_MAX)
+ mk_sysconf_map_entry (_SC_USHRT_MAX),
+#endif
+
+#if defined (_SC_V6_LPBIG_OFFBIG)
+ mk_sysconf_map_entry (_SC_V6_LPBIG_OFFBIG),
+#endif
+
+#if defined (_SC_WORD_BIT)
+ mk_sysconf_map_entry (_SC_WORD_BIT),
+#endif
+
+#if defined (_SC_EXPR_NEST_MAX)
+ mk_sysconf_map_entry (_SC_EXPR_NEST_MAX),
#endif
+
+#if defined (_SC_V6_ILP32_OFF32)
+ mk_sysconf_map_entry (_SC_V6_ILP32_OFF32),
+#endif
+
+#if defined (_SC_V6_ILP32_OFFBIG)
+ mk_sysconf_map_entry (_SC_V6_ILP32_OFFBIG),
+#endif
+
+#if defined (_SC_V6_LP64_OFF64)
+ mk_sysconf_map_entry (_SC_V6_LP64_OFF64),
+#endif
+
+#if defined (_SC_V7_ILP32_OFF32)
+ mk_sysconf_map_entry (_SC_V7_ILP32_OFF32),
+#endif
+
+#if defined (_SC_V7_ILP32_OFFBIG)
+ mk_sysconf_map_entry (_SC_V7_ILP32_OFFBIG),
+#endif
+
+#if defined (_SC_V7_LPBIG_OFFBIG)
+ mk_sysconf_map_entry (_SC_V7_LPBIG_OFFBIG),
+#endif
+
+#if defined (_SC_V7_LP64_OFF64)
+ mk_sysconf_map_entry (_SC_V7_LP64_OFF64),
+#endif
+
+#if defined (_SC_PRIORITIZED_IO)
+ mk_sysconf_map_entry (_SC_PRIORITIZED_IO),
+#endif
+
+#if defined (_SC_PRIORITY_SCHEDULING)
+ mk_sysconf_map_entry (_SC_PRIORITY_SCHEDULING),
+#endif
+
+#if defined (_SC_RAW_SOCKETS)
+ mk_sysconf_map_entry (_SC_RAW_SOCKETS),
+#endif
+
#if defined (_SC_READER_WRITER_LOCKS)
- mk_posixopt_sysconf_map_entry (READER_WRITER_LOCKS),
+ mk_sysconf_map_entry (_SC_READER_WRITER_LOCKS),
#endif
- mk_posixopt_sysconf_map_entry (REALTIME_SIGNALS),
+
+#if defined (_SC_REALTIME_SIGNALS)
+ mk_sysconf_map_entry (_SC_REALTIME_SIGNALS),
+#endif
+
+#if defined (_SC_RE_DUP_MAX)
+ mk_sysconf_map_entry (_SC_RE_DUP_MAX),
+#endif
+
#if defined (_SC_REGEXP)
- mk_posixopt_sysconf_map_entry (REGEXP),
+ mk_sysconf_map_entry (_SC_REGEXP),
+#endif
+
+#if defined (_SC_REGEX_VERSION)
+ mk_sysconf_map_entry (_SC_REGEX_VERSION),
+#endif
+
+#if defined (_SC_RTSIG_MAX)
+ mk_sysconf_map_entry (_SC_RTSIG_MAX),
+#endif
+
+#if defined (_SC_SAVED_IDS)
+ mk_sysconf_map_entry (_SC_SAVED_IDS),
+#endif
+
+#if defined (_SC_SCHAR_MAX)
+ mk_sysconf_map_entry (_SC_SCHAR_MAX),
+#endif
+
+#if defined (_SC_SCHAR_MIN)
+ mk_sysconf_map_entry (_SC_SCHAR_MIN),
#endif
- mk_posixopt_sysconf_map_entry (SAVED_IDS),
- mk_posixopt_sysconf_map_entry (SEMAPHORES),
- mk_posixopt_sysconf_map_entry (SHARED_MEMORY_OBJECTS),
+
+#if defined (_SC_SELECT)
+ mk_sysconf_map_entry (_SC_SELECT),
+#endif
+
+#if defined (_SC_SEMAPHORES)
+ mk_sysconf_map_entry (_SC_SEMAPHORES),
+#endif
+
+#if defined (_SC_SEM_NSEMS_MAX)
+ mk_sysconf_map_entry (_SC_SEM_NSEMS_MAX),
+#endif
+
+#if defined (_SC_SEM_VALUE_MAX)
+ mk_sysconf_map_entry (_SC_SEM_VALUE_MAX),
+#endif
+
+#if defined (_SC_SHARED_MEMORY_OBJECTS)
+ mk_sysconf_map_entry (_SC_SHARED_MEMORY_OBJECTS),
+#endif
+
#if defined (_SC_SHELL)
- mk_posixopt_sysconf_map_entry (SHELL),
+ mk_sysconf_map_entry (_SC_SHELL),
#endif
+
+#if defined (_SC_SHRT_MAX)
+ mk_sysconf_map_entry (_SC_SHRT_MAX),
+#endif
+
+#if defined (_SC_SHRT_MIN)
+ mk_sysconf_map_entry (_SC_SHRT_MIN),
+#endif
+
+#if defined (_SC_SIGNALS)
+ mk_sysconf_map_entry (_SC_SIGNALS),
+#endif
+
#if defined (_SC_SPAWN)
- mk_posixopt_sysconf_map_entry (SPAWN),
+ mk_sysconf_map_entry (_SC_SPAWN),
#endif
+
#if defined (_SC_SPIN_LOCKS)
- mk_posixopt_sysconf_map_entry (SPIN_LOCKS),
+ mk_sysconf_map_entry (_SC_SPIN_LOCKS),
#endif
+
#if defined (_SC_SPORADIC_SERVER)
- mk_posixopt_sysconf_map_entry (SPORADIC_SERVER),
+ mk_sysconf_map_entry (_SC_SPORADIC_SERVER),
#endif
- mk_posixopt_sysconf_map_entry (SYNCHRONIZED_IO),
- mk_posixopt_sysconf_map_entry (THREAD_ATTR_STACKSIZE),
+
+#if defined (_SC_SYNCHRONIZED_IO)
+ mk_sysconf_map_entry (_SC_SYNCHRONIZED_IO),
+#endif
+
+#if defined (_SC_THREAD_ATTR_STACKADDR)
+ mk_sysconf_map_entry (_SC_THREAD_ATTR_STACKADDR),
+#endif
+
+#if defined (_SC_THREAD_ATTR_STACKSIZE)
+ mk_sysconf_map_entry (_SC_THREAD_ATTR_STACKSIZE),
+#endif
+
#if defined (_SC_THREAD_CPUTIME)
- mk_posixopt_sysconf_map_entry (THREAD_CPUTIME),
+ mk_sysconf_map_entry (_SC_THREAD_CPUTIME),
+#endif
+
+#if defined (_SC_THREAD_PRIO_INHERIT)
+ mk_sysconf_map_entry (_SC_THREAD_PRIO_INHERIT),
#endif
- mk_posixopt_sysconf_map_entry (THREAD_PRIO_INHERIT),
- mk_posixopt_sysconf_map_entry (THREAD_PRIO_PROTECT),
- mk_posixopt_sysconf_map_entry (THREAD_PRIORITY_SCHEDULING),
+
+#if defined (_SC_THREAD_PRIO_PROTECT)
+ mk_sysconf_map_entry (_SC_THREAD_PRIO_PROTECT),
+#endif
+
+#if defined (_SC_THREAD_PRIORITY_SCHEDULING)
+ mk_sysconf_map_entry (_SC_THREAD_PRIORITY_SCHEDULING),
+#endif
+
#if defined (_SC_THREAD_PROCESS_SHARED)
- mk_posixopt_sysconf_map_entry (THREAD_PROCESS_SHARED),
+ mk_sysconf_map_entry (_SC_THREAD_PROCESS_SHARED),
#endif
- mk_posixopt_sysconf_map_entry (THREAD_SAFE_FUNCTIONS),
+
+#if defined (_SC_THREAD_ROBUST_PRIO_INHERIT)
+ mk_sysconf_map_entry (_SC_THREAD_ROBUST_PRIO_INHERIT),
+#endif
+
+#if defined (_SC_THREAD_ROBUST_PRIO_PROTECT)
+ mk_sysconf_map_entry (_SC_THREAD_ROBUST_PRIO_PROTECT),
+#endif
+
+#if defined (_SC_THREAD_SAFE_FUNCTIONS)
+ mk_sysconf_map_entry (_SC_THREAD_SAFE_FUNCTIONS),
+#endif
+
#if defined (_SC_THREAD_SPORADIC_SERVER)
- mk_posixopt_sysconf_map_entry (THREAD_SPORADIC_SERVER),
+ mk_sysconf_map_entry (_SC_THREAD_SPORADIC_SERVER),
+#endif
+
+#if defined (_SC_THREADS)
+ mk_sysconf_map_entry (_SC_THREADS),
#endif
- mk_posixopt_sysconf_map_entry (THREADS),
+
#if defined (_SC_TIMEOUTS)
- mk_posixopt_sysconf_map_entry (TIMEOUTS),
+ mk_sysconf_map_entry (_SC_TIMEOUTS),
+#endif
+
+#if defined (_SC_TIMERS)
+ mk_sysconf_map_entry (_SC_TIMERS),
#endif
- mk_posixopt_sysconf_map_entry (TIMERS),
+
#if defined (_SC_TRACE)
- mk_posixopt_sysconf_map_entry (TRACE),
+ mk_sysconf_map_entry (_SC_TRACE),
#endif
+
#if defined (_SC_TRACE_EVENT_FILTER)
- mk_posixopt_sysconf_map_entry (TRACE_EVENT_FILTER),
+ mk_sysconf_map_entry (_SC_TRACE_EVENT_FILTER),
#endif
+
#if defined (_SC_TRACE_INHERIT)
- mk_posixopt_sysconf_map_entry (TRACE_INHERIT),
+ mk_sysconf_map_entry (_SC_TRACE_INHERIT),
#endif
+
#if defined (_SC_TRACE_LOG)
- mk_posixopt_sysconf_map_entry (TRACE_LOG),
+ mk_sysconf_map_entry (_SC_TRACE_LOG),
+#endif
+
+#if defined (_SC_TYPED_MEMORY_OBJECT)
+ mk_sysconf_map_entry (_SC_TYPED_MEMORY_OBJECT),
+#endif
+
+#if defined (_SC_XBS5_ILP32_OFF32)
+ mk_sysconf_map_entry (_SC_XBS5_ILP32_OFF32),
+#endif
+
+#if defined (_SC_XBS5_ILP32_OFFBIG)
+ mk_sysconf_map_entry (_SC_XBS5_ILP32_OFFBIG),
+#endif
+
+#if defined (_SC_XBS5_LP64_OFF64)
+ mk_sysconf_map_entry (_SC_XBS5_LP64_OFF64),
+#endif
+
+#if defined (_SC_XBS5_LPBIG_OFFBIG)
+ mk_sysconf_map_entry (_SC_XBS5_LPBIG_OFFBIG),
+#endif
+
+#if defined (_SC_XOPEN_CRYPT)
+ mk_sysconf_map_entry (_SC_XOPEN_CRYPT),
+#endif
+
+#if defined (_SC_XOPEN_ENH_I18N)
+ mk_sysconf_map_entry (_SC_XOPEN_ENH_I18N),
+#endif
+
+#if defined (_SC_XOPEN_LEGACY)
+ mk_sysconf_map_entry (_SC_XOPEN_LEGACY),
+#endif
+
+#if defined (_SC_XOPEN_REALTIME)
+ mk_sysconf_map_entry (_SC_XOPEN_REALTIME),
+#endif
+
+#if defined (_SC_XOPEN_REALTIME_THREADS)
+ mk_sysconf_map_entry (_SC_XOPEN_REALTIME_THREADS),
+#endif
+
+#if defined (_SC_XOPEN_SHM)
+ mk_sysconf_map_entry (_SC_XOPEN_SHM),
+#endif
+
+#if defined (_SC_XOPEN_UNIX)
+ mk_sysconf_map_entry (_SC_XOPEN_UNIX),
+#endif
+
+#if defined (_SC_XOPEN_XPG2)
+ mk_sysconf_map_entry (_SC_XOPEN_XPG2),
#endif
-#ifdef _SC_TYPED_MEMORY_OBJECT
- mk_posixopt_sysconf_map_entry (TYPED_MEMORY_OBJECT),
+
+#if defined (_SC_XOPEN_XPG3)
+ mk_sysconf_map_entry (_SC_XOPEN_XPG3),
#endif
-#if defined (_POSIX_VDISABLE)
- mk_sysconf_map_entry (_POSIX_VDISABLE),
+
+#if defined (_SC_XOPEN_XPG4)
+ mk_sysconf_map_entry (_SC_XOPEN_XPG4),
#endif
- mk_sysconf_map_entry (_XOPEN_CRYPT),
- mk_sysconf_map_entry (_XOPEN_LEGACY),
-#if defined (_XOPEN_REALTIME)
- mk_sysconf_map_entry (_XOPEN_REALTIME),
+
+#if defined (_SC_XOPEN_VERSION)
+ mk_sysconf_map_entry (_SC_XOPEN_VERSION),
#endif
-#if defined (_XOPEN_REALTIME_THREADS)
- mk_sysconf_map_entry (_XOPEN_REALTIME_THREADS),
+
+#if defined (_SC_XOPEN_XCU_VERSION)
+ mk_sysconf_map_entry (_SC_XOPEN_XCU_VERSION),
#endif
- mk_sysconf_map_entry (_XOPEN_UNIX),
{ 0, NULL }
};
@@ -514,7 +1397,7 @@ struct procenv_map scheduler_map[] = {
mk_map_entry (SCHED_IDLE),
#endif
#endif
-
+
{ 0, NULL }
};
@@ -524,6 +1407,15 @@ struct procenv_map thread_sched_policy_map[] = {
mk_map_entry (SCHED_RR)
};
+#if defined (PROCENV_LINUX) && defined (HAVE_NUMA_H)
+struct procenv_map numa_mempolicy_map[] = {
+ mk_map_entry (MPOL_DEFAULT),
+ mk_map_entry (MPOL_PREFERRED),
+ mk_map_entry (MPOL_BIND),
+ mk_map_entry (MPOL_INTERLEAVE),
+};
+#endif
+
void
usage (void)
{
@@ -533,53 +1425,90 @@ usage (void)
show ("");
show ("Options:");
show ("");
- show (" -a, --meta : Display meta details.");
- show (" -A, --arguments : Display program arguments.");
- show (" -b, --libs : Display library details.");
- show (" -c, --cgroup[s] : Display cgroup details (Linux only).");
- show (" -d, --compiler : Display compiler details.");
- show (" -e, --env[ironment] : Display environment variables.");
- show (" --exec : Treat non-option arguments as program to execute.");
- show (" -f, --fds : Display file descriptor details.");
- show (" --file=<file> : Send output to <file> (implies --output=file).");
- show (" -g, --sizeof : Display sizes of data types in bytes.");
- show (" -h, --help : This help text.");
- show (" -i, --misc : Display miscellaneous details.");
- show (" -j, --uname : Display uname details.");
- show (" -k, --clock[s] : Display clock details.");
- show (" -l, --limits : Display limits.");
- show (" -L, --locale : Display locale details.");
- show (" -m, --mount[s] : Display mount details.");
- show (" -n, --confstr : Display confstr details.");
- show (" -N, --network : Display network details.");
- show (" -o, --oom : Display out-of-memory manager details (Linux only)");
- show (" --output=<type> : Send output to alternative location. <type> can be one of:");
+ show (" -a, --meta : Display meta details.");
+ show (" -A, --arguments : Display program arguments.");
+ show (" -b, --libs : Display details of linked libraries.");
+ show (" -B, --libc : Display standard library details.");
+ show (" -c, --cgroups : Display cgroup details (Linux only).");
+ show (" -C, --cpu : Display CPU and scheduler details.");
+ show (" --crumb-separator=<str> : Specify string '<str>' as alternate delimiter");
+ show (" for crumb format output (default='%s').",
+ PROCENV_DEFAULT_CRUMB_SEPARATOR);
+ show (" -d, --compiler : Display compiler details.");
+ show (" -e, --environment : Display environment variables.");
+ show (" -E, --semaphores : Display semaphore details.");
+ show (" --exec : Treat non-option arguments as program to execute.");
+ show (" -f, --fds : Display file descriptor details.");
+ show (" -F, --namespaces : Display namespace details.");
+ show (" --file=<file> : Send output to <file> (implies --output=file).");
+ show (" --format=<format> : Specify output format. <format> can be one of:");
+ show ("");
+ show (" crumb : ASCII 'breadcrumbs'");
+ show (" json : JSON output.");
+ show (" text : ASCII output (default).");
+ show (" xml : XML output.");
+ show ("");
+ show (" -g, --sizeof : Display sizes of data types in bytes.");
+ show (" -h, --help : This help text.");
+ show (" -i, --misc : Display miscellaneous details.");
+ show (" --indent : Number of indent characters to use for each indent");
+ show (" (default=%d).", DEFAULT_INDENT_AMOUNT);
+ show (" --indent-char=<c> : Use character '<c>' for indenting");
+ show (" (default='%s').", DEFAULT_INDENT_CHAR);
+ show (" -j, --uname : Display uname details.");
+ show (" -k, --clocks : Display clock details.");
+ show (" -l, --limits : Display limits.");
+ show (" -L, --locale : Display locale details.");
+ show (" -m, --mounts : Display mount details.");
+ show (" -M, --message-queues : Display message queue details.");
+ show (" -n, --confstr : Display confstr details.");
+ show (" -N, --network : Display network details.");
+ show (" -o, --oom : Display out-of-memory manager details (Linux only)");
+ show (" --output=<type> : Send output to alternative location.");
+ show (" <type> can be one of:");
show ("");
- show (" file : Send output to a file.");
- show (" stderr : Write to standard error.");
- show (" stdout : Write to standard output (default).");
- show (" syslog : Write to the system log file.");
- show (" terminal : Write to terminal.");
+ show (" file : Send output to a file.");
+ show (" stderr : Write to standard error.");
+ show (" stdout : Write to standard output (default).");
+ show (" syslog : Write to the system log file.");
+ show (" terminal : Write to terminal.");
show ("");
- show (" -p, --proc[ess] : Display process details.");
- show (" -P, --platform : Display platform details.");
- show (" -q, --time : Display time details.");
- show (" -r, --range[s] : Display range of data types.");
- show (" -s, --signal[s] : Display signal details.");
- show (" -t, --tty : Display terminal details.");
- show (" -T, --threads : Display thread details.");
- show (" -u, --stat : Display stat details.");
- show (" -U, --rusage : Display rusage details.");
- show (" -v, --version : Display version details.");
- show (" -w, --capabilities : Display capaibility details (Linux only).");
- show (" -x, --pathconf : Display pathconf details.");
- show (" -y, --sysconf : Display sysconf details.");
- show (" -z, --timezone : Display timezone details.");
+ show (" -p, --process : Display process details.");
+ show (" -P, --platform : Display platform details.");
+ show (" -q, --time : Display time details.");
+ show (" -r, --ranges : Display range of data types.");
+ show (" --separator=<str> : Specify string '<str>' as alternate delimiter");
+ show (" for text format output (default='%s').",
+ PROCENV_DEFAULT_TEXT_SEPARATOR);
+ show (" -s, --signals : Display signal details.");
+ show (" -S, --shared-memory : Display shared memory details.");
+ show (" -t, --tty : Display terminal details.");
+ show (" -T, --threads : Display thread details.");
+ show (" -u, --stat : Display stat details.");
+ show (" -U, --rusage : Display rusage details.");
+ show (" -v, --version : Display version details.");
+ show (" -w, --capabilities : Display capability details (Linux only).");
+ show (" -x, --pathconf : Display pathconf details.");
+ show (" -y, --sysconf : Display sysconf details.");
+ show (" -Y, --memory : Display memory details.");
+ show (" -z, --timezone : Display timezone details.");
show ("");
show ("Notes:");
show ("");
- show (" - If no option is specified, all details are displayed.");
- show (" - Only one option may be specified.");
+ show (" - Options are considered in order, so '--output' should");
+ show (" precede any other option.");
+ show (" - If no display option is specified, all details are displayed.");
+ show (" - Only one display option may be specified.");
+ show (" - All values for '--indent-char' are literal except '\\t' which can be");
+ show (" used to specify a tab character. The same is true for '--separator'");
+ show (" and '--crumb-separator' but only if it is the first character specified.");
+ show (" - Specifying a visible indent-char is only (vaguely) meaningful");
+ show (" for text output.");
+ show (" - Any long option name may be shortened as long as it remains unique.");
+ show (" - The 'crumb' output format is designed for easy parsing: it displays");
+ show (" the data in a flattened format with each value on a separate line");
+ show (" preceded by all appropriate headings which are separated by the");
+ show (" current separator.");
show ("");
}
@@ -589,20 +1518,98 @@ show_pathconfs (ShowMountType what,
{
assert (dir);
- if (what == SHOW_ALL)
- showi (INDENT, "pathconf for path '%s':", dir);
- else
- show ("pathconf for path '%s':", dir);
+ if (what == SHOW_PATHCONF) {
+ header (dir);
+ } else {
+ header ("pathconf");
+ }
+
+
+#if defined (_PC_ALLOC_SIZE_MIN)
+ show_pathconf (what, dir, _PC_ALLOC_SIZE_MIN);
+#endif
+#if defined (_PC_ASYNC_IO)
+ show_pathconf (what, dir, _PC_ASYNC_IO);
+#endif
+
+#if defined (_PC_CHOWN_RESTRICTED)
+ show_pathconf (what, dir, _PC_CHOWN_RESTRICTED);
+#endif
+
+#if defined (_PC_FILESIZEBITS)
+ show_pathconf (what, dir, _PC_FILESIZEBITS);
+#endif
+
+#if defined (_PC_LINK_MAX)
show_pathconf (what, dir, _PC_LINK_MAX);
+#endif
+
+#if defined (_PC_MAX_CANON)
show_pathconf (what, dir, _PC_MAX_CANON);
+#endif
+
+#if defined (_PC_MAX_INPUT)
show_pathconf (what, dir, _PC_MAX_INPUT);
+#endif
+
+#if defined (_PC_NAME_MAX)
show_pathconf (what, dir, _PC_NAME_MAX);
+#endif
+
+#if defined (_PC_NO_TRUNC)
+ show_pathconf (what, dir, _PC_NO_TRUNC);
+#endif
+
+#if defined (_PC_PATH_MAX)
show_pathconf (what, dir, _PC_PATH_MAX);
+#endif
+
+#if defined (_PC_PIPE_BUF)
show_pathconf (what, dir, _PC_PIPE_BUF);
- show_pathconf (what, dir, _PC_CHOWN_RESTRICTED);
- show_pathconf (what, dir, _PC_NO_TRUNC);
+#endif
+
+#if defined (_PC_PRIO_IO)
+ show_pathconf (what, dir, _PC_PRIO_IO);
+#endif
+
+#if defined (_PC_REC_INCR_XFER_SIZE)
+ show_pathconf (what, dir, _PC_REC_INCR_XFER_SIZE);
+#endif
+
+#if defined (_PC_REC_MAX_XFER_SIZE)
+ show_pathconf (what, dir, _PC_REC_MAX_XFER_SIZE);
+#endif
+
+#if defined (_PC_REC_MIN_XFER_SIZE)
+ show_pathconf (what, dir, _PC_REC_MIN_XFER_SIZE);
+#endif
+
+#if defined (_PC_REC_XFER_ALIGN)
+ show_pathconf (what, dir, _PC_REC_XFER_ALIGN);
+#endif
+
+#if defined (_PC_SOCK_MAXBUF)
+ show_pathconf (what, dir, _PC_SOCK_MAXBUF);
+#endif
+
+#if defined (_PC_SYMLINK_MAX)
+ show_pathconf (what, dir, _PC_SYMLINK_MAX);
+#endif
+
+#if defined (_PC_2_SYMLINKS)
+ show_pathconf (what, dir, _PC_2_SYMLINKS);
+#endif
+
+#if defined (_PC_SYNC_IO)
+ show_pathconf (what, dir, _PC_SYNC_IO);
+#endif
+
+#if defined (_PC_VDISABLE)
show_pathconf (what, dir, _PC_VDISABLE);
+#endif
+
+ footer ();
}
const char *
@@ -623,23 +1630,25 @@ get_speed (speed_t speed)
*
* @prefix: string prefix to write,
* @indent: number of spaces to indent output to,
- * @fmt: printf-style format with associated arguments.
+ * @fmt: printf-style format with associated arguments that comprises
+ * the value part.
+ *
+ * Write output to @string, indented by @indent spaces. A trailing newline
+ * will be added.
*
- * Write output to @string, indented by @indent spaces.
* Note that error scenarios cannot call die() as by definition output
* may not be possible.
**/
void
_show (const char *prefix, int indent, const char *fmt, ...)
{
- int ret;
va_list ap;
char *buffer = NULL;
assert (fmt);
if (indent)
- appendf (&buffer, "%*s", indent, " ");
+ appendf (&buffer, "%*s", indent, indent_char);
if (prefix && *prefix)
appendf (&buffer, "%s: ", prefix);
@@ -648,28 +1657,160 @@ _show (const char *prefix, int indent, const char *fmt, ...)
appendva (&buffer, fmt, ap);
va_end (ap);
- appendf (&buffer, "\n");
+ append (&buffer, "\n");
+
+ _show_output (buffer);
+
+ free (buffer);
+}
+
+/**
+ * entry:
+ *
+ * @name: name of thing to display,
+ * @fmt: printf-style format with associated arguments that comprises
+ * the value part.
+ *
+ * Add name/value pair represented by @name and value comprising
+ * printf-format string to the @doc global. The value added will be
+ * indented appropriately.
+ **/
+void
+entry (const char *name, const char *fmt, ...)
+{
+ va_list ap;
+ pstring *encoded_name = NULL;
+ pstring *encoded_value = NULL;
+
+ assert (name);
+ assert (fmt);
+
+ common_assert ();
+
+ change_element (ELEMENT_TYPE_ENTRY);
+
+ encoded_name = char_to_pstring (name);
+ if (! encoded_name)
+ die ("failed to encode name");
+
+ /* annoyingly, we must encode here; we cannot simply call
+ * encode_string() once just prior to showing the output
+ * document since if the output format is XML, we'd end
+ * up encoding the XML tags themselves, not just the values
+ * within!
+ */
+ if (encode_string (&encoded_name) < 0)
+ die ("failed to encode name");
+
+ /* expand format */
+ va_start (ap, fmt);
+ wmappendva (&encoded_value, fmt, ap);
+ va_end (ap);
+
+ if (encode_string (&encoded_value) < 0)
+ die ("failed to encode value");
+
+ switch (output_format) {
+
+ case OUTPUT_FORMAT_CRUMB:
+ assert (crumb_list);
+
+ /* Add the bread crumbs */
+ PR_LIST_FOREACH (crumb_list, iter) {
+ char *crumb = (char *)iter->data;
+ wappendf (&doc,
+ L"%s%s",
+ crumb,
+ crumb_separator);
+ }
+
+ wappendf (&doc,
+ L"%ls%s%ls\n",
+ encoded_name->buf,
+ text_separator,
+ encoded_value->buf);
+ break;
+
+ case OUTPUT_FORMAT_TEXT:
+ wappendf (&doc,
+ L"%ls%s%ls",
+ encoded_name->buf,
+ text_separator,
+ encoded_value->buf);
+ break;
+
+ case OUTPUT_FORMAT_JSON:
+ wappendf (&doc,
+ L"\"%ls\" : \"%ls\"",
+ encoded_name->buf,
+ encoded_value->buf);
+ break;
+
+ case OUTPUT_FORMAT_XML:
+ wappendf (&doc,
+ L"<entry name=\"%ls\">%ls</entry>",
+ encoded_name->buf,
+ encoded_value->buf);
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+
+ pstring_free (encoded_name);
+ pstring_free (encoded_value);
+}
+
+/**
+ * _show_output:
+ *
+ * @string: String to display.
+ *
+ * Write output @string to appropriate location based on Output
+ * destination.
+ **/
+void
+_show_output_pstring (const pstring *pstr)
+{
+ char *str;
+
+ assert (pstr);
+
+ str = pstring_to_char (pstr);
+
+ _show_output (str);
+
+ free (str);
+}
+
+void
+_show_output (const char *str)
+{
+ int ret;
+
+ assert (str);
switch (output) {
case OUTPUT_SYSLOG:
- syslog (LOG_INFO, "%s", buffer);
+ syslog (LOG_INFO, "%s", str);
ret = 0;
break;
case OUTPUT_STDOUT:
- ret = fputs (buffer, stdout);
+ ret = fputs (str, stdout);
break;
case OUTPUT_STDERR:
- ret = fputs (buffer, stderr);
+ ret = fputs (str, stderr);
break;
case OUTPUT_TERM:
assert (user.tty_fd != -1);
- ret = write (user.tty_fd, buffer, strlen (buffer));
+ ret = write (user.tty_fd, str, strlen (str));
if (ret < 0) {
fprintf (stderr, "ERROR: failed to write to terminal\n");
- goto error;
+ exit (EXIT_FAILURE);
}
break;
@@ -682,14 +1823,14 @@ _show (const char *prefix, int indent, const char *fmt, ...)
if (output_fd < 0) {
fprintf (stderr, "ERROR: failed to open file '%s'\n",
output_file);
- goto error;
+ exit (EXIT_FAILURE);
}
}
- ret = write (output_fd, buffer, strlen (buffer));
+ ret = write (output_fd, str, strlen (str));
if (ret < 0) {
fprintf (stderr, "ERROR: failed to write to file '%s'\n",
output_file);
- goto error;
+ exit (EXIT_FAILURE);
}
break;
@@ -699,61 +1840,429 @@ _show (const char *prefix, int indent, const char *fmt, ...)
break;
}
- if (ret < 0)
- goto error;
+ if (ret < 0) {
+ fprintf (stderr, "ERROR: failed to output message\n");
+ exit (EXIT_FAILURE);
+ }
+}
- free (buffer);
+/**
+ * inc_indent:
+ *
+ * Increase indent.
+ **/
+void
+inc_indent (void)
+{
+ assert (indent >= 0);
- return;
+ indent += indent_amount;
+}
-error:
- if (buffer)
- free (buffer);
+/**
+ * dec_indent:
+ *
+ * Decrease indent.
+ **/
+void
+dec_indent (void)
+{
+ assert (indent >= 0);
+
+ indent -= indent_amount;
- fprintf (stderr, "ERROR: failed to construct message\n");
- exit (EXIT_FAILURE);
+ assert (indent >= 0);
}
/**
- * header:
- * @fmt: printf-style format with associated arguments.
+ * add_indent:
*
- * Display a header to stdout, unless user has requested
- * a summary view.
- */
+ * Insert the current indent to the output document.
+ **/
void
-header (const char *fmt, ...)
+add_indent (pstring **doc)
{
- char buffer[PROCENV_BUFFER];
- va_list ap;
- size_t bytes;
- size_t ret;
+ common_assert ();
- bytes = sizeof (buffer);
+ if (! indent)
+ return;
- memset (buffer, '\0', sizeof (buffer));
+ if (! strcmp (indent_char, DEFAULT_INDENT_CHAR)) {
+ wappendf (doc, L"%*s", indent, indent_char);
+ } else {
+ pstring *buffer = NULL;
- /* Don't display header if user has specified what to display as
- * only 1 group of information will be displayed (so a header is
- * unnecessary).
- */
- if (selected_option)
- return;
+ // Expand the buffer to the appropriate
+ // length by filling it with spaces and a random
+ // character.
+ wappendf (&buffer, L"%*lc", indent, wide_indent_char);
- /* append colon */
- va_start (ap, fmt);
- ret = vsprintf (buffer, fmt, ap);
- assert (ret);
- bytes -= ret;
- bytes--;
+ /* Now, replace the spaces and the random character with
+ * the chosen character. This convoluted approach is
+ * necessary as printf-type functions don't allow the
+ * padding character to be specified.
+ */
+ wmemset (buffer->buf, wide_indent_char, wcslen (buffer->buf));
- strncat (buffer, ":", bytes);
- va_end (ap);
+ pappend (doc, buffer);
+ pstring_free (buffer);
+ }
+}
+
+/**
+ * master_header:
+ *
+ * @doc: document to write footer to.
+ *
+ * Main header which is displayed once.
+ **/
+void
+master_header (pstring **doc)
+{
+ common_assert ();
+
+ switch (output_format) {
+
+ case OUTPUT_FORMAT_CRUMB: /* FALL */
+ case OUTPUT_FORMAT_TEXT:
+ /* NOP */
+ break;
+
+ case OUTPUT_FORMAT_JSON:
+ object_open (FALSE);
+ break;
- buffer[sizeof (buffer) - 1] = '\0';
+ case OUTPUT_FORMAT_XML:
+ wappend (doc, L"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ wappendf (doc, L"<%s version=\"%s\" package_string=\"%s\" "
+ "mode=\"%s%s\" format_version=\"%d\">\n",
+ PACKAGE_NAME, PACKAGE_VERSION, PACKAGE_STRING,
+ user.euid ? _(NON_STR) "-" : "",
+ PRIVILEGED_STR,
+ PROCENV_FORMAT_VERSION);
- _show ("", 0, buffer);
+ inc_indent ();
+
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+}
+
+/**
+ * master_footer:
+ *
+ * @doc: document to write footer to.
+ *
+ * Main footer which is displayed once.
+ **/
+void
+master_footer (pstring **doc)
+{
+ common_assert ();
+
+ switch (output_format) {
+
+ case OUTPUT_FORMAT_CRUMB: /* FALL */
+ case OUTPUT_FORMAT_TEXT:
+ /* Tweak */
+ wappend (doc, L"\n");
+ break;
+
+ case OUTPUT_FORMAT_JSON:
+ object_close (FALSE);
+
+ /* Tweak */
+ wappend (doc, L"\n");
+ break;
+
+ case OUTPUT_FORMAT_XML:
+ /* Tweak */
+ wappend (doc, L"\n");
+ dec_indent ();
+ wappendf (doc, L"</%s>\n", PACKAGE_NAME);
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+}
+
+/**
+ * object_open:
+ *
+ * @retain: if TRUE, do not disrupt the current element such that the
+ * opening of the object will be invisible to the state machine, but
+ * will still produce the required output.
+ *
+ * Note: @retain is only meaningful for OUTPUT_FORMAT_JSON.
+ *
+ * Handle opening an object.
+ **/
+void
+object_open (int retain)
+{
+ common_assert ();
+
+ if (output_format == OUTPUT_FORMAT_JSON) {
+ if (retain) {
+ format_element ();
+ } else {
+ change_element (ELEMENT_TYPE_OBJECT_OPEN);
+ }
+ } else {
+ /* Objects are only required for handling JSON. In
+ * fact, they cause problems for other output formats
+ * that do not have visible "objects" in that they cause
+ * the state table to lose track of the previous element
+ * since it is actually the previous-previous element
+ * (as the pointless object is the previous element).
+ *
+ * As such, ignore them.
+ */
+ }
+
+ switch (output_format) {
+
+ case OUTPUT_FORMAT_CRUMB: /* FALL */
+ case OUTPUT_FORMAT_TEXT:
+ /* NOP */
+ break;
+
+ case OUTPUT_FORMAT_JSON:
+ wappend (&doc, L"{");
+ break;
+
+ case OUTPUT_FORMAT_XML:
+ /* NOP */
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+}
+
+/**
+ * object_close:
+ *
+ * @retain: if TRUE, do not disrupt the current element such that the
+ * object closure will be invisible to the state machine, but will still
+ * produce @retain: if TRUE, do not disrupt the current element.
+ *
+ * Note: @retain is only meaningful for OUTPUT_FORMAT_JSON.
+ *
+ * Handle closing an object.
+ **/
+void
+object_close (int retain)
+{
+ common_assert ();
+
+ if (output_format == OUTPUT_FORMAT_JSON) {
+ if (retain) {
+ format_element ();
+ } else {
+ change_element (ELEMENT_TYPE_OBJECT_CLOSE);
+ }
+ } else {
+ /* Objects are only required for handling JSON. In
+ * fact, they cause problems for other output formats
+ * that do not have visible "objects" in that they cause
+ * the state table to lose track of the previous element
+ * since it is actually the previous-previous element
+ * (as the pointless object is the previous element).
+ *
+ * As such, ignore them.
+ */
+ }
+
+ switch (output_format) {
+
+ case OUTPUT_FORMAT_CRUMB: /* FALL */
+ case OUTPUT_FORMAT_TEXT:
+ /* NOP */
+ break;
+
+ case OUTPUT_FORMAT_JSON:
+ wappend (&doc, L"}");
+ break;
+
+ case OUTPUT_FORMAT_XML:
+ /* NOP */
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+}
+
+/**
+ * section_open:
+ *
+ * @name: name of section.
+ *
+ * Start a new section which will contain >0 entry() calls.
+ **/
+void
+section_open (const char *name)
+{
+ assert (name);
+ common_assert ();
+
+ change_element (ELEMENT_TYPE_SECTION_OPEN);
+
+ switch (output_format) {
+
+ case OUTPUT_FORMAT_TEXT:
+ wappendf (&doc, L"%s:", name);
+ break;
+
+ case OUTPUT_FORMAT_CRUMB:
+ add_breadcrumb (name);
+ break;
+
+ case OUTPUT_FORMAT_JSON:
+ wappendf (&doc, L"\"%s\" : {", name);
+ break;
+
+ case OUTPUT_FORMAT_XML:
+ wappendf (&doc, L"<section name=\"%s\">", name);
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+}
+
+void
+section_close (void)
+{
+ common_assert ();
+
+ change_element (ELEMENT_TYPE_SECTION_CLOSE);
+
+ switch (output_format) {
+
+ case OUTPUT_FORMAT_TEXT:
+ /* NOP */
+ break;
+
+ case OUTPUT_FORMAT_CRUMB:
+ remove_breadcrumb ();
+ break;
+
+ case OUTPUT_FORMAT_JSON:
+ wappend (&doc, L"}");
+ break;
+
+ case OUTPUT_FORMAT_XML:
+ wappend (&doc, L"</section>");
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+}
+
+/**
+ * container_open:
+ *
+ * @name: name of container.
+ *
+ * Start a new container which will contain >0 entry() calls.
+ *
+ * This is primarily to handle JSON arrays.
+ **/
+void
+container_open (const char *name)
+{
+ assert (name);
+ common_assert ();
+
+ change_element (ELEMENT_TYPE_CONTAINER_OPEN);
+
+ switch (output_format) {
+
+ case OUTPUT_FORMAT_TEXT:
+ wappendf (&doc, L"%s:", name);
+ break;
+
+ case OUTPUT_FORMAT_CRUMB:
+ add_breadcrumb (name);
+ break;
+
+ case OUTPUT_FORMAT_JSON:
+ wappendf (&doc, L"\"%s\" : [", name);
+ break;
+
+ case OUTPUT_FORMAT_XML:
+ wappendf (&doc, L"<container name=\"%s\">", name);
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+}
+
+/**
+ * container_close:
+ *
+ * Finish with a container.
+ **/
+void
+container_close (void)
+{
+ common_assert ();
+
+ change_element (ELEMENT_TYPE_CONTAINER_CLOSE);
+
+ switch (output_format) {
+
+ case OUTPUT_FORMAT_TEXT:
+ /* NOP */
+ break;
+
+ case OUTPUT_FORMAT_CRUMB:
+ remove_breadcrumb ();
+ break;
+
+ case OUTPUT_FORMAT_JSON:
+ wappend (&doc, L"]");
+ break;
+
+ case OUTPUT_FORMAT_XML:
+ wappend (&doc, L"</container>");
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+}
+
+void
+header (const char *name)
+{
+ assert (name);
+ common_assert ();
+
+ section_open (name);
+}
+
+void
+footer (void)
+{
+ common_assert ();
+ section_close ();
}
/**
@@ -804,7 +2313,7 @@ fd_valid (int fd)
*
* In additional to the classical semantics, by careful use of clone(2),
* it is possible for a child to inherit its parents dispositions
- * (using clones CLONE_SIGHAND+CLONE_VM flags). This is possible since
+ * (using clone's CLONE_SIGHAND+CLONE_VM flags). This is possible since
* the child then shares the parents signal handlers, which inherantly
* therefore provide access to the dispositions).
**/
@@ -818,7 +2327,7 @@ show_signals (void)
sigset_t old_sigset;
struct sigaction act;
- header ("signals");
+ container_open ("signals");
/* Query blocked signals.
*
@@ -851,15 +2360,27 @@ show_signals (void)
blocked = 1;
signal_name = get_signal_name (i);
+ if (! signal_name)
+ continue;
+
signal_desc = strsignal (i);
- show ("%s ('%s', %d): blocked=%s, ignored=%s",
- signal_name ? signal_name : UNKNOWN_STR,
- signal_desc ? signal_desc : UNKNOWN_STR,
- i,
- blocked ? YES_STR : NO_STR,
- ignored ? YES_STR : NO_STR);
+ object_open (FALSE);
+
+ section_open (signal_name);
+
+ entry ("number", "%d", i);
+ entry ("description", "'%s'",
+ signal_desc ? signal_desc : UNKNOWN_STR);
+ entry ("blocked", "%s", blocked ? YES_STR : NO_STR);
+ entry ("ignored", "%s", ignored ? YES_STR : NO_STR);
+
+ section_close ();
+
+ object_close (FALSE);
}
+
+ container_close ();
}
void
@@ -873,20 +2394,32 @@ show_rlimits (void)
show_limit (RLIMIT_DATA);
show_limit (RLIMIT_FSIZE);
- /* why can't we use this? */
-#if 0
- show_limit (RLIMIT_RTTIME);
-#endif
-
#if defined (PROCENV_LINUX)
+
+ if (LINUX_KERNEL_MMR (2, 6, 25)) {
+#if defined (RLIMIT_RTTIME)
+ show_limit (RLIMIT_RTTIME);
+#endif
+ }
show_limit (RLIMIT_LOCKS);
#endif
show_limit (RLIMIT_MEMLOCK);
#if defined (PROCENV_LINUX)
- show_limit (RLIMIT_MSGQUEUE);
- show_limit (RLIMIT_NICE);
+
+ if (LINUX_KERNEL_MMR (2, 6, 8)) {
+#if defined (RLIMIT_MSGQUEUE)
+ show_limit (RLIMIT_MSGQUEUE);
+#endif
+ }
+
+ if (LINUX_KERNEL_MMR (2, 6, 12)) {
+#if defined RLIMIT_NICE
+ show_limit (RLIMIT_NICE);
+#endif
+ }
+
#endif
show_limit (RLIMIT_NOFILE);
@@ -897,16 +2430,19 @@ show_rlimits (void)
show_limit (RLIMIT_RTPRIO);
#endif
- /* FIXME */
-#if 0
- show_limit (RLIMIT_RTTIME);
-#endif
-
#if defined (PROCENV_LINUX)
+
+ if (LINUX_KERNEL_MMR (2, 6, 8)) {
+#if defined (RLIMIT_SIGPENDING)
show_limit (RLIMIT_SIGPENDING);
#endif
+ }
+
+#endif
show_limit (RLIMIT_STACK);
+
+ footer ();
}
void
@@ -914,11 +2450,11 @@ show_rusage (void)
{
struct rusage usage;
- header ("rusage");
-
if (getrusage (RUSAGE_SELF, &usage) < 0)
die ("unable to query rusage");
+ header ("rusage");
+
show_usage (usage, ru_maxrss);
show_usage (usage, ru_ixrss);
show_usage (usage, ru_idrss);
@@ -933,10 +2469,12 @@ show_rusage (void)
show_usage (usage, ru_nsignals);
show_usage (usage, ru_nvcsw);
show_usage (usage, ru_nivcsw);
+
+ footer ();
}
void
-dump_sysconf (void)
+show_sysconf (void)
{
struct procenv_map *p;
long value;
@@ -945,11 +2483,17 @@ dump_sysconf (void)
for (p = sysconf_map; p && p->name; p++) {
value = get_sysconf (p->num);
- show ("%s=%ld", p->name, value);
+ if (value == -1)
+ entry (p->name, "%s", NA_STR);
+ else
+ entry (p->name, "%ld", value);
}
+
+ footer ();
}
#ifndef PROCENV_ANDROID
+
void
show_confstrs (void)
{
@@ -958,11 +2502,271 @@ show_confstrs (void)
#if defined (_CS_GNU_LIBC_VERSION)
show_confstr (_CS_GNU_LIBC_VERSION);
#endif
+
#if defined (_CS_GNU_LIBPTHREAD_VERSION)
show_confstr (_CS_GNU_LIBPTHREAD_VERSION);
#endif
+
+#if defined (_CS_LFS64_CFLAGS)
+ show_confstr (_CS_LFS64_CFLAGS);
+#endif
+
+#if defined (_CS_LFS64_LDFLAGS)
+ show_confstr (_CS_LFS64_LDFLAGS);
+#endif
+
+#if defined (_CS_LFS64_LIBS)
+ show_confstr (_CS_LFS64_LIBS);
+#endif
+
+#if defined (_CS_LFS64_LINTFLAGS)
+ show_confstr (_CS_LFS64_LINTFLAGS);
+#endif
+
+#if defined (_CS_LFS_CFLAGS)
+ show_confstr (_CS_LFS_CFLAGS);
+#endif
+
+#if defined (_CS_LFS_LDFLAGS)
+ show_confstr (_CS_LFS_LDFLAGS);
+#endif
+
+#if defined (_CS_LFS_LIBS)
+ show_confstr (_CS_LFS_LIBS);
+#endif
+
+#if defined (_CS_LFS_LINTFLAGS)
+ show_confstr (_CS_LFS_LINTFLAGS);
+#endif
+
+#if defined (_CS_PATH)
show_confstr (_CS_PATH);
+#endif
+
+#if defined (_CS_POSIX_V6_ILP32_OFF32)
+ show_confstr (_CS_POSIX_V6_ILP32_OFF32);
+#endif
+
+#if defined (_CS_POSIX_V6_ILP32_OFF32_CFLAGS)
+ show_confstr (_CS_POSIX_V6_ILP32_OFF32_CFLAGS);
+#endif
+
+#if defined (_CS_POSIX_V6_ILP32_OFF32_LDFLAGS)
+ show_confstr (_CS_POSIX_V6_ILP32_OFF32_LDFLAGS);
+#endif
+
+#if defined (_CS_POSIX_V6_ILP32_OFF32_LIBS)
+ show_confstr (_CS_POSIX_V6_ILP32_OFF32_LIBS);
+#endif
+
+#if defined (_CS_POSIX_V6_ILP32_OFF32_LINTFLAGS)
+ show_confstr (_CS_POSIX_V6_ILP32_OFF32_LINTFLAGS);
+#endif
+
+#if defined (_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS)
+ show_confstr (_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS);
+#endif
+
+#if defined (_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS)
+ show_confstr (_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS);
+#endif
+
+#if defined (_CS_POSIX_V6_ILP32_OFFBIG_LIBS)
+ show_confstr (_CS_POSIX_V6_ILP32_OFFBIG_LIBS);
+#endif
+
+#if defined (_CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS)
+ show_confstr (_CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS);
+#endif
+
+#if defined (_CS_POSIX_V6_LP64_OFF64_CFLAGS)
+ show_confstr (_CS_POSIX_V6_LP64_OFF64_CFLAGS);
+#endif
+
+#if defined (_CS_POSIX_V6_LP64_OFF64_LDFLAGS)
+ show_confstr (_CS_POSIX_V6_LP64_OFF64_LDFLAGS);
+#endif
+
+#if defined (_CS_POSIX_V6_LP64_OFF64_LIBS)
+ show_confstr (_CS_POSIX_V6_LP64_OFF64_LIBS);
+#endif
+
+#if defined (_CS_POSIX_V6_LP64_OFF64_LINTFLAGS)
+ show_confstr (_CS_POSIX_V6_LP64_OFF64_LINTFLAGS);
+#endif
+
+#if defined (_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS)
+ show_confstr (_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS);
+#endif
+
+#if defined (_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS)
+ show_confstr (_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS);
+#endif
+
+#if defined (_CS_POSIX_V6_LPBIG_OFFBIG_LIBS)
+ show_confstr (_CS_POSIX_V6_LPBIG_OFFBIG_LIBS);
+#endif
+
+#if defined (_CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS)
+ show_confstr (_CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS);
+#endif
+
+#if defined (_CS_POSIX_V7_ILP32_OFF32_CFLAGS)
+ show_confstr (_CS_POSIX_V7_ILP32_OFF32_CFLAGS);
+#endif
+
+#if defined (_CS_POSIX_V7_ILP32_OFF32_LDFLAGS)
+ show_confstr (_CS_POSIX_V7_ILP32_OFF32_LDFLAGS);
+#endif
+
+#if defined (_CS_POSIX_V7_ILP32_OFF32_LIBS)
+ show_confstr (_CS_POSIX_V7_ILP32_OFF32_LIBS);
+#endif
+
+#if defined (_CS_POSIX_V7_ILP32_OFF32_LINTFLAGS)
+ show_confstr (_CS_POSIX_V7_ILP32_OFF32_LINTFLAGS);
+#endif
+
+#if defined (_CS_POSIX_V7_ILP32_OFFBIG_CFLAGS)
+ show_confstr (_CS_POSIX_V7_ILP32_OFFBIG_CFLAGS);
+#endif
+
+#if defined (_CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS)
+ show_confstr (_CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS);
+#endif
+
+#if defined (_CS_POSIX_V7_ILP32_OFFBIG_LIBS)
+ show_confstr (_CS_POSIX_V7_ILP32_OFFBIG_LIBS);
+#endif
+
+#if defined (_CS_POSIX_V7_ILP32_OFFBIG_LINTFLAGS)
+ show_confstr (_CS_POSIX_V7_ILP32_OFFBIG_LINTFLAGS);
+#endif
+
+#if defined (_CS_POSIX_V7_LP64_OFF64_CFLAGS)
+ show_confstr (_CS_POSIX_V7_LP64_OFF64_CFLAGS);
+#endif
+
+#if defined (_CS_POSIX_V7_LP64_OFF64_LDFLAGS)
+ show_confstr (_CS_POSIX_V7_LP64_OFF64_LDFLAGS);
+#endif
+
+#if defined (_CS_POSIX_V7_LP64_OFF64_LIBS)
+ show_confstr (_CS_POSIX_V7_LP64_OFF64_LIBS);
+#endif
+
+#if defined (_CS_POSIX_V7_LP64_OFF64_LINTFLAGS)
+ show_confstr (_CS_POSIX_V7_LP64_OFF64_LINTFLAGS);
+#endif
+
+#if defined (_CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS)
+ show_confstr (_CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS);
+#endif
+
+#if defined (_CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS)
+ show_confstr (_CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS);
+#endif
+
+#if defined (_CS_POSIX_V7_LPBIG_OFFBIG_LIBS)
+ show_confstr (_CS_POSIX_V7_LPBIG_OFFBIG_LIBS);
+#endif
+
+#if defined (_CS_POSIX_V7_LPBIG_OFFBIG_LINTFLAGS)
+ show_confstr (_CS_POSIX_V7_LPBIG_OFFBIG_LINTFLAGS);
+#endif
+
+#if defined (_CS_V5_WIDTH_RESTRICTED_ENVS)
+ show_confstr (_CS_V5_WIDTH_RESTRICTED_ENVS);
+#endif
+
+#if defined (_CS_V5_WIDTH_RESTRICTED_ENVS)
+ _show_confstr (_CS_V5_WIDTH_RESTRICTED_ENVS, "_XBS5_WIDTH_RESTRICTED_ENVS");
+#endif
+
+#if defined (_CS_V5_WIDTH_RESTRICTED_ENVS)
+ _show_confstr (_CS_V5_WIDTH_RESTRICTED_ENVS, "XBS5_WIDTH_RESTRICTED_ENVS");
+#endif
+
+#if defined (_CS_V6_WIDTH_RESTRICTED_ENVS)
+ show_confstr (_CS_V6_WIDTH_RESTRICTED_ENVS);
+#endif
+
+#if defined (_CS_V6_WIDTH_RESTRICTED_ENVS)
+ _show_confstr (_CS_V6_WIDTH_RESTRICTED_ENVS, "POSIX_V6_WIDTH_RESTRICTED_ENVS,_POSIX_V6_WIDTH_RESTRICTED_ENVS");
+#endif
+
+#if defined (_CS_V7_WIDTH_RESTRICTED_ENVS)
+ show_confstr (_CS_V7_WIDTH_RESTRICTED_ENVS);
+#endif
+
+#if defined (_CS_XBS5_ILP32_OFF32_CFLAGS)
+ show_confstr (_CS_XBS5_ILP32_OFF32_CFLAGS);
+#endif
+
+#if defined (_CS_XBS5_ILP32_OFF32_LDFLAGS)
+ show_confstr (_CS_XBS5_ILP32_OFF32_LDFLAGS);
+#endif
+
+#if defined (_CS_XBS5_ILP32_OFF32_LIBS)
+ show_confstr (_CS_XBS5_ILP32_OFF32_LIBS);
+#endif
+
+#if defined (_CS_XBS5_ILP32_OFF32_LINTFLAGS)
+ show_confstr (_CS_XBS5_ILP32_OFF32_LINTFLAGS);
+#endif
+
+#if defined (_CS_XBS5_ILP32_OFFBIG_CFLAGS)
+ show_confstr (_CS_XBS5_ILP32_OFFBIG_CFLAGS);
+#endif
+
+#if defined (_CS_XBS5_ILP32_OFFBIG_LDFLAGS)
+ show_confstr (_CS_XBS5_ILP32_OFFBIG_LDFLAGS);
+#endif
+
+#if defined (_CS_XBS5_ILP32_OFFBIG_LIBS)
+ show_confstr (_CS_XBS5_ILP32_OFFBIG_LIBS);
+#endif
+
+#if defined (_CS_XBS5_ILP32_OFFBIG_LINTFLAGS)
+ show_confstr (_CS_XBS5_ILP32_OFFBIG_LINTFLAGS);
+#endif
+
+#if defined (_CS_XBS5_LP64_OFF64_CFLAGS)
+ show_confstr (_CS_XBS5_LP64_OFF64_CFLAGS);
+#endif
+
+#if defined (_CS_XBS5_LP64_OFF64_LDFLAGS)
+ show_confstr (_CS_XBS5_LP64_OFF64_LDFLAGS);
+#endif
+
+#if defined (_CS_XBS5_LP64_OFF64_LIBS)
+ show_confstr (_CS_XBS5_LP64_OFF64_LIBS);
+#endif
+
+#if defined (_CS_XBS5_LP64_OFF64_LINTFLAGS)
+ show_confstr (_CS_XBS5_LP64_OFF64_LINTFLAGS);
+#endif
+
+#if defined (_CS_XBS5_LPBIG_OFFBIG_CFLAGS)
+ show_confstr (_CS_XBS5_LPBIG_OFFBIG_CFLAGS);
+#endif
+
+#if defined (_CS_XBS5_LPBIG_OFFBIG_LDFLAGS)
+ show_confstr (_CS_XBS5_LPBIG_OFFBIG_LDFLAGS);
+#endif
+
+#if defined (_CS_XBS5_LPBIG_OFFBIG_LIBS)
+ show_confstr (_CS_XBS5_LPBIG_OFFBIG_LIBS);
+#endif
+
+#if defined (_CS_XBS5_LPBIG_OFFBIG_LINTFLAGS)
+ show_confstr (_CS_XBS5_LPBIG_OFFBIG_LINTFLAGS);
+#endif
+
+
+ footer ();
}
+
#endif
void
@@ -973,10 +2777,10 @@ get_misc (void)
assert (getcwd (misc.cwd, sizeof (misc.cwd)));
#if defined (PROCENV_LINUX)
- get_root (misc.root, sizeof (misc.root));
+ get_canonical (ROOT_PATH, misc.root, sizeof (misc.root));
#endif
-#if defined (PROCENV_BSD) || defined (__FreeBSD_kernel__)
- get_bsd_misc ();
+#if defined (PROCENV_BSD) || defined (PROCENV_GNU_BSD)
+ get_misc_bsd ();
#endif
}
@@ -1007,220 +2811,525 @@ is_console (int fd)
#endif
void
-dump_user (void)
+show_proc (void)
{
header ("process");
- show ("process id (pid): %d", user.pid);
+ entry ("process id (pid)", "%d", user.pid);
- show ("parent process id (ppid): %d", user.ppid);
- show ("session id (sid): %d (leader=%s)",
+ entry ("parent process id (ppid)", "%d", user.ppid);
+ entry ("session id (sid)", "%d (leader=%s)",
user.sid,
is_session_leader () ? YES_STR : NO_STR);
- show ("name: '%s'", user.proc_name);
+ entry ("name", "'%s'", user.proc_name);
show_proc_branch ();
- show ("process group id: %d (leader=%s)",
+ entry ("process group id", "%d (leader=%s)",
user.pgroup,
is_process_group_leader () ? YES_STR : NO_STR);
- show ("foreground process group: %d", user.fg_pgroup);
+ entry ("foreground process group", "%d", user.fg_pgroup);
- show ("terminal: '%s'", user.ctrl_terminal);
+ entry ("terminal", "'%s'", user.ctrl_terminal);
- show ("has controlling terminal: %s",
+ entry ("has controlling terminal", "%s",
has_ctty () ? YES_STR : NO_STR);
#if defined (PROCENV_HURD)
- show ("on console: %s", UNKNOWN_STR);
+ entry ("on console", "%s", UNKNOWN_STR);
#else
- show ("on console: %s",
+ entry ("on console", "%s",
is_console (user.tty_fd) ? YES_STR : NO_STR);
#endif
- show ("real user id (uid): %d ('%s')",
+ section_open ("user");
+
+ entry ("real user id (uid)", "%d ('%s')",
user.uid,
get_user_name (user.uid));
- show ("effective user id (euid): %d ('%s')",
+ entry ("effective user id (euid)", "%d ('%s')",
user.euid,
get_user_name (user.euid));
- show ("saved set-user-id (suid): %d ('%s')",
+ entry ("saved set-user-id (suid)", "%d ('%s')",
user.suid,
get_user_name (user.suid));
- show ("real group id (gid): %d ('%s')",
+ section_close ();
+
+ section_open ("group");
+
+ entry ("real group id (gid)", "%d ('%s')",
user.gid,
get_group_name (user.gid));
- show ("effective group id (egid): %d ('%s')",
+ entry ("effective group id (egid)", "%d ('%s')",
user.egid,
get_group_name (user.egid));
- show ("saved set-group-id (sgid): %d ('%s')",
+ entry ("saved set-group-id (sgid)", "%d ('%s')",
user.sgid,
get_group_name (user.sgid));
- show ("login name: '%s'", user.login ? user.login : "");
+ section_close ();
-#if defined (PROCENV_ANDROID)
+ entry ("login name", "'%s'", user.login ? user.login : "");
+
+ section_open ("passwd");
+
+ entry ("name", "'%s'", user.passwd.pw_name);
+
+#if ! defined (PROCENV_ANDROID)
/* No gecos on Android. In fact it doesn't actually use the
* passwd database, but meh.
*/
- show ("passwd: name='%s', dir='%s', shell='%s'",
- user.passwd.pw_name,
- user.passwd.pw_dir,
- user.passwd.pw_shell);
-#else
- show ("passwd: name='%s', gecos='%s', dir='%s', shell='%s'",
- user.passwd.pw_name,
- user.passwd.pw_gecos,
- user.passwd.pw_dir,
- user.passwd.pw_shell);
+ entry ("gecos", "'%s'", user.passwd.pw_gecos);
#endif
+
+ entry ("dir", "'%s'", user.passwd.pw_dir);
+ entry ("shell", "'%s'", user.passwd.pw_shell);
+
+ section_close ();
+
show_all_groups ();
+
+ footer ();
}
void
-dump_priorities (void)
+show_priorities (void)
{
- show ("scheduler priority: process=%d, process group=%d, user=%d",
- priority.process,
- priority.pgrp,
- priority.user);
+#if defined (PROCENV_LINUX)
+ int sched;
+
+ sched = sched_getscheduler (0);
+#endif
+
+ section_open ("scheduler");
+
+#if defined (PROCENV_LINUX)
+ entry ("type", "%s",
+ sched < 0 ? UNKNOWN_STR :
+ get_scheduler_name (sched));
+#endif
+
+ section_open ("priority");
+
+ entry ("process", "%d", priority.process);
+ entry ("process group", "%d", priority.pgrp);
+ entry ("user", "%d", priority.user);
+
+ section_close ();
+
+ section_close ();
}
void
-dump_misc (void)
+show_misc (void)
{
+#if defined (PROCENV_LINUX)
+ int domain = 0x0;
+
+ /* magic value - see personality(2) */
+ unsigned int persona = 0xFFFFFFFF;
+
+ unsigned int mask = PER_MASK;
+
+ const char *personality_name = NULL;
+ char *personality_flags = NULL;
+#endif
+
header ("misc");
- show ("umask: %4.4o", misc.umask_value);
- show ("current directory (cwd): '%s'", misc.cwd);
+ entry ("umask", "%4.4o", misc.umask_value);
+ entry ("current directory (cwd)", "'%s'", misc.cwd);
#if defined (PROCENV_LINUX)
- show ("root: %s%s%s",
+ entry ("root", "%s%s%s",
strcmp (misc.root, UNKNOWN_STR) ? "'" : "",
misc.root,
strcmp (misc.root, UNKNOWN_STR) ? "'" : "");
#endif
- show ("chroot: %s", in_chroot () ? YES_STR : NO_STR);
+ entry ("chroot", "%s", in_chroot () ? YES_STR : NO_STR);
+ entry ("container", "%s", container_type ());
+
#if defined (PROCENV_LINUX)
- show_linux_prctl ();
- show_linux_security_module ();
- show_linux_security_module_context ();
-#endif
- show ("container: %s", container_type ());
+ show_prctl_linux ();
- show_cpu ();
- dump_priorities ();
- show ("memory page size: %d bytes", getpagesize ());
+ section_open ("linux security module");
+ show_security_module_linux ();
+ show_security_module_context_linux ();
+ section_close ();
+#endif
#if defined (PROCENV_LINUX)
#ifdef LINUX_VERSION_CODE
- show ("kernel headers version: %u.%u.%u",
+ entry ("kernel headers version", "%u.%u.%u",
(LINUX_VERSION_CODE >> 16),
((LINUX_VERSION_CODE >> 8) & 0xFF),
(LINUX_VERSION_CODE & 0xFF));
#endif
+
+ domain = personality (persona);
+
+ personality_name = get_personality_name (domain & mask);
+
+ section_open ("personality");
+
+ entry ("type", "%s", personality_name
+ ? personality_name
+ : UNKNOWN_STR);
+
+ personality_flags = get_personality_flags (domain & (-1 ^ mask));
+ entry ("flags", "%s",
+ personality_flags
+ ? personality_flags
+ : "");
+
+ section_close ();
+
+ if (personality_flags)
+ free (personality_flags);
#endif
+
+ footer ();
}
void
-dump_platform (void)
+show_platform (void)
{
long kernel_bits;
long executable_bits;
header ("platform");
- show ("operating system: %s", get_os ());
- show ("architecture: %s", get_arch ());
+ entry ("operating system", "%s", get_os ());
+ entry ("architecture", "%s", get_arch ());
kernel_bits = get_kernel_bits ();
executable_bits = sizeof (void *) * CHAR_BIT * sizeof (char);
if (kernel_bits == -1)
- show ("kernel bits: %s", UNKNOWN_STR);
+ entry ("kernel bits", "%s", UNKNOWN_STR);
else
- show ("kernel bits: %lu", kernel_bits);
+ entry ("kernel bits", "%lu", kernel_bits);
- show ("executable bits: %lu", executable_bits);
+ entry ("executable bits", "%lu", executable_bits);
- show ("code endian: %s",
+ entry ("code endian", "%s",
is_big_endian () ? BIG_STR : LITTLE_STR);
+
show_data_model ();
+
+ footer ();
}
void
show_cpu (void)
{
+ header ("cpu");
+
#if defined (PROCENV_LINUX)
- show_linux_cpu ();
- show_linux_scheduler ();
+ show_cpu_linux ();
#endif
#if defined (PROCENV_BSD)
- show_bsd_cpu ();
+ show_cpu_bsd ();
#endif
+ show_cpu_affinities ();
+
+ show_priorities ();
+
+ footer ();
}
void
-dump_fds (void)
+show_memory (void)
{
- int fd;
- int max;
+ header ("memory");
- header ("fds");
- max = sysconf (_SC_OPEN_MAX);
+ entry ("page size", "%d bytes", getpagesize ());
- for (fd = 0; fd < max; fd++) {
- if (fd_valid (fd)) {
- int is_tty = isatty (fd);
- char *name = NULL;
+#if defined (PROCENV_LINUX)
+ show_numa_memory ();
+#endif /* PROCENV_LINUX */
- if (is_tty) {
-#if ! defined (PROCENV_ANDROID)
- name = ttyname (fd);
+ footer ();
+}
+
+/* Display cpu affinities in the same compressed but reasonably
+ * human-readable fashion as /proc/self/status:Cpus_allowed_list under Linux.
+ */
+void
+show_cpu_affinities (void)
+{
+ int ret = 0;
+ long max;
+ size_t size;
+#if defined (PROCENV_BSD) || ! defined (CPU_ALLOC)
+ PROCENV_CPU_SET_TYPE cpu_set_real;
#endif
- show ("fd %d: terminal=%s ('%s')", fd,
- is_tty ? YES_STR : NO_STR,
- name ? name : NA_STR);
- } else {
- show ("fd %d: terminal=%s", fd, NO_STR);
+ PROCENV_CPU_SET_TYPE *cpu_set;
+ long cpu;
+ char *cpu_list = NULL;
+
+ /* TRUE if any enabled cpus have been displayed yet */
+ int displayed = FALSE;
+
+ /* Number of cpu's in *current* range */
+ size_t count = 0;
+
+ /* Only valid to read these when count is >0 */
+ size_t last = 0;
+ size_t first = 0;
+
+ max = get_sysconf (_SC_NPROCESSORS_ONLN);
+ if (max < 0)
+ die ("failed to query cpu count");
+
+#if defined (PROCENV_LINUX) || defined (PROCENV_GNU_BSD) || defined (PROCENV_HURD)
+
+#if defined (CPU_ALLOC)
+
+ cpu_set = CPU_ALLOC (max);
+ assert (cpu_set);
+
+ size = CPU_ALLOC_SIZE (max);
+ CPU_ZERO_S (size, cpu_set);
+
+#else /* ! CPU_ALLOC */
+
+ /* RHEL 5 */
+
+ cpu_set = &cpu_set_real;
+
+ size = sizeof (PROCENV_CPU_SET_TYPE);
+
+#endif /* CPU_ALLOC */
+
+#elif defined (PROCENV_BSD) || ! defined (CPU_ALLOC)
+ cpu_set = &cpu_set_real;
+
+ size = sizeof (PROCENV_CPU_SET_TYPE);
+
+#endif /* PROCENV_LINUX || PROCENV_GNU_BSD || PROCENV_HURD */
+
+ /* We could use sched_getaffinity(2) rather than
+ * sched_getaffinity() on Linux (2.5.8+) but
+ * pthread_getaffinity_np() provides the same information...
+ * Except it is missing on kFreeBSD systems (!) so we have to
+ * use sched_getaffinity() there. :(
+ */
+#if (defined (PROCENV_GNU_BSD) || defined (PROCENV_HURD)) || (defined (PROCENV_LINUX) && ! defined (CPU_ALLOC))
+ ret = sched_getaffinity (0, size, cpu_set);
+#else
+
+#if defined (PROCENV_LINUX) && defined (CPU_ALLOC)
+ /* On a hyperthreaded system, "size" as above may not actually
+ be big enough, and we get EINVAL. (hwloc has a similar
+ workaround.) */
+
+ {
+ int mult = 0;
+ while ((ret = pthread_getaffinity_np (pthread_self (), size, cpu_set))
+ == EINVAL) {
+ CPU_FREE (cpu_set);
+ /* Bail out at an arbitrary value. */
+ if (mult > 128) break;
+ mult += 2;
+ cpu_set = CPU_ALLOC (mult * max);
+ size = CPU_ALLOC_SIZE (mult * max);
+ CPU_ZERO_S (size, cpu_set);
+ }
+ }
+#endif /* PROCENV_LINUX && CPU_ALLOC */
+
+#endif
+
+ if (ret)
+ goto out;
+
+ for (cpu = 0; cpu < max; cpu++) {
+
+ if (CPU_ISSET (cpu, cpu_set)) {
+
+ /* Record first entry in the range */
+ if (! count)
+ first = cpu;
+
+ last = cpu;
+ count++;
+ } else {
+ if (count) {
+ if (first == last) {
+ appendf (&cpu_list, "%s%d",
+ displayed ? "," : "",
+ first);
+ } else {
+ appendf (&cpu_list, "%s%d-%d",
+ displayed ? "," : "",
+ first, last);
+ }
+ displayed = TRUE;
}
+
+ /* Reset */
+ count = 0;
+ }
+ }
+
+ if (count) {
+ if (first == last) {
+ appendf (&cpu_list, "%s%d",
+ displayed ? "," : "",
+ first);
+ } else {
+ appendf (&cpu_list, "%s%d-%d",
+ displayed ? "," : "",
+ first, last);
}
}
+out:
+ entry ("affinity list", "%s", cpu_list ? cpu_list : "-1");
+
+#if defined (PROCENV_LINUX) || defined (PROCENV_GNU_BSD) || defined (PROCENV_HURD)
+#if defined (CPU_ALLOC)
+ CPU_FREE (cpu_set);
+#endif
+#endif
+
+ free (cpu_list);
+}
+
+
+void
+show_fds (void)
+{
#if defined (PROCENV_LINUX)
- dump_linux_proc_fds ();
+ show_fds_linux ();
+#else
+ show_fds_generic ();
+#endif
+
+}
+
+void
+show_namespaces (void)
+{
+#if defined (PROCENV_LINUX)
+ show_namespaces_linux ();
+#else
+ show_namespaces_stub ();
+#endif
+
+}
+
+void
+show_fds_generic (void)
+{
+ int fd;
+ int max;
+
+ container_open ("file descriptors");
+
+ max = get_sysconf (_SC_OPEN_MAX);
+
+ for (fd = 0; fd < max; fd++) {
+ int is_tty = isatty (fd);
+ char *name = NULL;
+ char *num = NULL;
+
+ if (! fd_valid (fd))
+ continue;
+
+#if ! defined (PROCENV_ANDROID)
+ name = ttyname (fd);
+#endif
+ appendf (&num, "%d", fd);
+
+ object_open (FALSE);
+
+ section_open (num);
+
+ entry ("terminal", "%s", is_tty ? YES_STR : NO_STR);
+ entry ("valid", "%s", fd_valid (fd) ? YES_STR : NO_STR);
+ entry ("device", "%s", name ? name : NA_STR);
+
+ section_open ("capabilities");
+#if defined (PROCENV_BSD) && defined (HAVE_SYS_CAPABILITY_H)
+ show_capabilities_bsd (fd);
#endif
+ section_close ();
+
+ section_close ();
+
+ object_close (FALSE);
+ free (num);
+ }
+
+ container_close ();
}
void
show_env (void)
{
char **env = environ;
+ char **copy;
+ char *name;
+ char *value;
size_t i;
+ size_t max;
header ("environment");
/* Calculate size of environment array */
- for (i=0; env[i]; i++)
+ for (max=0; env[max]; max++)
;
- /* sort it */
+ copy = calloc (1+max, sizeof (char *));
+ if (! copy)
+ die ("failed to alloate storage");
+
+ /* Copy the environ array since modification is not allowed */
+ for (i=0; i < max; i++) {
+ copy[i] = calloc (1, 1+strlen (env[i]));
+ if (! copy[i])
+ die ("failed to alloate storage");
+ strcpy (copy[i], env[i]);
+ }
+
+ /* Terminate */
+ copy[max] = NULL;
+
+ /* Sort */
+ env = copy;
qsort (env, i, sizeof (env[0]), qsort_compar);
- env = environ;
+ /* Display */
+ env = copy;
while (env && *env) {
- show ("%s", *env);
+ name = *env;
+ value = strchr (name, '=');
+ assert (value);
+ *value = '\0';
+ value++;
+
+ entry (name, "%s", value);
env++;
}
+
+ /* Tidy up */
+ for (i = 0; i < max; i++)
+ free (copy[i]);
+
+ free (copy);
+
+ footer ();
}
int
@@ -1308,82 +3417,462 @@ get_user_info (void)
assert (p == (void *)&user.passwd);
}
-/* append @new to @orig */
+/* append @src to @dest */
void
-append (char **str, const char *new)
+append (char **dest, const char *src)
{
- size_t len;
- size_t total;
+ size_t len;
- assert (str);
- assert (new);
+ assert (dest);
+ assert (src);
- if (! *str)
- *str = strdup ("");
+ len = strlen (src);
- assert (*str);
+ appendn (dest, src, len);
+}
- /* +1 for terminating nul */
- total = strlen (*str) + 1;
+/* Version of append() that operates on a wide string @dest and @src */
+void
+wappend (pstring **dest, const wchar_t *src)
+{
+ size_t len;
- len = strlen (new);
+ assert (dest);
+ assert (src);
- /* +1 for comma-delimiter */
- total += len + 1;
+ len = wcslen (src);
- *str = realloc (*str, total);
- assert (*str);
- strcat (*str, new);
+ wappendn (dest, src, len);
}
-/* append fmt and args to @str */
+/* Version of append() that operates on a wide string @dest
+ * and multi-byte @src.
+ */
void
-appendf (char **str, const char *fmt, ...)
+wmappend (pstring **dest, const char *src)
{
- va_list ap;
- char *new = NULL;
+ wchar_t *wide_src = NULL;
- assert (str);
- assert (fmt);
+ assert (dest);
+ assert (src);
- if (! *str)
- *str = strdup ("");
+ wide_src = char_to_wchar (src);
+ if (! wide_src)
+ die ("failed to allocate space for wide string");
- assert (*str);
+ wappend (dest, wide_src);
- va_start (ap, fmt);
+ free (wide_src);
+}
- if (vasprintf (&new, fmt, ap) < 0) {
- perror ("vasprintf");
- exit (EXIT_FAILURE);
- }
+/**
+ * appendn:
+ *
+ * @dest: [output] string to append to,
+ * @src: string to append to @dest,
+ * @len: length of @new.
+ *
+ * Append first @len bytes of @new to @str,
+ * ensuring result is nul-terminated.
+ **/
+void
+appendn (char **dest, const char *src, size_t len)
+{
+ size_t total;
- va_end (ap);
+ assert (dest);
+ assert (src);
+
+ if (! len)
+ return;
- append (str, new);
- free (new);
+ if (! *dest)
+ *dest = strdup ("");
+ if (! *dest)
+ die ("failed to allocate space for string");
+
+ /* +1 for terminating nul */
+ total = strlen (*dest) + 1;
+
+ total += len;
+
+ *dest = realloc (*dest, total);
+ assert (*dest);
+
+ if (! *dest) {
+ /* string is empty, so initialise the memory to avoid
+ * surprises with strncat() being unable to find the
+ * terminator!
+ */
+ memset (*dest, '\0', total);
+ }
+
+ strncat (*dest, src, len);
+
+ assert ((*dest)[total-1] == '\0');
}
+/* Version of appendn() that operates on a wide string @dest and @src */
void
-appendva (char **str, const char *fmt, va_list ap)
+wappendn (pstring **dest, const wchar_t *src, size_t len)
{
- char *new = NULL;
+ wchar_t *p;
+ size_t total;
+ size_t bytes;
+
+ assert (dest);
+ assert (src);
- assert (str);
- assert (fmt);
+ if (! len)
+ return;
- if (! *str)
- *str = strdup ("");
+ if (! *dest)
+ *dest = pstring_new ();
+ if (! *dest)
+ die ("failed to allocate space for pstring");
- assert (*str);
+ total = (*dest)->len + len;
- if (vasprintf (&new, fmt, ap) < 0) {
- perror ("vasprintf");
- exit (EXIT_FAILURE);
- }
+ /* +1 for terminating nul */
+ bytes = (1 + total) * sizeof (wchar_t);
+
+ p = realloc ((*dest)->buf, bytes);
+
+ /* FIXME: turn into die() [all occurences!] */
+ assert (p);
+
+ (*dest)->buf = p;
+
+ if (! (*dest)->len) {
+ /* pstring is empty, so initialise the memory to avoid
+ * surprises with wcsncat() being unable to find the
+ * terminator!
+ */
+ memset ((*dest)->buf, 0, bytes);
+ }
+
+ /* Used to check for overrun */
+ (*dest)->buf[total] = L'\0';
+
+ wcsncat ((*dest)->buf + (*dest)->len, src, len);
+
+ /* update */
+ (*dest)->len = total;
+ (*dest)->size = bytes;
+
+ /* check for overrun */
+ assert ((*dest)->buf[total] == L'\0');
+}
+
+
+/* Version of appendn() that operates on a wide string @dest and
+ * multi-byte @src.
+ */
+void
+wmappendn (pstring **dest, const char *src, size_t len)
+{
+ wchar_t *wide_src = NULL;
+
+ assert (dest);
+ assert (src);
+
+ if (! len)
+ return;
+
+ wide_src = char_to_wchar (src);
+ if (! wide_src)
+ die ("failed to allocate space for wide string");
+
+ wappendn (dest, wide_src, wcslen (wide_src));
+
+ free (wide_src);
+}
+
+/* append @fmt and args to @dest */
+void
+appendf (char **dest, const char *fmt, ...)
+{
+ va_list ap;
+
+ assert (dest);
+ assert (fmt);
+
+ va_start (ap, fmt);
+
+ appendva (dest, fmt, ap);
+
+ va_end (ap);
+}
+
+/* Version of appendf() that operates on a wide string @dest
+ * and @fmt.
+ */
+void
+wappendf (pstring **dest, const wchar_t *fmt, ...)
+{
+ va_list ap;
+
+ assert (dest);
+ assert (fmt);
+
+ va_start (ap, fmt);
+
+ wappendva (dest, fmt, ap);
+
+ va_end (ap);
+}
+
+/* Version of appendf() that operates on a wide string @dest
+ * and multi-byte @fmt.
+ */
+void
+wmappendf (pstring **dest, const char *fmt, ...)
+{
+ wchar_t *wide_fmt = NULL;
+ va_list ap;
+
+ assert (dest);
+ assert (fmt);
+
+ wide_fmt = char_to_wchar (fmt);
+ if (! wide_fmt)
+ die ("failed to allocate memory for wide format");
+
+ va_start (ap, fmt);
+
+ wappendva (dest, wide_fmt, ap);
+
+ va_end (ap);
+
+ free (wide_fmt);
+}
+
+/* append @fmt and args to @dest */
+void
+appendva (char **dest, const char *fmt, va_list ap)
+{
+ int ret;
+ char *new = NULL;
+ char *p;
+ size_t bytes;
+
+ /* Start with a guess for how big we think the buffer needs to
+ * be.
+ */
+ size_t len = DEFAULT_ALLOC_GUESS_SIZE;
+
+ assert (dest);
+ assert (fmt);
+
+ bytes = (1 + len) * sizeof (char);
+
+ /* we could use vasprintf(3), but that's GNU-specific and hence
+ * not available everywhere we need it.
+ */
+ new = malloc (bytes);
+ if (! new)
+ die ("failed to allocate space for string");
+
+ memset (new, '\0', bytes);
+
+ /* keep on increasing size of buffer until the translation
+ * succeeds.
+ */
+ while (TRUE) {
+ va_list ap_copy;
+
+ va_copy (ap_copy, ap);
+ ret = vsnprintf (new, len, fmt, ap_copy);
+ va_end (ap_copy);
+
+ if (ret < 0)
+ die ("failed to format string");
+
+ if ((size_t)ret < len) {
+ /* now we have sufficient space */
+ break;
+ }
+
+ /* Bump to allow one char to be written */
+ len++;
+
+ /* recalculate number of bytes */
+ bytes = (1 + len) * sizeof (char);
+
+ p = realloc (new, bytes);
+ if (! p)
+ die ("failed to allocate space for string");
+
+ new = p;
+ }
+
+ if (*dest) {
+ append (dest, new);
+ free (new);
+ } else {
+ *dest = new;
+ }
+}
+
+/* Version of appendva() that operates on a wide string @dest
+ * and @fmt.
+ */
+void
+wappendva (pstring **dest, const wchar_t *fmt, va_list ap)
+{
+ int ret;
+ wchar_t *new = NULL;
+ wchar_t *p;
+ size_t bytes;
+ va_list ap_copy;
+
+ /* Start with a guess for how big we think the buffer needs to
+ * be.
+ */
+ size_t len = DEFAULT_ALLOC_GUESS_SIZE;
+
+ assert (dest);
+ assert (fmt);
+
+ bytes = (1 + len) * sizeof (wchar_t);
+
+ new = malloc (bytes);
+ if (! new)
+ die ("failed to allocate space for wide string");
+
+ memset (new, '\0', bytes);
+
+ /* keep on increasing size of buffer until the translation
+ * succeeds.
+ */
+ while (TRUE) {
+ va_copy (ap_copy, ap);
+ ret = vswprintf (new, len, fmt, ap_copy);
+ va_end (ap_copy);
+
+ if ((size_t)ret < len) {
+ /* now we have sufficient space, so update for
+ * actual number of bytes used (including the
+ * terminator!)
+ *
+ * Note that, conveniently, if the string is
+ * zero-characters long (ie ""), ret will be -1
+ * which we correct to 0.
+ */
+ len = ret + 1;
+
+ break;
+ }
+
+ /* Bump to allow one more wide-char to be written */
+ len++;
+
+ /* recalculate number of bytes */
+ bytes = (1 + len) * sizeof (wchar_t);
+
+ p = realloc (new, bytes);
+ if (! p)
+ die ("failed to allocate space for string");
+
+ new = p;
+
+ memset (new, '\0', bytes);
+ }
+
+ if (*dest) {
+ wappend (dest, new);
+ free (new);
+ } else {
+ wchar_t *n;
+
+ /* recalculate number of bytes */
+ bytes = (1 + len) * sizeof (wchar_t);
+
+ /* compress */
+ n = realloc (new, bytes);
+
+ if (! n)
+ die ("failed to reallocate space");
+
+ new = n;
+
+ (*dest) = pstring_new ();
+ assert (*dest);
+ (*dest)->buf = new;
+ (*dest)->len = len;
+ (*dest)->size = bytes;
+ }
+}
+
+/* Version of appendva() that operates on a wide string @dest
+ * and multi-byte @fmt.
+ */
+void
+wmappendva (pstring **dest, const char *fmt, va_list ap)
+{
+ wchar_t *wide_fmt = NULL;
+ va_list ap_copy;
+
+ assert (dest);
+ assert (fmt);
+
+ wide_fmt = char_to_wchar (fmt);
+ if (! wide_fmt)
+ die ("failed to allocate memory for wide format");
+
+ va_copy (ap_copy, ap);
+ wappendva (dest, wide_fmt, ap_copy);
+ va_end (ap_copy);
- append (str, new);
- free (new);
+ free (wide_fmt);
+}
+
+/*
+ * Append @src onto the end of @dest.
+ */
+void
+pappend (pstring **dest, const pstring *src)
+{
+ size_t total;
+ size_t bytes;
+ wchar_t *p;
+
+ assert (dest);
+ assert (src);
+
+ if (! src->len)
+ return;
+
+ if (! *dest)
+ *dest = pstring_new ();
+ if (! *dest)
+ die ("failed to allocate space for pstring");
+
+ total = (*dest)->len + src->len;
+
+ /* adjust since we only store _one_ of the string terminators
+ * from @dest and @src.
+ */
+ total--;
+
+ /* +1 for terminating nul */
+ bytes = (1 + total) * sizeof (wchar_t);
+
+ p = realloc ((*dest)->buf, bytes);
+
+ /* FIXME: turn into die() [all occurences!] */
+ assert (p);
+
+ (*dest)->buf = p;
+
+ wcsncat ((*dest)->buf + (*dest)->len, src->buf, src->len);
+
+ /* update */
+ (*dest)->len = total;
+ (*dest)->size = bytes;
+
+ /* Used to check for overrun */
+ (*dest)->buf[total] = L'\0';
}
void
@@ -1391,7 +3880,7 @@ show_all_groups (void)
{
int i;
int ret;
- char *str;
+ char *str = NULL;
/* Initial number of groups we'll try to read. If this isn't
* enough, we increase it to make rooom for all available
@@ -1400,25 +3889,32 @@ show_all_groups (void)
int size = 32;
gid_t *groups = NULL;
+ gid_t *g;
char **group_names = NULL;
+ size_t bytes;
+
+ bytes = size * sizeof (gid_t);
- groups = malloc (size * sizeof (gid_t));
+ groups = malloc (bytes);
if (! groups)
goto error;
+ memset (groups, '\0', bytes);
+
while (TRUE) {
ret = getgroups (size, groups);
if (ret >= 0)
break;
size++;
- groups = realloc (groups, (size * sizeof (gid_t)));
- if (! groups)
+ g = realloc (groups, (size * sizeof (gid_t)));
+ if (! g) {
+ free (groups);
goto error;
- }
+ }
- str = strdup ("groups:");
- assert (str);
+ groups = g;
+ }
size = ret;
@@ -1429,15 +3925,14 @@ show_all_groups (void)
group = get_group_name (user.passwd.pw_gid);
if (! group) {
- show (str);
- free (str);
+ entry ("groups", "%s", UNKNOWN_STR);
return;
}
appendf (&str, " '%s' (%d)",
group,
user.passwd.pw_gid);
- show (str);
+ entry ("groups", "%s", str);
free (str);
return;
}
@@ -1450,10 +3945,8 @@ show_all_groups (void)
appendf (&str, " ");
for (i = 0; i < size; i++) {
- ret = asprintf (&group_names[i], "'%s' (%d)",
+ appendf (&group_names[i], "'%s' (%d)",
get_group_name (groups[i]), groups[i]);
- if (ret < 0)
- die ("unable to create group entry");
}
qsort (group_names, size, sizeof (char *), qsort_compar);
@@ -1468,7 +3961,7 @@ show_all_groups (void)
free (group_names);
free (groups);
- show (str);
+ entry ("groups", "%s", str);
free (str);
return;
@@ -1478,15 +3971,63 @@ error:
}
void
-set_indent (void)
+save_locale (void)
{
- indent = selected_option ? 0 : INDENT;
+ char *value;
+
+ assert (! saved_locale);
+
+ /* save the existing value, but crucially also load the correct
+ * locale from the environment to enable UTF-8 functionality.
+ */
+ value = setlocale (LC_ALL, "");
+ if (! value) {
+ /* Can't determine locale, so ignore */
+ return;
+ }
+
+ saved_locale = strdup (value);
+ if (! saved_locale)
+ die ("failed to allocate space for locale");
+
+ if (atexit (restore_locale))
+ die ("failed to register exit handler");
+}
+
+void
+restore_locale (void)
+{
+ if (! saved_locale) {
+ /* Nothing to do */
+ return;
+ }
+
+ (void)setlocale (LC_ALL, saved_locale);
+
+ free (saved_locale);
+}
+
+void
+handle_indent_char (void)
+{
+ size_t len;
+
+ const char *new = indent_char;
+
+ len = mbsrtowcs (NULL, &new, 0, NULL);
+ if (len != 1)
+ die ("invalid indent character");
+
+ if (mbsrtowcs (&wide_indent_char, &new, len, NULL) != len)
+ die ("failed to convert indent character");
}
void
init (void)
{
- set_indent ();
+ save_locale ();
+
+ handle_indent_char ();
/* required to allow for more graceful handling of prctl(2)
* options that were introduced in kernel version 'x.y'.
@@ -1496,12 +4037,14 @@ init (void)
get_user_info ();
get_misc ();
get_priorities ();
-
}
void
cleanup (void)
{
+ common_assert ();
+ assert (doc);
+
close (user.tty_fd);
if (output_fd != -1)
@@ -1509,6 +4052,13 @@ cleanup (void)
if (output == OUTPUT_SYSLOG)
closelog ();
+
+ if (output_format == OUTPUT_FORMAT_CRUMB && crumb_list) {
+ clear_breadcrumbs ();
+ free (crumb_list);
+ }
+
+ pstring_free (doc);
}
/**
@@ -1528,27 +4078,61 @@ is_big_endian (void)
}
void
-dump_meta (void)
+show_meta (void)
{
- header (PACKAGE_NAME);
+ const char *build_type;
+
+#if defined (PROCENV_REPRODUCIBLE_BUILD)
+ build_type = BUILD_TYPE_REPRODUCIBLE_STR;
+#else
+ build_type = BUILD_TYPE_STD_STR;
+#endif
+
+ header ("meta");
+
+ entry ("version", "%s", PACKAGE_VERSION);
- show ("version: %s", PACKAGE_STRING);
- show ("mode: %s%s",
+ entry ("package", "%s", PACKAGE_STRING);
+ entry ("mode", "%s%s",
user.euid ? _(NON_STR) "-" : "",
PRIVILEGED_STR);
+
+ entry ("build-type", "%s", build_type);
+
+ entry ("format-type", "%s", get_output_format_name ());
+ entry ("format-version", "%d", PROCENV_FORMAT_VERSION);
+
+ footer ();
}
void
show_arguments (void)
{
- int i;
+ int i;
header ("arguments");
- show ("count: %u", argvc);
+ entry ("count", "%u", argvc);
+
+ container_open ("list");
+
+ for (i = 0; i < argvc; i++) {
+ char *buffer = NULL;
- for (i = 0; i < argvc; i++)
- show ("argv[%d]='%s'", i, argvp[i]);
+ appendf (&buffer, "argv[%d]", i);
+
+ object_open (FALSE);
+
+ entry (buffer, "%s", argvp[i]);
+
+ object_close (FALSE);
+
+ free (buffer);
+ }
+
+ container_close ();
+
+ footer ();
}
void
@@ -1556,10 +4140,11 @@ show_stat (void)
{
struct stat st;
char real_path[PATH_MAX];
- char formatted_time[32];
- char modestr[10+1];
+ char formatted_atime[32];
+ char formatted_ctime[32];
+ char formatted_mtime[32];
+ char *modestr;
mode_t perms;
- int i = 0;
char *tmp = NULL;
assert (program_name);
@@ -1577,32 +4162,24 @@ show_stat (void)
die ("unable to stat path: '%s'", real_path);
header ("stat");
- show ("argv[0]: '%s'", program_name);
- show ("real path: '%s'", real_path);
- show ("dev: major=%u, minor=%u",
- major (st.st_dev), minor (st.st_dev));
- show ("inode: %lu", (unsigned long int)st.st_ino);
- memset (modestr, '\0', sizeof (modestr));
+ entry ("argv[0]", "'%s'", program_name);
+ entry ("real path", "'%s'", real_path);
- modestr[i++] = (S_ISLNK (st.st_mode & S_IFMT)) ? 'l' : '-';
+ section_open ("device");
- perms = (st.st_mode & S_IRWXU);
- modestr[i++] = (perms & S_IRUSR) ? 'r' : '-';
- modestr[i++] = (perms & S_IWUSR) ? 'w' : '-';
- modestr[i++] = (perms & S_IXUSR) ? 'x' : '-';
+ entry ("major", "%u", major (st.st_dev));
+ entry ("minor", "%u", minor (st.st_dev));
- perms = (st.st_mode & S_IRWXG);
- modestr[i++] = (perms & S_IRGRP) ? 'r' : '-';
- modestr[i++] = (perms & S_IWGRP) ? 'w' : '-';
- modestr[i++] = (perms & S_IXGRP) ? 'x' : '-';
+ section_close ();
- perms = (st.st_mode & S_IRWXO);
- modestr[i++] = (perms & S_IROTH) ? 'r' : '-';
- modestr[i++] = (perms & S_IWOTH) ? 'w' : '-';
- modestr[i++] = (perms & S_IXOTH) ? 'x' : '-';
+ entry ("inode", "%lu", (unsigned long int)st.st_ino);
+ modestr = format_perms (st.st_mode);
+ if (! modestr)
+ die ("failed to allocate space for permissions string");
perms = (st.st_mode &= ~S_IFMT);
+
if (perms & S_ISUID)
modestr[3] = 's';
if (perms & S_ISGID)
@@ -1610,28 +4187,45 @@ show_stat (void)
if (perms & S_ISVTX)
modestr[9] = 't';
- show ("permissions: %4.4o (%s)", perms, modestr);
+ section_open ("permissions");
+
+ entry ("octal", "%4.4o", perms);
+ entry ("symbolic", "%s", modestr);
+ free (modestr);
+
+ section_close ();
- show ("hard links: %u", st.st_nlink);
- show ("user id (uid): %d ('%s')", st.st_uid, get_user_name (st.st_uid));
- show ("group id (gid): %d ('%s')", st.st_gid, get_group_name (st.st_uid));
- show ("size: %lu bytes (%lu 512-byte blocks)", st.st_size, st.st_blocks);
+ entry ("hard links", "%u", st.st_nlink);
+ entry ("user id (uid)", "%d ('%s')", st.st_uid, get_user_name (st.st_uid));
+ entry ("group id (gid)", "%d ('%s')", st.st_gid, get_group_name (st.st_uid));
+ entry ("size", "%lu bytes (%lu 512-byte blocks)", st.st_size, st.st_blocks);
- if (! ctime_r ((time_t *)&st.st_atime, formatted_time))
+ /*****************************************/
+ section_open ("times");
+
+ if (! ctime_r ((time_t *)&st.st_atime, formatted_atime))
die ("failed to format atime");
- formatted_time[ strlen (formatted_time)-1] = '\0';
- show ("atime: %lu (%s)", st.st_atime, formatted_time);
+ formatted_atime[ strlen (formatted_atime)-1] = '\0';
+ entry ("atime (access)", "%lu (%s)", st.st_atime, formatted_atime);
- if (! ctime_r ((time_t *)&st.st_mtime, formatted_time))
+ if (! ctime_r ((time_t *)&st.st_mtime, formatted_mtime))
die ("failed to format mtime");
- formatted_time[ strlen (formatted_time)-1] = '\0';
- show ("mtime: %lu (%s)", st.st_mtime, formatted_time);
+ formatted_mtime[ strlen (formatted_mtime)-1] = '\0';
+
+ entry ("mtime (modification)", "%lu (%s)", st.st_mtime, formatted_mtime);
- if (! ctime_r ((time_t *)&st.st_ctime, formatted_time))
+ if (! ctime_r ((time_t *)&st.st_ctime, formatted_ctime))
die ("failed to format ctime");
- formatted_time[ strlen (formatted_time)-1] = '\0';
- show ("ctime: %lu (%s)", st.st_ctime, formatted_time);
+ formatted_ctime[ strlen (formatted_ctime)-1] = '\0';
+
+ entry ("ctime (status change)", "%lu (%s)", st.st_ctime, formatted_ctime);
+
+ section_close ();
+
+ /*****************************************/
+
+ footer ();
}
long
@@ -1641,9 +4235,9 @@ get_kernel_bits (void)
long value;
errno = 0;
- value = sysconf (_SC_LONG_BIT);
+ value = get_sysconf (_SC_LONG_BIT);
if (value == -1 && errno != 0)
- die ("failed to determine kernel bits");
+ return -1;
return value;
#endif
return -1;
@@ -1653,49 +4247,55 @@ get_kernel_bits (void)
void
dump (void)
{
- dump_meta ();
+ master_header (&doc);
+
+ show_meta ();
show_arguments ();
-#if defined (PROCENV_LINUX)
show_capabilities ();
- show_linux_cgroups ();
-#endif
+ show_cgroups ();
show_clocks ();
show_compiler ();
#ifndef PROCENV_ANDROID
show_confstrs ();
#endif
+ show_cpu ();
show_env ();
- dump_fds ();
+ show_fds ();
+ show_libc ();
#ifndef PROCENV_ANDROID
show_libs ();
#endif
show_rlimits ();
show_locale ();
- dump_misc ();
+ show_memory ();
+ show_msg_queues ();
+ show_misc ();
show_mounts (SHOW_ALL);
+ show_namespaces ();
show_network ();
-#if defined (PROCENV_LINUX)
show_oom ();
-#endif
- dump_platform ();
- dump_user ();
+ show_platform ();
+ show_proc ();
show_ranges ();
/* We should really call this last, to make figures as reliable
* as possible.
*/
show_rusage ();
-
+ show_semaphores ();
+ show_shared_mem ();
show_signals ();
show_sizeof ();
show_stat ();
- dump_sysconf ();
+ show_sysconf ();
show_threads ();
show_time ();
show_timezone ();
show_tty_attrs ();
- dump_uname ();
+ show_uname ();
+
+ master_footer (&doc);
}
void
get_network_address (const struct sockaddr *address, int family, char *name)
@@ -1731,57 +4331,52 @@ get_network_address (const struct sockaddr *address, int family, char *name)
assert (name[NI_MAXHOST-1] == '\0');
}
-char *
+void
decode_if_flags (unsigned int flags)
{
- char *str = NULL;
struct if_flag_map *p;
- int first = TRUE;
for (p = if_flag_map; p && p->name; p++) {
if (flags & p->flag) {
- appendf (&str, "%s%s",
- first ? "" : ",",
- p->name);
- first = FALSE;
+ object_open (FALSE);
+ entry (p->name, "0x%x", p->flag);
+ object_close (FALSE);
}
}
-
- return str;
}
const char *
get_ipv6_scope_name (uint32_t scope)
{
switch (scope) {
- case 0x0:
- case 0xf:
- return "reserved";
- break;
+ case 0x0:
+ case 0xf:
+ return "reserved";
+ break;
- case 0x1:
- return "interface-local";
- break;
+ case 0x1:
+ return "interface-local";
+ break;
- case 0x2:
- return "link-local";
- break;
+ case 0x2:
+ return "link-local";
+ break;
- case 0x4:
- return "admin-local";
- break;
+ case 0x4:
+ return "admin-local";
+ break;
- case 0x5:
- return "site-local";
- break;
+ case 0x5:
+ return "site-local";
+ break;
- case 0x8:
- return "organization-local";
- break;
+ case 0x8:
+ return "organization-local";
+ break;
- case 0xe:
- return "global";
- break;
+ case 0xe:
+ return "global";
+ break;
}
return UNKNOWN_STR;
@@ -1792,7 +4387,7 @@ get_mtu (const struct ifaddrs *ifaddr)
{
int sock;
struct ifreq ifr;
- int request = SIOCGIFMTU;
+ unsigned long request = SIOCGIFMTU;
assert (ifaddr);
@@ -1808,8 +4403,8 @@ get_mtu (const struct ifaddrs *ifaddr)
strncpy (ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ-1);
if (ioctl (sock, request, &ifr) < 0)
- goto out;
-out:
+ ifr.ifr_mtu = 0;
+
close (sock);
return ifr.ifr_mtu;
@@ -1826,7 +4421,7 @@ get_mac_address (const struct ifaddrs *ifaddr)
char *mac_address = NULL;
int i;
int valid = FALSE;
-#if defined (PROCENV_BSD) || defined (__FreeBSD_kernel__)
+#if defined (PROCENV_BSD) || defined (PROCENV_GNU_BSD)
struct sockaddr_dl *link_layer;
#else
struct ifreq ifr;
@@ -1834,12 +4429,12 @@ get_mac_address (const struct ifaddrs *ifaddr)
#endif
#if defined (PROCENV_LINUX) || defined (PROCENV_HURD)
- int request = SIOCGIFHWADDR;
+ unsigned long request = SIOCGIFHWADDR;
#endif
assert (ifaddr);
-#if defined (PROCENV_BSD) || defined (__FreeBSD_kernel__)
+#if defined (PROCENV_BSD) || defined (PROCENV_GNU_BSD)
link_layer = (struct sockaddr_dl *)ifaddr->ifa_addr;
#else
@@ -1858,7 +4453,7 @@ get_mac_address (const struct ifaddrs *ifaddr)
goto out;
#endif
-#if defined (PROCENV_BSD) || defined (__FreeBSD_kernel__)
+#if defined (PROCENV_BSD) || defined (PROCENV_GNU_BSD)
data = LLADDR (link_layer);
#else
data = (char *)ifr.ifr_hwaddr.sa_data;
@@ -1895,7 +4490,7 @@ get_mac_address (const struct ifaddrs *ifaddr)
out:
-#if defined (PROCENV_BSD) || defined (__FreeBSD_kernel__)
+#if defined (PROCENV_BSD) || defined (PROCENV_GNU_BSD)
/* NOP */
#else
close (sock);
@@ -1906,7 +4501,7 @@ out:
#if defined (PROCENV_LINUX) || defined (PROCENV_HURD)
void
-show_linux_mounts (ShowMountType what)
+show_mounts_linux (ShowMountType what)
{
FILE *mtab;
struct mntent *mnt;
@@ -1914,25 +4509,30 @@ show_linux_mounts (ShowMountType what)
unsigned int major = 0;
unsigned int minor = 0;
int have_stats;
+#if defined (PROCENV_LINUX)
+ char canonical[PATH_MAX];
+#endif
+
+ common_assert ();
mtab = fopen (MOUNTS, "r");
- if (! mtab) {
- show ("%s", UNKNOWN_STR);
+ if (! mtab)
return;
- }
while ((mnt = getmntent (mtab))) {
- char *str = NULL;
have_stats = TRUE;
if (what == SHOW_ALL || what == SHOW_MOUNTS) {
unsigned multiplier = 0;
- fsblkcnt_t blocks;
- fsblkcnt_t bfree;
- fsblkcnt_t bavail;
- fsblkcnt_t used_blocks;
- fsblkcnt_t used_files;
+ fsblkcnt_t blocks = 0;
+ fsblkcnt_t bfree = 0;
+ fsblkcnt_t bavail = 0;
+ fsblkcnt_t used_blocks = 0;
+ fsblkcnt_t used_files = 0;
+#if defined (PROCENV_LINUX)
+ int ret;
+#endif
if (statvfs (mnt->mnt_dir, &fs) < 0) {
have_stats = FALSE;
@@ -1946,61 +4546,96 @@ show_linux_mounts (ShowMountType what)
used_files = fs.f_files - fs.f_ffree;
}
- get_major_minor (mnt->mnt_dir,
+ (void)get_major_minor (mnt->mnt_dir,
&major,
&minor);
- appendf (&str,
- "fsname='%s', dir='%s', type='%s', "
- "opts='%s', "
- "dev=(major:%u, minor:%u), "
- "dump_freq=%d, fsck_passno=%d, ",
- mnt->mnt_fsname,
- mnt->mnt_dir,
- mnt->mnt_type,
- mnt->mnt_opts,
- major, minor,
- mnt->mnt_freq, mnt->mnt_passno);
+
+ assert (mnt->mnt_dir);
+ section_open (mnt->mnt_dir);
+
+ entry ("filesystem", "'%s'", mnt->mnt_fsname);
+
+#if defined (PROCENV_LINUX)
+ ret = get_canonical (mnt->mnt_fsname, canonical, sizeof (canonical));
+ entry ("canonical", "%s%s%s",
+ ret ? "'" : "",
+ canonical,
+ ret ? "'" : "");
+#endif
+
+ entry ("type", "'%s'", mnt->mnt_type);
+ entry ("options", "'%s'", mnt->mnt_opts);
+
+ show_pathconfs (what, mnt->mnt_dir);
+
+ section_open ("device");
+ entry ("major", "%u", major);
+ entry ("minor", "%u", minor);
+ section_close ();
+
+ entry ("dump frequency", "%d", mnt->mnt_freq);
+ entry ("fsck pass number", "%d", mnt->mnt_passno);
if (have_stats) {
- appendf (&str,
- "fsid=%.*x, "
- "optimal_block_size=%lu, "
- "%d-byte blocks (total=%lu, used=%lu, free=%lu, available=%lu), "
- "files/inodes (total=%lu, used=%lu, free=%lu)",
- sizeof (fs.f_fsid),
- fs.f_fsid,
- fs.f_bsize,
- DF_BLOCK_SIZE,
- blocks,
- used_blocks,
- bfree,
- bavail,
- fs.f_files,
- used_files,
- fs.f_ffree);
+ union fsid_u {
+ unsigned long int fsid;
+ unsigned int val[2];
+ } fsid_val;
+
+ fsid_val.fsid = fs.f_fsid;
+
+ entry ("fsid", "%.*x%.*x",
+ 2 * sizeof (fsid_val.val[0]),
+ fsid_val.val[0],
+ 2 * sizeof (fsid_val.val[1]),
+ fsid_val.val[1]);
+
+ entry ("optimal block size", "%lu", fs.f_bsize);
+
+ section_open ("blocks");
+
+ entry ("size", "%lu bytes", DF_BLOCK_SIZE);
+ entry ("total", "%lu", blocks);
+ entry ("used", "%lu", used_blocks);
+ entry ("free", "%lu", bfree);
+ entry ("available", "%lu", bavail);
+
+ section_close ();
+
+ section_open ("files/inodes");
+
+ entry ("total", "%lu", fs.f_files);
+ entry ("used", "%lu", used_files);
+ entry ("free", "%lu", fs.f_ffree);
+
+ section_close ();
} else {
- appendf (&str,
- "fsid=%s, "
- "optimal_block_size=%s, "
- "%d-byte blocks (total=%s, used=%s, free=%s, available=%s), "
- "files/inodes (total=%s, free=%s)",
- UNKNOWN_STR,
- UNKNOWN_STR,
- UNKNOWN_STR,
- UNKNOWN_STR,
- UNKNOWN_STR,
- UNKNOWN_STR,
- UNKNOWN_STR,
- UNKNOWN_STR,
- UNKNOWN_STR);
- }
+ entry ("fsid", "%s", UNKNOWN_STR);
+ entry ("optimal block size", "%s", UNKNOWN_STR);
- show (str);
- free (str);
- }
+ section_open ("blocks");
- if (what == SHOW_ALL || what == SHOW_PATHCONF)
+ entry ("size", "%lu bytes", DF_BLOCK_SIZE);
+ entry ("total", "%s", UNKNOWN_STR);
+ entry ("used", "%s", UNKNOWN_STR);
+ entry ("free", "%s", UNKNOWN_STR);
+ entry ("available", "%s", UNKNOWN_STR);
+
+ section_close ();
+
+ section_open ("files/inodes");
+
+ entry ("total", "%s", UNKNOWN_STR);
+ entry ("used", "%s", UNKNOWN_STR);
+ entry ("free", "%s", UNKNOWN_STR);
+
+ section_close ();
+ }
+
+ section_close ();
+ } else {
show_pathconfs (what, mnt->mnt_dir);
+ }
}
fclose (mtab);
@@ -2008,13 +4643,11 @@ show_linux_mounts (ShowMountType what)
#endif
#if defined (PROCENV_LINUX)
-char *
+void
decode_extended_if_flags (const char *interface, unsigned short *flags)
{
int sock;
struct ifreq ifr;
- int first = TRUE;
- char *str = NULL;
struct if_extended_flag_map *p;
assert (interface);
@@ -2026,7 +4659,7 @@ decode_extended_if_flags (const char *interface, unsigned short *flags)
sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sock < 0)
- return NULL;
+ return;
memset (&ifr, 0, sizeof (struct ifreq));
strncpy (ifr.ifr_name, interface, IFNAMSIZ-1);
@@ -2038,15 +4671,13 @@ decode_extended_if_flags (const char *interface, unsigned short *flags)
for (p = if_extended_flag_map; p && p->name; p++) {
if (*flags & p->flag) {
- appendf (&str, "%s%s",
- first ? "" : ",",
- p->name);
- first = FALSE;
+ object_open (FALSE);
+ entry (p->name, "0x%x", p->flag);
+ object_close (FALSE);
}
}
out:
close (sock);
- return str;
}
@@ -2114,20 +4745,200 @@ linux_kernel_version (int major, int minor, int revision)
return FALSE;
}
+void
+show_numa_memory (void)
+{
+#if defined (HAVE_NUMA_H)
+ int policy;
+ const char *policy_name;
+ char *allowed_list = NULL;
+ int ret;
+ unsigned long node;
+ unsigned long allowed_size;
+
+#if defined (HAVE_NUMA_H)
+#if LIBNUMA_API_VERSION == 2
+ struct bitmask *allowed;
+#else
+ nodemask_t allowed;
#endif
+#endif
+
+ /* part of the libnuma public API - stop the library calling
+ * exit(3) on error.
+ */
+ numa_exit_on_error = 0;
+
+ /* TRUE if any numa nodes have been displayed yet */
+ int displayed = FALSE;
+
+ /* Number of numa nodes in *current* range */
+ size_t count = 0;
+
+ /* Only valid to read these when count is >0 */
+ size_t last = 0;
+ size_t first = 0;
+#endif /* HAVE_NUMA_H */
+
+ header ("numa");
+
+#if defined (HAVE_NUMA_H)
+ if (numa_available () < 0)
+ /* NUMA not supported on this system */
+ goto out;
+
+#if LIBNUMA_API_VERSION == 2
+ entry ("api version", "%d", 2);
+#else
+ entry ("api version", "%d", 1);
+#endif
+
+ ret = get_mempolicy (&policy, NULL, 0, 0, 0);
+
+ if (ret < 0) {
+ entry ("policy", "%s", UNKNOWN_STR);
+ goto out;
+ }
+
+ policy_name = get_numa_policy (policy);
+
+ entry ("policy", "%s", policy_name ? policy_name : UNKNOWN_STR);
+
+#if LIBNUMA_API_VERSION == 2
+ entry ("maximum nodes", "%d", numa_num_possible_nodes ());
+ entry ("configured nodes", "%d", numa_num_configured_nodes ());
+
+ allowed = numa_get_mems_allowed ();
+ if (! allowed)
+ die ("failed to query NUMA allowed list");
+
+ allowed_size = allowed->size;
+
+#else
+ entry ("maximum nodes", "%s", UNKNOWN_STR);
+ entry ("configured nodes", "%d", numa_max_node ());
+
+ allowed = numa_get_run_node_mask ();
+ allowed_size = NUMA_NUM_NODES;
+#endif
+
+ for (node = 0; node < allowed_size; node++) {
+ if (PROCENV_NUMA_BITMASK_ISSET (allowed, node)) {
+ /* Record first entry in the range */
+ if (! count)
+ first = node;
+
+ last = node;
+ count++;
+ } else {
+ if (count) {
+ if (first == last) {
+ appendf (&allowed_list, "%s%d",
+ displayed ? "," : "",
+ first);
+ } else {
+ appendf (&allowed_list, "%s%d-%d",
+ displayed ? "," : "",
+ first, last);
+ }
+ displayed = TRUE;
+ }
+
+ /* Reset */
+ count = 0;
+ }
+ }
+
+ if (count) {
+ if (first == last) {
+ appendf (&allowed_list, "%s%d",
+ displayed ? "," : "",
+ first);
+ } else {
+ appendf (&allowed_list, "%s%d-%d",
+ displayed ? "," : "",
+ first, last);
+ }
+ }
+
+ entry ("allowed list", "%s", allowed_list);
+
+#if LIBNUMA_API_VERSION == 2
+ numa_free_nodemask (allowed);
+#endif
+
+ free (allowed_list);
+
+out:
+#endif /* HAVE_NUMA_H */
+ footer ();
+}
+
+#if defined (HAVE_NUMA_H)
+const char *
+get_numa_policy (int policy)
+{
+ struct procenv_map *p;
+
+ for (p = numa_mempolicy_map; p && p->name; p++) {
+ if (p->num == policy)
+ return p->name;
+ }
+
+ return NULL;
+}
+#endif /* HAVE_NUMA_H */
+
+const char *
+get_personality_name (unsigned int domain)
+{
+ struct personality_map *m;
+
+ for (m = personality_map; m && m->name; m++) {
+ if (m->personality == (domain & PER_MASK))
+ return m->name;
+ }
+
+ return NULL;
+}
+
+char *
+get_personality_flags (unsigned int flags)
+{
+ struct personality_flag_map *m;
+ char *list = NULL;
+ int first = TRUE;
+
+ for (m = personality_flag_map; m && m->name; m++) {
+ if (flags & m->flag) {
+ appendf (&list, "%s%s",
+ first ? "" : ", ",
+ m->name);
+ first = FALSE;
+ }
+ }
+
+ return list;
+}
+
+#endif /* PROCENV_LINUX */
void
show_mounts (ShowMountType what)
{
- header ("mounts");
+ common_assert ();
+
+ header (what == SHOW_PATHCONF ? "pathconf" : "mounts");
#if defined (PROCENV_LINUX) || defined (PROCENV_HURD)
- show_linux_mounts (what);
+ show_mounts_linux (what);
#endif
-#if defined (PROCENV_BSD) || defined (__FreeBSD_kernel__)
- show_bsd_mounts (what);
+#if defined (PROCENV_BSD) || defined (PROCENV_GNU_BSD)
+ show_mounts_bsd (what);
#endif
+
+ footer ();
}
const char *
@@ -2135,24 +4946,24 @@ get_net_family_name (sa_family_t family)
{
switch (family) {
#if defined (PROCENV_LINUX)
- case AF_PACKET:
- return "AF_PACKET";
- break;
+ case AF_PACKET:
+ return "AF_PACKET";
+ break;
#endif
-#if defined (PROCENV_BSD) || defined (__FreeBSD_kernel__)
- case AF_LINK:
- return "AF_LINK";
- break;
+#if defined (PROCENV_BSD) || defined (PROCENV_GNU_BSD)
+ case AF_LINK:
+ return "AF_LINK";
+ break;
#endif
- case AF_INET:
- return "AF_INET";
- break;
+ case AF_INET:
+ return "AF_INET";
+ break;
- case AF_INET6:
- return "AF_INET6";
- break;
+ case AF_INET6:
+ return "AF_INET6";
+ break;
}
return UNKNOWN_STR;
@@ -2161,70 +4972,85 @@ get_net_family_name (sa_family_t family)
void
show_network_if (const struct ifaddrs *ifa, const char *mac_address)
{
- char *str = NULL;
- char *flags = NULL;
- char *extended_flags = NULL;
unsigned short ext_flags = 0;
sa_family_t family;
char address[NI_MAXHOST];
int mtu = 0;
+ common_assert ();
assert (ifa);
family = ifa->ifa_addr->sa_family;
- flags = decode_if_flags (ifa->ifa_flags);
+ assert (ifa->ifa_name);
+ section_open (ifa->ifa_name);
+
+ entry ("family", "%s (0x%x)", get_net_family_name (family), family);
+
+ /*******************************/
+
+ section_open ("flags");
+
+ entry ("value", "0x%x", ifa->ifa_flags);
+
+ container_open ("fields");
+
+ decode_if_flags (ifa->ifa_flags);
+
+ container_close ();
+
+ section_close ();
+
+ /*******************************/
+
+ section_open ("extended flags");
+
+ entry ("value", "0x%x", ext_flags);
+
+ container_open ("fields");
#if defined (PROCENV_LINUX)
- extended_flags = decode_extended_if_flags (ifa->ifa_name, &ext_flags);
-#endif
- appendf (&str, "interface %s: family=%s (0x%x), "
- "flags=0x%x (%s), extended_flags=0x%x (%s)",
- ifa->ifa_name,
- get_net_family_name (family),
- family,
- ifa->ifa_flags,
- flags ? flags : UNKNOWN_STR,
- ext_flags,
- extended_flags ? extended_flags : NA_STR);
- if (flags)
- free (flags);
-
- if (extended_flags)
- free (extended_flags);
+ decode_extended_if_flags (ifa->ifa_name, &ext_flags);
+#endif
+
+ container_close ();
+
+ section_close ();
+
+ /*******************************/
mtu = get_mtu (ifa);
#if defined (PROCENV_HURD)
/* No AF_LINK/AF_PACKET on Hurd atm */
- appendf (&str, ", mac=%s", UNKNOWN_STR);
+ entry ("mac", "%s", UNKNOWN_STR);
#else
- appendf (&str, ", mac=%s", mac_address ? mac_address : NA_STR);
+ entry ("mac", "%s", mac_address ? mac_address : NA_STR);
#endif
if (mtu > 0) {
- appendf (&str, ", mtu=%d", mtu);
+ entry ("mtu", "%d", mtu);
} else {
- appendf (&str, ", mtu=%s", UNKNOWN_STR);
+ entry ("mtu", "%s", UNKNOWN_STR);
}
get_network_address (ifa->ifa_addr, family, address);
- appendf (&str, ", address=%s", address);
+ entry ("address", "%s", address);
if (ifa->ifa_netmask)
get_network_address (ifa->ifa_netmask, family, address);
- appendf (&str, ", netmask=%s", ifa->ifa_netmask ? address : NA_STR);
+ entry ("netmask", "%s", ifa->ifa_netmask ? address : NA_STR);
#if !defined (PROCENV_HURD)
if (family != PROCENV_LINK_LEVEL_FAMILY) {
if ((ifa->ifa_flags & IFF_BROADCAST) && ifa->ifa_broadaddr) {
get_network_address (ifa->ifa_broadaddr, family, address);
- appendf (&str, ", broadcast=%s", ifa->ifa_broadaddr ? address : NA_STR);
+ entry ("broadcast", "%s", ifa->ifa_broadaddr ? address : NA_STR);
}
} else {
#endif
- appendf (&str, ", broadcast=%s", NA_STR);
+ entry ("broadcast", "%s", NA_STR);
#if !defined (PROCENV_HURD)
}
#endif
@@ -2233,11 +5059,10 @@ show_network_if (const struct ifaddrs *ifa, const char *mac_address)
get_network_address (ifa->ifa_dstaddr, family, address);
- appendf (&str, ", point-to-point=%s", address);
+ entry ("point-to-point", "%s", address);
}
- show (str);
- free (str);
+ section_close ();
}
/*
@@ -2275,6 +5100,18 @@ show_network_if (const struct ifaddrs *ifa, const char *mac_address)
* suggests this _seems_ to be the case, but is not documented as being
* guaranteed.
*/
+#ifdef PROCENV_ANDROID
+
+void
+show_network (void)
+{
+ /* Bionic isn't actually that bionic at all :( */
+ header ("network");
+ footer ();
+}
+
+#else
+
void
show_network (void)
{
@@ -2285,13 +5122,13 @@ show_network (void)
struct network_map *node = NULL;
struct network_map *tmp = NULL;
+ common_assert ();
+
header ("network");
/* Query all network interfaces */
- if (getifaddrs (&if_addrs) < 0) {
- show ("%s", UNKNOWN_STR);
+ if (getifaddrs (&if_addrs) < 0)
return;
- }
/* Construct an initial node for the cache */
head = calloc (1, sizeof (struct network_map));
@@ -2397,12 +5234,15 @@ show_network (void)
free (head);
freeifaddrs (if_addrs);
+
+ footer ();
}
+#endif
-#if defined (PROCENV_BSD) || defined (__FreeBSD_kernel__)
+#if defined (PROCENV_BSD) || defined (PROCENV_GNU_BSD)
char *
-get_bsd_mount_opts (uint64_t flags)
+get_mount_opts_bsd (uint64_t flags)
{
struct mntopt_map *opt;
char *str = NULL;
@@ -2452,7 +5292,7 @@ get_bsd_mount_opts (uint64_t flags)
}
void
-show_bsd_mounts (ShowMountType what)
+show_mounts_bsd (ShowMountType what)
{
int count;
struct statfs *mounts;
@@ -2466,6 +5306,8 @@ show_bsd_mounts (ShowMountType what)
statfs_int_type bavail;
statfs_int_type used;
+ common_assert ();
+
/* Note that returned memory cannot be freed (by us) */
count = getmntinfo (&mounts, MNT_WAIT);
@@ -2473,18 +5315,17 @@ show_bsd_mounts (ShowMountType what)
die ("unable to query mount info");
mnt = mounts;
-
+
for (i = 0; i < count; i++) {
char *opts = NULL;
- opts = get_bsd_mount_opts (mnt->f_flags);
+ opts = get_mount_opts_bsd (mnt->f_flags);
if (! opts)
die ("cannot determine FS flags for mountpoint '%s'",
mnt->f_mntonname);
if (what == SHOW_ALL || what == SHOW_MOUNTS) {
-
- get_major_minor (mnt->f_mntonname,
+ (void)get_major_minor (mnt->f_mntonname,
&major,
&minor);
@@ -2494,34 +5335,49 @@ show_bsd_mounts (ShowMountType what)
bavail = mnt->f_bavail * multiplier;
used = blocks - bfree;
- show ("fsname='%s', dir='%s', type='%s', "
- "opts='%s', "
- "dev=(major:%u, minor:%u), "
- "fsid=%.*x%.*x, "
- "optimal_block_size=%" statfs_int_fmt ", "
- "%d-byte blocks (total=%" statfs_int_fmt ", "
- "used=%" statfs_int_fmt ", free=%" statfs_int_fmt ", available=%" statfs_int_fmt "), "
- "files/inodes (total=%" statfs_int_fmt ", free=%" statfs_int_fmt ")",
- mnt->f_mntfromname,
- mnt->f_mntonname,
- mnt->f_fstypename,
- opts,
- major, minor,
+ assert (mnt->f_mntfromname);
+ section_open (mnt->f_mntfromname);
+
+ entry ("dir", "'%s'", mnt->f_mntonname);
+ entry ("type", "%s", mnt->f_fstypename);
+ entry ("options", "'%s'", opts);
+ section_open ("device");
+ entry ("major", "%u", major);
+ entry ("minor", "%u", minor);
+ section_close ();
+
+ entry ("fsid", "%.*x%.*x",
/* Always zero on BSD? */
- sizeof (mnt->f_fsid.val[0]),
+ 2 * sizeof (mnt->f_fsid.val[0]),
mnt->f_fsid.val[0],
- sizeof (mnt->f_fsid.val[1]),
- mnt->f_fsid.val[1],
-
- mnt->f_bsize,
- DF_BLOCK_SIZE,
- blocks,
- used,
- bfree,
- bavail,
- mnt->f_files,
- mnt->f_ffree);
+ 2 * sizeof (mnt->f_fsid.val[1]),
+ mnt->f_fsid.val[1]);
+
+ entry ("optimal block size", "%" statfs_int_fmt,
+ mnt->f_bsize);
+
+ section_open ("blocks");
+
+ entry ("size", "%lu bytes", DF_BLOCK_SIZE);
+
+ entry ("total", "%" statfs_int_fmt, blocks);
+ entry ("used", "%"statfs_int_fmt, used);
+ entry ("free", "%" statfs_int_fmt, bfree);
+ entry ("available", "%" statfs_int_fmt, bavail);
+
+ section_close ();
+
+ section_open ("files/inodes");
+
+ entry ("total", "%" statfs_int_fmt, mnt->f_files);
+ entry ("used", "%" statfs_int_fmt,
+ mnt->f_files - mnt->f_ffree);
+ entry ("free", "%" statfs_int_fmt, mnt->f_ffree);
+
+ section_close ();
+
+ section_close ();
}
if (what == SHOW_ALL || what == SHOW_PATHCONF)
@@ -2534,6 +5390,144 @@ show_bsd_mounts (ShowMountType what)
#endif
+#if defined (PROCENV_BSD) && defined (HAVE_SYS_CAPABILITY_H)
+void
+show_capabilities_bsd (int fd)
+{
+ int ret;
+ u_int mode;
+ cap_rights_t rights;
+
+ ret = cap_getmode (&mode);
+ if (ret < 0) {
+ /* No Capsicum support */
+ goto out;
+ }
+
+ ret = cap_rights_get (fd, &rights);
+ if (ret < 0) {
+ /* Cannot query capabilities */
+ goto out;
+ }
+
+ show_capsicum_cap (rights, CAP_ACCEPT);
+ show_capsicum_cap (rights, CAP_ACL_CHECK);
+ show_capsicum_cap (rights, CAP_ACL_DELETE);
+ show_capsicum_cap (rights, CAP_ACL_GET);
+ show_capsicum_cap (rights, CAP_ACL_SET);
+ show_capsicum_cap (rights, CAP_BIND);
+#if __FreeBSD__ > 9
+ show_capsicum_cap (rights, CAP_BINDAT);
+ show_capsicum_cap (rights, CAP_CHFLAGSAT);
+#endif
+ show_capsicum_cap (rights, CAP_CONNECT);
+#if __FreeBSD__ > 9
+ show_capsicum_cap (rights, CAP_CONNECTAT);
+#endif
+ show_capsicum_cap (rights, CAP_CREATE);
+#if __FreeBSD__ > 9
+ show_capsicum_cap (rights, CAP_EVENT);
+#endif
+ show_capsicum_cap (rights, CAP_EXTATTR_DELETE);
+ show_capsicum_cap (rights, CAP_EXTATTR_GET);
+ show_capsicum_cap (rights, CAP_EXTATTR_LIST);
+ show_capsicum_cap (rights, CAP_EXTATTR_SET);
+ show_capsicum_cap (rights, CAP_FCHDIR);
+ show_capsicum_cap (rights, CAP_FCHFLAGS);
+ show_capsicum_cap (rights, CAP_FCHMOD);
+#if __FreeBSD__ > 9
+ show_capsicum_cap (rights, CAP_FCHMODAT);
+#endif
+ show_capsicum_cap (rights, CAP_FCHOWN);
+#if __FreeBSD__ > 9
+ show_capsicum_cap (rights, CAP_FCHOWNAT);
+#endif
+ show_capsicum_cap (rights, CAP_FCNTL);
+ show_capsicum_cap (rights, CAP_FEXECVE);
+ show_capsicum_cap (rights, CAP_FLOCK);
+ show_capsicum_cap (rights, CAP_FPATHCONF);
+ show_capsicum_cap (rights, CAP_FSCK);
+ show_capsicum_cap (rights, CAP_FSTAT);
+#if __FreeBSD__ > 9
+ show_capsicum_cap (rights, CAP_FSTATAT);
+#endif
+ show_capsicum_cap (rights, CAP_FSTATFS);
+ show_capsicum_cap (rights, CAP_FSYNC);
+ show_capsicum_cap (rights, CAP_FTRUNCATE);
+ show_capsicum_cap (rights, CAP_FUTIMES);
+#if __FreeBSD__ > 9
+ show_capsicum_cap (rights, CAP_FUTIMESAT);
+#endif
+ show_capsicum_cap (rights, CAP_GETPEERNAME);
+ show_capsicum_cap (rights, CAP_GETSOCKNAME);
+ show_capsicum_cap (rights, CAP_GETSOCKOPT);
+ show_capsicum_cap (rights, CAP_IOCTL);
+#if __FreeBSD__ > 9
+ show_capsicum_cap (rights, CAP_KQUEUE);
+ show_capsicum_cap (rights, CAP_KQUEUE_CHANGE);
+ show_capsicum_cap (rights, CAP_KQUEUE_EVENT);
+ show_capsicum_cap (rights, CAP_LINKAT);
+#endif
+ show_capsicum_cap (rights, CAP_LISTEN);
+ show_capsicum_cap (rights, CAP_LOOKUP);
+ show_capsicum_cap (rights, CAP_MAC_GET);
+ show_capsicum_cap (rights, CAP_MAC_SET);
+#if __FreeBSD__ > 9
+ show_capsicum_cap (rights, CAP_MKDIRAT);
+ show_capsicum_cap (rights, CAP_MKFIFOAT);
+ show_capsicum_cap (rights, CAP_MKNODAT);
+ show_capsicum_cap (rights, CAP_MMAP);
+ show_capsicum_cap (rights, CAP_MMAP_R);
+ show_capsicum_cap (rights, CAP_MMAP_RW);
+ show_capsicum_cap (rights, CAP_MMAP_RWX);
+ show_capsicum_cap (rights, CAP_MMAP_RX);
+ show_capsicum_cap (rights, CAP_MMAP_W);
+ show_capsicum_cap (rights, CAP_MMAP_WX);
+ show_capsicum_cap (rights, CAP_MMAP_X);
+#endif
+ show_capsicum_cap (rights, CAP_PDGETPID);
+ show_capsicum_cap (rights, CAP_PDKILL);
+ show_capsicum_cap (rights, CAP_PDWAIT);
+ show_capsicum_cap (rights, CAP_PEELOFF);
+ show_capsicum_cap (rights, CAP_POLL_EVENT);
+#if __FreeBSD__ > 9
+ show_capsicum_cap (rights, CAP_PREAD);
+ show_capsicum_cap (rights, CAP_PWRITE);
+#endif
+ show_capsicum_cap (rights, CAP_READ);
+#if __FreeBSD__ > 9
+ show_capsicum_cap (rights, CAP_RECV);
+ show_capsicum_cap (rights, CAP_RENAMEAT);
+#endif
+ show_capsicum_cap (rights, CAP_SEEK);
+#if __FreeBSD__ > 9
+ show_capsicum_cap (rights, CAP_SEEK_TELL);
+#endif
+ show_capsicum_cap (rights, CAP_SEM_GETVALUE);
+ show_capsicum_cap (rights, CAP_SEM_POST);
+ show_capsicum_cap (rights, CAP_SEM_WAIT);
+#if __FreeBSD__ > 9
+ show_capsicum_cap (rights, CAP_SEND);
+#endif
+ show_capsicum_cap (rights, CAP_SETSOCKOPT);
+ show_capsicum_cap (rights, CAP_SHUTDOWN);
+#if __FreeBSD__ > 9
+ show_capsicum_cap (rights, CAP_SOCK_CLIENT);
+ show_capsicum_cap (rights, CAP_SOCK_SERVER);
+ show_capsicum_cap (rights, CAP_SYMLINKAT);
+#endif
+ show_capsicum_cap (rights, CAP_TTYHOOK);
+#if __FreeBSD__ > 9
+ show_capsicum_cap (rights, CAP_UNLINKAT);
+#endif
+ show_capsicum_cap (rights, CAP_WRITE);
+
+out:
+ /* clang requires this */
+ return;
+}
+#endif /* (PROCENV_BSD) && defined (HAVE_SYS_CAPABILITY_H) */
+
void
get_priorities (void)
{
@@ -2659,6 +5653,9 @@ in_chroot (void)
error:
die ("cannot stat '%s'", dir);
+
+ /* compiler appeasement */
+ return FALSE;
}
/* detect if setsid(2) has been called */
@@ -2678,19 +5675,25 @@ is_process_group_leader (void)
void
show_proc_branch (void)
{
-#if defined (PROCENV_LINUX)
- show_linux_proc_branch ();
+ common_assert ();
+
+#if defined (PROCENV_LINUX) || defined (PROCENV_GNU_BSD)
+ show_proc_branch_linux ();
+#endif
+
+#if defined (PROCENV_HURD)
+ /* FIXME: how can this be queried in Hurd?? */
#endif
#if defined (PROCENV_BSD)
- show_bsd_proc_branch ();
+ show_proc_branch_bsd ();
#endif
}
#if defined (PROCENV_BSD)
/* Who would have thought handling PIDs was so tricky? */
void
-show_bsd_proc_branch (void)
+show_proc_branch_bsd (void)
{
int count = 0;
int i;
@@ -2700,11 +5703,10 @@ show_bsd_proc_branch (void)
struct kinfo_proc *p;
pid_t self, current;
int done = FALSE;
- char *str;
+ char *str = NULL;
pid_t ultimate_parent = 0;
- str = strdup ("ancestry: ");
- assert (str);
+ common_assert ();
self = current = getpid ();
@@ -2807,19 +5809,23 @@ show_bsd_proc_branch (void)
if (kvm_close (kvm) < 0)
die ("failed to close kvm");
- show (str);
+ entry ("ancestry", "%s", str);
free (str);
}
#endif
#if defined (PROCENV_LINUX)
void
-show_linux_prctl (void)
+show_prctl_linux (void)
{
int rc;
int arg2;
char name[17] = { 0 };
+ common_assert ();
+
+ section_open ("prctl");
+
#ifdef PR_GET_ENDIAN
if (LINUX_KERNEL_MMR (2, 6, 18)) {
const char *value;
@@ -2843,7 +5849,7 @@ show_linux_prctl (void)
break;
}
}
- show ("process endian: %s", value);
+ entry ("process endian", "%s", value);
}
#endif
@@ -2869,7 +5875,7 @@ show_linux_prctl (void)
break;
}
}
- show ("dumpable: %s", value);
+ entry ("dumpable", "%s", value);
}
#endif
@@ -2896,7 +5902,7 @@ show_linux_prctl (void)
break;
}
}
- show ("floating point emulation: %s", value);
+ entry ("floating point emulation", "%s", value);
}
#endif
@@ -2932,7 +5938,7 @@ show_linux_prctl (void)
break;
}
}
- show ("floating point exceptions: %s", value);
+ entry ("floating point exceptions", "%s", value);
}
#endif
@@ -2940,9 +5946,9 @@ show_linux_prctl (void)
if (LINUX_KERNEL_MMR (2, 6, 11)) {
rc = prctl (PR_GET_NAME, name, 0, 0, 0);
if (rc < 0)
- show ("process name: %s", UNKNOWN_STR);
+ entry ("process name", "%s", UNKNOWN_STR);
else
- show ("process name: %s", name);
+ entry ("process name", "%s", name);
}
#endif
@@ -2951,11 +5957,11 @@ show_linux_prctl (void)
if (LINUX_KERNEL_MMR (2, 3, 15)) {
rc = prctl (PR_GET_PDEATHSIG, &arg2, 0, 0, 0);
if (rc < 0)
- show ("parent death signal: %s", UNKNOWN_STR);
+ entry ("parent death signal", "%s", UNKNOWN_STR);
else if (rc == 0)
- show ("parent death signal: disabled");
+ entry ("parent death signal", "disabled");
else
- show ("parent death signal: %d", arg2);
+ entry ("parent death signal", "%d", arg2);
}
#endif
@@ -2982,7 +5988,7 @@ show_linux_prctl (void)
break;
}
}
- show ("secure computing: %s", value);
+ entry ("secure computing", "%s", value);
}
#endif
@@ -3008,7 +6014,7 @@ show_linux_prctl (void)
break;
}
}
- show ("process timing: %s", value);
+ entry ("process timing", "%s", value);
}
#endif
@@ -3032,7 +6038,7 @@ show_linux_prctl (void)
break;
}
}
- show ("timestamp counter read: %s", value);
+ entry ("timestamp counter read", "%s", value);
}
#endif
@@ -3056,7 +6062,7 @@ show_linux_prctl (void)
break;
}
}
- show ("unaligned access: %s", value);
+ entry ("unaligned access", "%s", value);
}
#endif
@@ -3083,7 +6089,7 @@ show_linux_prctl (void)
break;
}
}
- show ("machine-check exception: %s", value);
+ entry ("machine-check exception", "%s", value);
}
#endif
@@ -3107,7 +6113,7 @@ show_linux_prctl (void)
break;
}
}
- show ("no new privileges: %s", value);
+ entry ("no new privileges", "%s", value);
}
#endif
@@ -3115,9 +6121,9 @@ show_linux_prctl (void)
if (LINUX_KERNEL_MMR (2, 6, 28)) {
rc = prctl (PR_GET_TIMERSLACK, 0, 0, 0, 0);
if (rc < 0)
- show ("timer slack: %s", UNKNOWN_STR);
+ entry ("timer slack", "%s", UNKNOWN_STR);
else
- show ("timer slack: %dns", rc);
+ entry ("timer slack", "%dns", rc);
}
#endif
@@ -3125,23 +6131,28 @@ show_linux_prctl (void)
if (LINUX_KERNEL_MM (3, 4)) {
rc = prctl (PR_GET_CHILD_SUBREAPER, &arg2, 0, 0, 0);
if (rc < 0)
- show ("child subreaper: %s", UNKNOWN_STR);
+ entry ("child subreaper", "%s", UNKNOWN_STR);
else
- show ("child subreaper: %s", arg2 ? YES_STR : NO_STR);
+ entry ("child subreaper", "%s", arg2 ? YES_STR : NO_STR);
}
#endif
#ifdef PR_GET_TID_ADDRESS
rc = prctl (PR_GET_TID_ADDRESS, &arg2, 0, 0, 0);
if (rc < 0)
- show ("clear child tid address: %s", UNKNOWN_STR);
+ entry ("clear child tid address", "%s", UNKNOWN_STR);
else
- show ("clear child tid address: %p", arg2);
+ entry ("clear child tid address", "%p", arg2);
#endif
+
+ section_close ();
}
+#endif
+
+#if defined (PROCENV_LINUX) || defined (PROCENV_GNU_BSD)
void
-show_linux_proc_branch (void)
+show_proc_branch_linux (void)
{
char buffer[1024];
char path[PATH_MAX];
@@ -3151,10 +6162,9 @@ show_linux_proc_branch (void)
size_t len;
char *p;
FILE *f;
- char *str;
+ char *str = NULL;
- str = strdup ("ancestry: ");
- assert (str);
+ common_assert ();
sprintf (pid, "%d", (int)getpid ());
@@ -3201,7 +6211,7 @@ show_linux_proc_branch (void)
}
out:
- show (str);
+ entry ("ancestry", "%s", str);
free (str);
}
#endif
@@ -3221,6 +6231,8 @@ show_tty_attrs (void)
int fds[4] = { -1, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO };
size_t i;
+ common_assert ();
+
fds[0] = user.tty_fd;
/* For non-Linux platforms, this will force the lock
@@ -3240,18 +6252,21 @@ show_tty_attrs (void)
}
}
- show ("%s", NA_STR);
+ /* cannot query attributes */
+ footer ();
return;
work:
-
user.tty_fd = fds[i];
#ifdef PROCENV_LINUX
get_tty_locked_status (&lock_status);
#endif
- show ("c_iflag=0x%x", tty.c_iflag);
+ /*****************************************/
+ section_open ("c_iflag (input)");
+
+ entry ("value", "0x%x", tty.c_iflag);
show_const_tty (tty, c_iflag, IGNBRK, lock_status);
show_const_tty (tty, c_iflag, BRKINT, lock_status);
@@ -3273,7 +6288,12 @@ work:
show_const_tty (tty, c_iflag, IUTF8, lock_status);
#endif
- show ("c_oflag=0x%x", tty.c_oflag);
+ section_close ();
+
+ /*****************************************/
+ section_open ("c_oflag (output)");
+
+ entry ("c_oflag", "0x%x", tty.c_oflag);
show_const_tty (tty, c_oflag, OPOST, lock_status);
#if defined (PROCENV_LINUX)
@@ -3296,13 +6316,12 @@ work:
show_const_tty (tty, c_oflag, FFDLY, lock_status);
#endif
- show ("c_cflag=0x%x", tty.c_cflag);
+ section_close ();
- show (" [c_cflag:input baud speed=%s]",
- get_speed (cfgetispeed (&tty)));
+ /*****************************************/
+ section_open ("c_cflag (control)");
- show (" [c_cflag:output baud speed=%s]",
- get_speed (cfgetospeed (&tty)));
+ entry ("value", "0x%x", tty.c_cflag);
#if defined (PROCENV_LINUX)
show_const_tty (tty, c_cflag, CBAUDEX, lock_status);
@@ -3324,7 +6343,12 @@ work:
#endif
show_const_tty (tty, c_cflag, CRTSCTS, lock_status);
- show ("c_lflag=0x%x", tty.c_lflag);
+ section_close ();
+
+ /*****************************************/
+ section_open ("c_lflag (local)");
+
+ entry ("value", "0x%x", tty.c_lflag);
show_const_tty (tty, c_lflag, ISIG, lock_status);
#if defined (PROCENV_LINUX)
@@ -3344,7 +6368,10 @@ work:
show_const_tty (tty, c_lflag, PENDIN, lock_status);
show_const_tty (tty, c_lflag, IEXTEN, lock_status);
- show ("c_cc:");
+ section_close ();
+
+ /*****************************************/
+ section_open ("c_cc (special)");
show_cc_tty (tty, VINTR, lock_status);
show_cc_tty (tty, VQUIT, lock_status);
@@ -3366,13 +6393,35 @@ work:
show_cc_tty (tty, VLNEXT, lock_status);
show_cc_tty (tty, VEOL2, lock_status);
+ section_close ();
+
if (ioctl (user.tty_fd, TIOCGWINSZ, &size) < 0)
die ("failed to determine terminal dimensions");
- show ("winsize:ws_row=%u", size.ws_row);
- show ("winsize:ws_col=%u", size.ws_col);
- show ("winsize:ws_xpixel=%u", size.ws_xpixel);
- show ("winsize:ws_ypixel=%u", size.ws_ypixel);
+ /*****************************************/
+ section_open ("speed");
+
+ entry ("input (baud)", "%s",
+ get_speed (cfgetispeed (&tty)));
+
+ entry ("output (baud)", "%s",
+ get_speed (cfgetospeed (&tty)));
+
+ section_close ();
+
+ /*****************************************/
+ section_open ("winsize");
+
+ entry ("ws_row", "%u", size.ws_row);
+ entry ("ws_col", "%u", size.ws_col);
+ entry ("ws_xpixel", "%u", size.ws_xpixel);
+ entry ("ws_ypixel", "%u", size.ws_ypixel);
+
+ section_close ();
+
+ /*****************************************/
+
+ footer ();
}
void
@@ -3383,13 +6432,15 @@ show_locale (void)
char *v;
char *saved = NULL;
+ common_assert ();
+
header ("locale");
v = getenv ("LANG");
- show ("LANG=\"%s\"", v ? v : "");
+ entry ("LANG", "%s", v ? v : "");
v = getenv ("LANGUAGE");
- show ("LANGUAGE=\"%s\"", v ? v : "");
+ entry ("LANGUAGE", "%s", v ? v : "");
value = setlocale (LC_ALL, "");
if (value) {
@@ -3400,16 +6451,18 @@ show_locale (void)
for (p = locale_map; p && p->name; p++) {
value = setlocale (p->num, NULL);
- show ("%s=\"%s\"", p->name, value ? value : UNKNOWN_STR);
+ entry (p->name, "%s", value ? value : UNKNOWN_STR);
}
v = getenv ("LC_ALL");
- show ("LC_ALL=\"%s\"", v ? v : "");
+ entry ("LC_ALL", "%s", v ? v : "");
if (saved) {
(void)setlocale (LC_ALL, saved);
free (saved);
}
+
+ footer ();
}
const char *
@@ -3460,7 +6513,7 @@ get_os (void)
return "iSeries (OS/400)";
#endif
-#if defined (__FreeBSD_kernel__) && defined (__GNUC__)
+#if defined (PROCENV_GNU_BSD) && defined (__GNUC__)
return "GNU/kFreeBSD";
#endif
@@ -3507,7 +6560,9 @@ get_os (void)
return "z/OS (MVS)";
#endif
+#ifndef __COVERITY__
return UNKNOWN_STR;
+#endif
}
/**
@@ -3521,9 +6576,6 @@ get_arch (void)
{
#ifdef __arm__
-#ifdef __aarch64__
- return "ARM64";
-#endif
#ifdef __ARM_PCS_VFP
return "ARMhf";
#endif
@@ -3533,6 +6585,15 @@ get_arch (void)
return "ARM";
#endif
+ /* not arm apparently! :) */
+#ifdef __aarch64__
+ return "ARM64/AARCH64";
+#endif
+
+#if defined (__OR1K__) || defined (__or1k__)
+ return "OpenRISC";
+#endif
+
#ifdef __hppa__
return "HP/PA RISC";
#endif
@@ -3545,15 +6606,30 @@ get_arch (void)
return "IA64";
#endif
+#ifdef __MIPSEL__
+ return "MIPSEL";
+#endif
+
#ifdef __mips__
return "MIPS";
#endif
+#if defined (__powerpc64__) || defined (__ppc64__)
+
+#if defined (_LITTLE_ENDIAN)
+ return "PPC64LE";
+#endif
+ return "PPC64/PowerPC64";
+#endif
+
#ifdef __powerpc__
+#if defined (__SPE__) && __SIZEOF_POINTER__ == 4
+ return "PPCspe";
+#endif
return "PowerPC";
#endif
-#ifdef __sparc64__
+#if defined (__sparc64__) || defined (__sparc_v9__)
return "Sparc64";
#endif
@@ -3573,6 +6649,10 @@ get_arch (void)
return "x32";
#endif
+#ifdef __sh__
+ return "SuperH";
+#endif
+
#if defined (__s390__) || defined (__zarch__) || defined (__SYSC_ZARCH__) || defined (__THW_370__)
return "SystemZ";
#endif
@@ -3588,8 +6668,37 @@ get_arch (void)
int
libs_callback (struct dl_phdr_info *info, size_t size, void *data)
{
- if (info->dlpi_name && *info->dlpi_name)
- show ("%s", info->dlpi_name);
+ const char *name;
+ const char *path;
+
+ assert (info);
+
+ if (! info->dlpi_name || ! *info->dlpi_name)
+ return 0;
+
+ path = info->dlpi_name;
+ assert (path);
+
+ name = strrchr (path, '/');
+
+ if (name) {
+ /* Jump over slash */
+ name++;
+ } else {
+ /* BSD libraries don't show the path */
+ name = path;
+ }
+
+ object_open (FALSE);
+
+ section_open (name);
+
+ entry ("path", "%s", path);
+ entry ("address", "%p", (void *)info->dlpi_addr);
+
+ section_close ();
+
+ object_close (FALSE);
return 0;
}
@@ -3597,9 +6706,13 @@ libs_callback (struct dl_phdr_info *info, size_t size, void *data)
void
show_libs (void)
{
- header ("libs");
+ common_assert ();
+
+ container_open ("libraries");
dl_iterate_phdr (libs_callback, NULL);
+
+ container_close ();
}
#endif
@@ -3617,7 +6730,7 @@ show_clocks (void)
show_clock_res (CLOCK_MONOTONIC);
-#if defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
+#if defined (__FreeBSD__) || defined (PROCENV_GNU_BSD)
show_clock_res (CLOCK_MONOTONIC_PRECISE);
show_clock_res (CLOCK_MONOTONIC_FAST);
show_clock_res (CLOCK_UPTIME);
@@ -3637,84 +6750,115 @@ show_clocks (void)
show_clock_res (CLOCK_PROCESS_CPUTIME_ID);
show_clock_res (CLOCK_THREAD_CPUTIME_ID);
#endif
+
+ footer ();
}
void
show_timezone (void)
{
#if defined (PROCENV_LINUX)
- tzset ();
-
- header ("timezone");
-
- show ("tzname[0]='%s'", tzname[0]);
- show ("tzname[1]='%s'", tzname[1]);
- show ("timezone=%ld", timezone);
- show ("daylight=%d", daylight);
+ show_timezone_linux ();
+#else
+ show_timezone_stub ();
#endif
}
-#define show_size(thing) \
- show ("sizeof (" #thing "): %lu byte%s", \
- (unsigned long int)sizeof (thing), \
- sizeof (thing) == 1 ? "" : "s")
-
void
show_sizeof (void)
{
header ("sizeof");
- show ("bits/byte (CHAR_BIT): %d", CHAR_BIT);
-
- /* fundamental types and non-aggregate typedefs */
-
- show_size (char);
- show_size (short int);
- show_size (int);
-
- show_size (long int);
-
- show_size (long long int);
-
- show_size (float);
-
- show_size (double);
-
- show_size (long double);
-
- show_size (size_t);
- show_size (ssize_t);
- show_size (ptrdiff_t);
- show_size (void *);
- show_size (wchar_t);
-
- show_size (intmax_t);
- show_size (uintmax_t);
- show_size (imaxdiv_t);
- show_size (intptr_t);
- show_size (uintptr_t);
-
- show_size (time_t);
- show_size (clock_t);
-
- show_size (sig_atomic_t);
- show_size (off_t);
- show_size (fpos_t);
- show_size (mode_t);
-
- show_size (pid_t);
- show_size (uid_t);
- show_size (gid_t);
-
- show_size (rlim_t);
- show_size (fenv_t);
- show_size (fexcept_t);
-
- show_size (wint_t);
- show_size (div_t);
- show_size (ldiv_t);
- show_size (lldiv_t);
- show_size (mbstate_t);
+ entry ("bits/byte (CHAR_BIT)", "%d", CHAR_BIT);
+
+ show_sizeof_type (blkcnt_t);
+ show_sizeof_type (blksize_t);
+ show_sizeof_type (char);
+ show_sizeof_type (clockid_t);
+ show_sizeof_type (clock_t);
+ show_sizeof_type (dev_t);
+ show_sizeof_type (div_t);
+ show_sizeof_type (double);
+ show_sizeof_type (fenv_t);
+ show_sizeof_type (fexcept_t);
+ show_sizeof_type (float);
+ show_sizeof_type (fpos_t);
+ show_sizeof_type (fsblkcnt_t);
+ show_sizeof_type (fsfilcnt_t);
+ show_sizeof_type (gid_t);
+ show_sizeof_type (id_t);
+ show_sizeof_type (imaxdiv_t);
+ show_sizeof_type (ino_t);
+ show_sizeof_type (int);
+ show_sizeof_type (int16_t);
+ show_sizeof_type (int32_t);
+ show_sizeof_type (int64_t);
+ show_sizeof_type (int8_t);
+ show_sizeof_type (int_fast16_t);
+ show_sizeof_type (int_fast32_t);
+ show_sizeof_type (int_fast64_t);
+ show_sizeof_type (int_fast8_t);
+ show_sizeof_type (int_least16_t);
+ show_sizeof_type (int_least32_t);
+ show_sizeof_type (int_least64_t);
+ show_sizeof_type (int_least8_t);
+ show_sizeof_type (intmax_t);
+ show_sizeof_type (intptr_t);
+ show_sizeof_type (key_t);
+ show_sizeof_type (ldiv_t);
+ show_sizeof_type (lldiv_t);
+ show_sizeof_type (long double);
+ show_sizeof_type (long int);
+ show_sizeof_type (long long int);
+ show_sizeof_type (mbstate_t);
+ show_sizeof_type (mode_t);
+ show_sizeof_type (mode_t);
+ show_sizeof_type (nlink_t);
+ show_sizeof_type (off_t);
+ show_sizeof_type (pid_t);
+ show_sizeof_type (pthread_attr_t);
+ show_sizeof_type (pthread_barrierattr_t);
+ show_sizeof_type (pthread_barrier_t);
+ show_sizeof_type (pthread_condattr_t);
+ show_sizeof_type (pthread_cond_t);
+ show_sizeof_type (pthread_key_t);
+ show_sizeof_type (pthread_mutexattr_t);
+ show_sizeof_type (pthread_mutex_t);
+ show_sizeof_type (pthread_once_t);
+ show_sizeof_type (pthread_rwlockattr_t);
+ show_sizeof_type (pthread_rwlock_t);
+ show_sizeof_type (pthread_spinlock_t);
+ show_sizeof_type (pthread_t);
+ show_sizeof_type (ptrdiff_t);
+ show_sizeof_type (rlim_t);
+ show_sizeof_type (short int);
+ show_sizeof_type (sig_atomic_t);
+ show_sizeof_type (size_t);
+ show_sizeof_type (ssize_t);
+ show_sizeof_type (suseconds_t);
+ show_sizeof_type (timer_t);
+ show_sizeof_type (time_t);
+ show_sizeof_type (uid_t);
+ show_sizeof_type (uint16_t);
+ show_sizeof_type (uint32_t);
+ show_sizeof_type (uint64_t);
+ show_sizeof_type (uint8_t);
+ show_sizeof_type (uint_fast16_t);
+ show_sizeof_type (uint_fast32_t);
+ show_sizeof_type (uint_fast64_t);
+ show_sizeof_type (uint_fast8_t);
+ show_sizeof_type (uint_least16_t);
+ show_sizeof_type (uint_least32_t);
+ show_sizeof_type (uint_least64_t);
+ show_sizeof_type (uint_least8_t);
+ show_sizeof_type (uintmax_t);
+ show_sizeof_type (uintptr_t);
+ show_sizeof_type (useconds_t);
+ show_sizeof_type (void *);
+ show_sizeof_type (wchar_t);
+ show_sizeof_type (wint_t);
+
+ footer ();
}
void
@@ -3723,71 +6867,133 @@ show_ranges (void)
header ("ranges");
/******************************/
- show ("char:");
+ section_open ("char");
+
+ show_size (char);
+
+ section_open ("unsigned");
- showi (INDENT, "unsigned: %u to %u (%e to %e, 0x%.*x to 0x%.*x)",
- 0, UCHAR_MAX,
- (double)0, (double)UCHAR_MAX,
+ entry ("decimal", "%u to %u", 0, UCHAR_MAX);
+ entry ("symbolic", "%u to %s", 0, "UCHAR_MAX");
+
+ entry ("scientific", "%e to %e", (double)0, (double)UCHAR_MAX);
+ entry ("hex", "0x%.*x to 0x%.*x",
type_hex_width (char), 0,
type_hex_width (char), UCHAR_MAX);
- showi (INDENT, "signed: %d to %d", CHAR_MIN, CHAR_MAX);
+
+ section_close ();
+
+ section_open ("signed");
+ entry ("decimal", "%d to %d", SCHAR_MIN, SCHAR_MAX);
+ entry ("symbolic", "%s to %s", "SCHAR_MIN", "SCHAR_MAX");
+ section_close ();
+
+ section_close ();
/******************************/
- show ("short int:");
+ section_open ("short int");
- showi (INDENT, "unsigned: %u to %u (%e to %e, 0x%.*x to 0x%.*x)",
- 0, USHRT_MAX,
- (double)0, (double)USHRT_MAX,
+ show_size (short int);
+ section_open ("unsigned");
+ entry ("decimal", "%u to %u", 0, USHRT_MAX);
+ entry ("symbolic", "%u to %s", 0, "USHRT_MAX");
+ entry ("scientific", "%e to %e", (double)0, (double)USHRT_MAX);
+ entry ("hex", "0x%.*x to 0x%.*x",
type_hex_width (short int), 0,
type_hex_width (short int), USHRT_MAX);
+ section_close ();
+
+ section_open ("signed");
+ entry ("decimal", "%d to %d", SHRT_MIN, SHRT_MAX);
+ entry ("symbolic", "%s to %s", "SHRT_MIN", "SHRT_MAX");
+ section_close ();
- showi (INDENT, "signed: %d to %d", SHRT_MIN, SHRT_MAX);
+ section_close ();
/******************************/
- show ("int:");
+ section_open ("int");
- showi (INDENT, "unsigned: %u to %u (%e to %e, 0x%.*x to 0x%.*x)",
- 0, UINT_MAX,
- (double)0, (double)UINT_MAX,
+ show_size (int);
+ section_open ("unsigned");
+ entry ("decimal", "%u to %u", 0, UINT_MAX);
+ entry ("symbolic", "%u to %s", 0, "UINT_MAX");
+ entry ("scientific", "%e to %e", (double)0, (double)UINT_MAX);
+ entry ("hex", "0x%.*x to 0x%.*x",
type_hex_width (int), 0,
type_hex_width (int), UINT_MAX);
- showi (INDENT, "signed: %d to %d", INT_MIN, INT_MAX);
+ section_close ();
+
+ section_open ("signed");
+ entry ("decimal", "%d to %d", INT_MIN, INT_MAX);
+ entry ("symbolic", "%s to %s", "INT_MIN", "INT_MAX");
+ section_close ();
+
+ section_close ();
/******************************/
- show ("long int:");
+ section_open ("long int");
- showi (INDENT, "unsigned: %lu to %lu (%e to %e, 0x%.*lx to 0x%.*lx)",
- 0L, ULONG_MAX,
- (double)0, (double)ULONG_MAX,
+ show_size (long int);
+ section_open ("unsigned");
+ entry ("decimal", "%u to %u", 0, ULONG_MAX);
+ entry ("symbolic", "%u to %s", 0, "ULONG_MAX");
+ entry ("scientific", "%e to %e", (double)0, (double)ULONG_MAX);
+ entry ("hex", "0x%.*x to 0x%.*x",
type_hex_width (long int), 0L,
type_hex_width (long int), ULONG_MAX);
- showi (INDENT, "signed: %ld to %ld", LONG_MIN, LONG_MAX);
+ section_close ();
+
+ section_open ("signed");
+ entry ("decimal", "%ld to %ld", LONG_MIN, LONG_MAX);
+ entry ("symbolic", "%s to %s", "LONG_MIN", "LONG_MAX");
+ section_close ();
+
+ section_close ();
/******************************/
- show ("long long int:");
+ section_open ("long long int");
- showi (INDENT, "unsigned: %llu to %llu (%e to %e, 0x%.*llx to 0x%.*llx)",
- 0LL, ULLONG_MAX,
- (double)0LL, (double)ULLONG_MAX,
+ show_size (long long int);
+ section_open ("unsigned");
+ entry ("decimal", "%llu to %llu", 0, ULLONG_MAX);
+ entry ("symbolic", "%u to %s", 0, "ULLONG_MAX");
+ entry ("scientific", "%e to %e", (double)0, (double)ULLONG_MAX);
+ entry ("hex", "0x%.*llx to 0x%.*llx",
type_hex_width (long long int), 0LL,
type_hex_width (long long int), ULLONG_MAX);
- showi (INDENT, "signed: %lld to %lld", LLONG_MIN, LLONG_MAX);
- /******************************/
- show ("float:");
+ section_close ();
- showi (INDENT, "signed: %e to %e", FLT_MIN, FLT_MAX);
+ section_open ("signed");
+ entry ("decimal", "%lld to %lld", LLONG_MIN, LLONG_MAX);
+ entry ("symbolic", "%s to %s", "LLONG_MIN", "LLONG_MAX");
+ section_close ();
- /******************************/
- show ("double:");
+ section_close ();
- showi (INDENT, "signed: %le to %le", DBL_MIN, DBL_MAX);
+ /******************************/
+ section_open ("float");
+ show_size (float);
+ entry ("signed", "%e to %e", FLT_MIN, FLT_MAX);
+ entry ("symbolic", "%s to %s", "FLT_MIN", "FLT_MAX");
+ section_close ();
/******************************/
- show ("long double:");
+ section_open ("double");
+ show_size (double);
+ entry ("signed", "%le to %le", DBL_MIN, DBL_MAX);
+ entry ("symbolic", "%s to %s", "DBL_MIN", "DBL_MAX");
+ section_close ();
- showi (INDENT, "signed: %Le to %Le", LDBL_MIN, LDBL_MAX);
+ /******************************/
+ section_open ("long double");
+ show_size (long double);
+ entry ("signed", "%Le to %Le", LDBL_MIN, LDBL_MAX);
+ entry ("symbolic", "%s to %s", "LDBL_MIN", "LDBL_MAX");
+ section_close ();
/******************************/
+
+ footer ();
}
void
@@ -3808,123 +7014,227 @@ show_compiler (void)
#endif
header ("compiler");
- show ("name: %s", name ? name : UNKNOWN_STR);
- show ("version: %s", version ? version : UNKNOWN_STR);
- show ("compile date (__DATE__): %s", __DATE__);
- show ("compile time (__TIME__): %s", __TIME__);
- show ("translation unit (__FILE__): %s", __FILE__);
- show ("base file (__BASE_FILE__): %s", __BASE_FILE__);
- show ("timestamp (__TIMESTAMP__): %s", __TIMESTAMP__);
+
+ entry ("name", "%s", name ? name : UNKNOWN_STR);
+ entry ("version", "%s", version ? version : UNKNOWN_STR);
+
+#if defined (PROCENV_REPRODUCIBLE_BUILD)
+ entry ("compile date (__DATE__)", "%s", SUPPRESSED_STR);
+ entry ("compile time (__TIME__)", "%s", SUPPRESSED_STR);
+
+#ifdef __TIMESTAMP__
+ entry ("timestamp (__TIMESTAMP__)", "%s", SUPPRESSED_STR);
+#endif
+
+#else
+ entry ("compile date (__DATE__)", "%s", __DATE__);
+ entry ("compile time (__TIME__)", "%s", __TIME__);
+
+#ifdef __TIMESTAMP__
+ entry ("timestamp (__TIMESTAMP__)", "%s", __TIMESTAMP__);
+#endif
+#endif
+
+ entry ("translation unit (__FILE__)", "%s", __FILE__);
+ entry ("base file (__BASE_FILE__)", "%s", __BASE_FILE__);
+
+ section_open ("feature test macros");
+
+#ifdef __STDC_VERSION__
+ entry ("__STDC_VERSION__", "%lu", __STDC_VERSION__);
+#else
+ entry ("__STDC_VERSION__", "%s", NOT_DEFINED_STR);
+#endif
#ifdef __STRICT_ANSI__
- show ("__STRICT_ANSI__: %s", DEFINED_STR);
+ entry ("__STRICT_ANSI__", "%s", DEFINED_STR);
#else
- show ("__STRICT_ANSI__: %s", NOT_DEFINED_STR);
+ entry ("__STRICT_ANSI__", "%s", NOT_DEFINED_STR);
#endif
#ifdef _POSIX_C_SOURCE
- show ("_POSIX_C_SOURCE: %lu", _POSIX_C_SOURCE);
+ entry ("_POSIX_C_SOURCE", "%lu", _POSIX_C_SOURCE);
#else
- show ("_POSIX_C_SOURCE: %s", NOT_DEFINED_STR);
+ entry ("_POSIX_C_SOURCE", "%s", NOT_DEFINED_STR);
+#endif
+
+#if defined (_POSIX_RAW_SOCKETS)
+ entry ("_POSIX_RAW_SOCKETS", "%s", DEFINED_STR),
+#else
+ entry ("_POSIX_RAW_SOCKETS", "%s", NOT_DEFINED_STR),
#endif
#ifdef _POSIX_SOURCE
- show ("_POSIX_SOURCE: %s", DEFINED_STR);
+ entry ("_POSIX_SOURCE", "%s", DEFINED_STR);
#else
- show ("_POSIX_SOURCE: %s", NOT_DEFINED_STR);
+ entry ("_POSIX_SOURCE", "%s", NOT_DEFINED_STR);
#endif
#ifdef _XOPEN_SOURCE
- show ("_XOPEN_SOURCE: %lu", _XOPEN_SOURCE);
+ entry ("_XOPEN_SOURCE", "%lu", _XOPEN_SOURCE);
#else
- show ("_XOPEN_SOURCE: %s", NOT_DEFINED_STR);
+ entry ("_XOPEN_SOURCE", "%s", NOT_DEFINED_STR);
#endif
#ifdef _XOPEN_SOURCE_EXTENDED
- show ("_XOPEN_SOURCE_EXTENDED: %s", DEFINED_STR);
+ entry ("_XOPEN_SOURCE_EXTENDED", "%s", DEFINED_STR);
#else
- show ("_XOPEN_SOURCE_EXTENDED: %s", NOT_DEFINED_STR);
+ entry ("_XOPEN_SOURCE_EXTENDED", "%s", NOT_DEFINED_STR);
#endif
#ifdef _ISOC95_SOURCE
- show ("_ISOC95_SOURCE: %s", DEFINED_STR);
+ entry ("_ISOC95_SOURCE", "%s", DEFINED_STR);
#else
- show ("_ISOC95_SOURCE: %s", NOT_DEFINED_STR);
+ entry ("_ISOC95_SOURCE", "%s", NOT_DEFINED_STR);
#endif
#ifdef _ISOC99_SOURCE
- show ("_ISOC99_SOURCE: %s", DEFINED_STR);
+ entry ("_ISOC99_SOURCE", "%s", DEFINED_STR);
#else
- show ("_ISOC99_SOURCE: %s", NOT_DEFINED_STR);
+ entry ("_ISOC99_SOURCE", "%s", NOT_DEFINED_STR);
#endif
#ifdef _ISOC11_SOURCE
- show ("_ISOC11_SOURCE: %s", DEFINED_STR);
+ entry ("_ISOC11_SOURCE", "%s", DEFINED_STR);
+#else
+ entry ("_ISOC11_SOURCE", "%s", NOT_DEFINED_STR);
+#endif
+
+#ifdef _LARGEFILE_SOURCE
+ entry ("_LARGEFILE_SOURCE", "%s", DEFINED_STR);
#else
- show ("_ISOC11_SOURCE: %s", NOT_DEFINED_STR);
+ entry ("_LARGEFILE_SOURCE", "%s", NOT_DEFINED_STR);
#endif
#ifdef _LARGEFILE64_SOURCE
- show ("_LARGEFILE64_SOURCE: %s", DEFINED_STR);
+ entry ("_LARGEFILE64_SOURCE", "%s", DEFINED_STR);
#else
- show ("_LARGEFILE64_SOURCE: %s", NOT_DEFINED_STR);
+ entry ("_LARGEFILE64_SOURCE", "%s", NOT_DEFINED_STR);
#endif
#ifdef _FILE_OFFSET_BITS
- show ("_FILE_OFFSET_BITS: %lu", _FILE_OFFSET_BITS);
+ entry ("_FILE_OFFSET_BITS", "%lu", _FILE_OFFSET_BITS);
#else
- show ("_FILE_OFFSET_BITS: %s", NOT_DEFINED_STR);
+ entry ("_FILE_OFFSET_BITS", "%s", NOT_DEFINED_STR);
#endif
#ifdef _BSD_SOURCE
- show ("_BSD_SOURCE: %s", DEFINED_STR);
+ entry ("_BSD_SOURCE", "%s", DEFINED_STR);
#else
- show ("_BSD_SOURCE: %s", NOT_DEFINED_STR);
+ entry ("_BSD_SOURCE", "%s", NOT_DEFINED_STR);
#endif
#ifdef _SVID_SOURCE
- show ("_SVID_SOURCE: %s", DEFINED_STR);
+ entry ("_SVID_SOURCE", "%s", DEFINED_STR);
#else
- show ("_SVID_SOURCE: %s", NOT_DEFINED_STR);
+ entry ("_SVID_SOURCE", "%s", NOT_DEFINED_STR);
#endif
#ifdef _ATFILE_SOURCE
- show ("_ATFILE_SOURCE: %s", DEFINED_STR);
+ entry ("_ATFILE_SOURCE", "%s", DEFINED_STR);
#else
- show ("_ATFILE_SOURCE: %s", NOT_DEFINED_STR);
+ entry ("_ATFILE_SOURCE", "%s", NOT_DEFINED_STR);
#endif
#ifdef _GNU_SOURCE
- show ("_GNU_SOURCE: %s", DEFINED_STR);
+ entry ("_GNU_SOURCE", "%s", DEFINED_STR);
#else
- show ("_GNU_SOURCE: %s", NOT_DEFINED_STR);
+ entry ("_GNU_SOURCE", "%s", NOT_DEFINED_STR);
#endif
#ifdef _REENTRANT
- show ("_REENTRANT: %s", DEFINED_STR);
+ entry ("_REENTRANT", "%s", DEFINED_STR);
#else
- show ("_REENTRANT: %s", NOT_DEFINED_STR);
+ entry ("_REENTRANT", "%s", NOT_DEFINED_STR);
#endif
#ifdef _THREAD_SAFE
- show ("_THREAD_SAFE: %s", DEFINED_STR);
+ entry ("_THREAD_SAFE", "%s", DEFINED_STR);
#else
- show ("_THREAD_SAFE: %s", NOT_DEFINED_STR);
+ entry ("_THREAD_SAFE", "%s", NOT_DEFINED_STR);
#endif
#ifdef _FORTIFY_SOURCE
- show ("_FORTIFY_SOURCE: %s", DEFINED_STR);
+ entry ("_FORTIFY_SOURCE", "%s", DEFINED_STR);
+#else
+ entry ("_FORTIFY_SOURCE", "%s", NOT_DEFINED_STR);
+#endif
+
+#ifdef _DEFAULT_SOURCE
+ entry ("_DEFAULT_SOURCE", "%s", DEFINED_STR);
#else
- show ("_FORTIFY_SOURCE: %s", NOT_DEFINED_STR);
+ entry ("_DEFAULT_SOURCE", "%s", NOT_DEFINED_STR);
#endif
+ section_close ();
+ footer ();
+}
+
+void
+show_libc (void)
+{
+ char *name = NULL;
+ long version = -1;
+ long minor = -1;
+
+#if defined (__GLIBC__)
+ name = "GNU libc (glibc)";
+ version = __GLIBC__;
+#ifdef __GLIBC_MINOR__
+ minor = __GLIBC_MINOR__;
+#endif
+#endif
+
+#if defined (__UCLIBC__)
+ name = "uClibc";
+#ifdef __UCLIBC_MAJOR__
+ version = __UCLIBC_MAJOR__;
+#endif
+#ifdef __UCLIBC_MINOR__
+ minor = __UCLIBC_MINOR__;
+#endif
+#endif
+
+#if defined (__KLIBC__)
+ name = "klibc";
+ version = __KLIBC__;
+#ifdef __KLIBC_MINOR__
+ minor = __KLIBC_MINOR__;
+#endif
+#endif
+
+#if defined (__dietlibc__)
+ name = "dietlibc";
+#endif
+
+#if defined (__BIONIC__)
+ name = "bionic";
+#endif
+
+ header ("libc");
+
+ entry ("name", "%s", name ? name : UNKNOWN_STR);
+
+ if (version >= 0) {
+ entry ("version", "%lu", version);
+ } else {
+ entry ("version", "%s", UNKNOWN_STR);
+ }
+
+ if (minor >= 0) {
+ entry ("minor", "%lu", minor);
+ } else {
+ entry ("minor", "%s", UNKNOWN_STR);
+ }
+
+ footer ();
}
void
show_time (void)
{
- char formatted_time[32];
+ char formatted_time[CTIME_BUFFER];
struct timespec ts;
struct tm *tm;
@@ -3935,25 +7245,28 @@ show_time (void)
if (! tm)
die ("failed to determine localtime");
- header ("time");
- show ("raw: %u.%lu",
- (unsigned int)ts.tv_sec,
- ts.tv_nsec);
-
if (! asctime_r (tm, formatted_time))
die ("failed to determine formatted time");
/* overwrite trailing '\n' */
- formatted_time[ strlen (formatted_time)-1] = '\0';
+ formatted_time[strlen (formatted_time)-1] = '\0';
- show ("local: %s", formatted_time);
+ header ("time");
+
+ entry ("raw", "%u.%lu",
+ (unsigned int)ts.tv_sec,
+ ts.tv_nsec);
+
+ entry ("local", "%s", formatted_time);
- show ("ISO: %4.4d-%2.2d-%2.2dT%2.2d:%2.2d",
+ entry ("ISO", "%4.4d-%2.2d-%2.2dT%2.2d:%2.2d",
1900+tm->tm_year,
tm->tm_mon,
tm->tm_mday,
tm->tm_hour,
tm->tm_min);
+
+ footer ();
}
void
@@ -3964,202 +7277,420 @@ get_uname (void)
}
void
-dump_uname (void)
+show_uname (void)
{
header ("uname");
- show ("sysname: %s", uts.sysname);
- show ("nodename: %s", uts.nodename);
- show ("release: %s", uts.release);
- show ("version: %s", uts.version);
- show ("machine: %s", uts.machine);
+ entry ("sysname", "%s", uts.sysname);
+ entry ("nodename", "%s", uts.nodename);
+ entry ("release", "%s", uts.release);
+ entry ("version", "%s", uts.version);
+ entry ("machine", "%s", uts.machine);
#if defined (_GNU_SOURCE) && defined (PROCENV_LINUX)
- show ("domainname: %s", uts.domainname);
+ entry ("domainname", "%s", uts.domainname[0] ? uts.domainname : UNKNOWN_STR);
#endif
+
+ footer ();
}
+void
+show_cgroups (void)
+{
#if defined (PROCENV_LINUX)
+ show_cgroups_linux ();
+#else
+ show_cgroups_stub ();
+#endif
+}
+
+void
+show_oom (void)
+{
+#if defined (PROCENV_LINUX)
+ show_oom_linux ();
+#else
+ show_oom_stub ();
+#endif
+}
void
show_capabilities (void)
{
- int ret;
+#if defined (PROCENV_LINUX)
+ show_capabilities_linux ();
+#else
+ show_capabilities_stub ();
+#endif
+}
+
+#if defined (PROCENV_LINUX)
+
+#if defined (HAVE_SYS_CAPABILITY_H)
+int
+get_capability_by_flag_type (cap_t cap_p, cap_flag_t type, cap_value_t cap)
+{
+ int ret;
+ cap_flag_value_t result;
+
+ assert (cap_p);
+
+ ret = cap_get_flag (cap_p, cap, type, &result);
+
+ return ret < 0 ? ret : result;
+}
+#endif /* HAVE_SYS_CAPABILITY_H */
+
+void
+show_capabilities_linux (void)
+{
+#if defined (HAVE_SYS_CAPABILITY_H)
+ int last_known;
+ cap_t caps;
+
+ /* Most recently-added capability that procenv knew about at
+ * compile time.
+ */
+ last_known = CAP_LAST_CAP;
+#endif
+
+ header ("capabilities");
+
+#if defined (HAVE_SYS_CAPABILITY_H)
+ caps = cap_get_proc ();
+
+ entry ("count (CAP_LAST_CAP+1)", "%d", CAP_LAST_CAP+1);
+
+ if (! caps)
+ goto out;
+
+ section_open ("known");
+
+ show_capability (caps, CAP_CHOWN);
+ show_capability (caps, CAP_DAC_OVERRIDE);
+ show_capability (caps, CAP_DAC_READ_SEARCH);
+ show_capability (caps, CAP_FOWNER);
+ show_capability (caps, CAP_FSETID);
+ show_capability (caps, CAP_KILL);
+ show_capability (caps, CAP_SETGID);
+ show_capability (caps, CAP_SETUID);
+ show_capability (caps, CAP_SETPCAP);
+ show_capability (caps, CAP_LINUX_IMMUTABLE);
+ show_capability (caps, CAP_NET_BIND_SERVICE);
+ show_capability (caps, CAP_NET_BROADCAST);
+ show_capability (caps, CAP_NET_ADMIN);
+ show_capability (caps, CAP_NET_RAW);
+ show_capability (caps, CAP_IPC_LOCK);
+ show_capability (caps, CAP_IPC_OWNER);
+ show_capability (caps, CAP_SYS_MODULE);
+ show_capability (caps, CAP_SYS_RAWIO);
+ show_capability (caps, CAP_SYS_CHROOT);
+ show_capability (caps, CAP_SYS_PTRACE);
+ show_capability (caps, CAP_SYS_PACCT);
+ show_capability (caps, CAP_SYS_ADMIN);
+ show_capability (caps, CAP_SYS_BOOT);
+ show_capability (caps, CAP_SYS_NICE);
+ show_capability (caps, CAP_SYS_RESOURCE);
+ show_capability (caps, CAP_SYS_TIME);
+ show_capability (caps, CAP_SYS_TTY_CONFIG);
- header ("capabilities(linux)");
-
- show_capability (CAP_CHOWN);
- show_capability (CAP_DAC_OVERRIDE);
- show_capability (CAP_DAC_READ_SEARCH);
- show_capability (CAP_FOWNER);
- show_capability (CAP_FSETID);
- show_capability (CAP_KILL);
- show_capability (CAP_SETGID);
- show_capability (CAP_SETUID);
- show_capability (CAP_SETPCAP);
- show_capability (CAP_LINUX_IMMUTABLE);
- show_capability (CAP_NET_BIND_SERVICE);
- show_capability (CAP_NET_BROADCAST);
- show_capability (CAP_NET_ADMIN);
- show_capability (CAP_NET_RAW);
- show_capability (CAP_IPC_LOCK);
- show_capability (CAP_IPC_OWNER);
- show_capability (CAP_SYS_MODULE);
- show_capability (CAP_SYS_RAWIO);
- show_capability (CAP_SYS_CHROOT);
- show_capability (CAP_SYS_PTRACE);
- show_capability (CAP_SYS_PACCT);
- show_capability (CAP_SYS_ADMIN);
- show_capability (CAP_SYS_BOOT);
- show_capability (CAP_SYS_NICE);
- show_capability (CAP_SYS_RESOURCE);
- show_capability (CAP_SYS_TIME);
- show_capability (CAP_SYS_TTY_CONFIG);
if (LINUX_KERNEL_MM (2, 4)) {
- show_capability (CAP_MKNOD);
- show_capability (CAP_LEASE);
+ show_capability (caps, CAP_MKNOD);
+ show_capability (caps, CAP_LEASE);
}
+
if (LINUX_KERNEL_MMR (2, 6, 11)) {
- show_capability (CAP_AUDIT_WRITE);
- show_capability (CAP_AUDIT_CONTROL);
+ show_capability (caps, CAP_AUDIT_WRITE);
+ show_capability (caps, CAP_AUDIT_CONTROL);
}
if (LINUX_KERNEL_MMR (2, 6, 24))
- show_capability (CAP_SETFCAP);
+ show_capability (caps, CAP_SETFCAP);
if (LINUX_KERNEL_MMR (2, 6, 25)) {
- show_capability (CAP_MAC_OVERRIDE);
- show_capability (CAP_MAC_ADMIN);
+ show_capability (caps, CAP_MAC_OVERRIDE);
+ show_capability (caps, CAP_MAC_ADMIN);
}
#ifdef CAP_SYSLOG
if (LINUX_KERNEL_MMR (2, 6, 37))
- show_capability (CAP_SYSLOG);
+ show_capability (caps, CAP_SYSLOG);
#endif
#ifdef CAP_WAKE_ALARM
if (LINUX_KERNEL_MM (3, 0))
- show_capability (CAP_WAKE_ALARM);
+ show_capability (caps, CAP_WAKE_ALARM);
+#endif
+
+#ifdef CAP_BLOCK_SUSPEND
+ if (LINUX_KERNEL_MM (3, 5))
+ show_capability (caps, CAP_BLOCK_SUSPEND);
+#endif
+
+#ifdef CAP_AUDIT_READ
+ if (LINUX_KERNEL_MM (3, 16)) {
+ show_capability (caps, CAP_AUDIT_READ);
+ }
+#endif
+
+ section_close ();
+
+ /* It's possible that procenv is running on a system which has
+ * more capabilities that the system it was built on (for
+ * example, it might be running in a chroot with a newer kernel
+ * than the chroot environment). So display any unknown
+ * capabilities. We don't have their names, but it's useful to
+ * see that there are additional capabilities in available in
+ * the environment.
+ */
+ section_open ("unknown");
+
+#if defined (PR_CAPBSET_READ)
+ for (int i = 1+last_known; ; i++) {
+ int ret;
+ char *name = NULL;
+
+ ret = cap_get_bound (i);
+ if (ret < 0)
+ break;
+
+ /* Found an "unknown" */
+
+ appendf (&name, "CAP_LAST_CAP+%d", i);
+
+ _show_capability (caps, i, name);
+
+ free (name);
+ }
#endif
+ cap_free (caps);
+
+ section_close ();
+
#ifdef PR_GET_KEEPCAPS
if (LINUX_KERNEL_MMR (2, 2, 18)) {
+ int ret;
ret = prctl (PR_GET_KEEPCAPS, 0, 0, 0, 0);
if (ret < 0)
- show ("keep=%s", UNKNOWN_STR);
+ entry ("keep", "%s", UNKNOWN_STR);
else
- show ("keep=%s", ret ? YES_STR : NO_STR);
+ entry ("keep", "%s", ret ? YES_STR : NO_STR);
}
#endif
+
#if defined (PR_GET_SECUREBITS) && defined (HAVE_LINUX_SECUREBITS_H)
if (LINUX_KERNEL_MMR (2, 6, 26)) {
+ int ret;
+
ret = prctl (PR_GET_SECUREBITS, 0, 0, 0, 0);
if (ret < 0)
- show ("securebits=%s", UNKNOWN_STR);
+ entry ("securebits", "%s", UNKNOWN_STR);
else {
struct securebits_t {
unsigned int securebits;
} flags;
flags.securebits = (unsigned int)ret;
- show ("securebits=0x%x", flags.securebits);
+
+ section_open ("securebits");
+
+ entry ("value", "0x%x", flags.securebits);
+
+ container_open ("fields");
show_const (flags, securebits, SECBIT_KEEP_CAPS);
show_const (flags, securebits, SECBIT_NO_SETUID_FIXUP);
show_const (flags, securebits, SECBIT_NOROOT);
+
+ container_close ();
+
+ section_close ();
}
}
#endif
+
+out:
+#endif /* HAVE_SYS_CAPABILITY_H */
+ footer ();
}
+#if defined (HAVE_SYS_CAPABILITY_H)
+#ifdef PROCENV_NEED_LOCAL_CAP_GET_BOUND
+
+int cap_get_bound (cap_value_t cap)
+{
+#if defined (PR_CAPBSET_READ)
+ return prctl (PR_CAPBSET_READ, cap);
+#else
+ return -1;
+#endif
+}
+
+#endif /* PROCENV_NEED_LOCAL_CAP_GET_BOUND */
+#endif /* HAVE_SYS_CAPABILITY_H */
+
+void
+show_timezone_linux (void)
+{
+ tzset ();
+
+ header ("timezone");
+
+ entry ("tzname[0]", "'%s'", tzname[0]);
+ entry ("tzname[1]", "'%s'", tzname[1]);
+ entry ("timezone", "%ld", timezone);
+ entry ("daylight", "%d", daylight);
+
+ footer ();
+}
+
void
-show_linux_security_module (void)
+show_security_module_linux (void)
{
char *lsm = UNKNOWN_STR;
+
#if defined (HAVE_APPARMOR)
if (aa_is_enabled ())
lsm = "AppArmor";
#endif
-#if defined (HAVE_SELINUX)
- if (is_selinux_enabled ())
- lsm = "SELinux";
+
+#if defined (HAVE_SELINUX_SELINUX_H)
+ if (is_selinux_enabled () == 1) {
+
+ if (is_selinux_mls_enabled () == 1)
+ lsm = "SELinux (MLS)";
+ else
+ lsm = "SELinux";
+ }
#endif
- show ("Linux Security Module: %s", lsm);
+
+ entry ("name", "%s", lsm);
}
void
-show_linux_security_module_context (void)
+show_security_module_context_linux (void)
{
char *context = NULL;
char *mode = NULL;
#if defined (HAVE_APPARMOR)
- if (aa_is_enabled ())
+ if (aa_is_enabled ()) {
+ /* XXX: The mode string is *NOT* be freed since it forms
+ * part of the allocation returned in context.
+ *
+ * See aa_gettaskcon(2) for details.
+ */
if (aa_gettaskcon (user.pid, &context, &mode) < 0)
die ("failed to query AppArmor context");
+ }
#endif
-#if defined (HAVE_SELINUX)
- if (is_selinux_enabled ())
+
+#if defined (HAVE_SELINUX_SELINUX_H)
+ if (is_selinux_enabled ()) {
if (getpidcon (user.pid, &context) < 0)
die ("failed to query SELinux context");
+ }
#endif
if (context) {
- if (mode)
- show ("LSM context: %s (%s)", context, mode);
- else
- show ("LSM context: %s", context);
- } else
- show ("LSM context: %s", UNKNOWN_STR);
+ if (mode) {
+ entry ("context", "%s (%s)", context, mode);
+ } else {
+ entry ("context", "%s", context);
+ }
+ } else {
+ entry ("context", "%s", UNKNOWN_STR);
+ }
- free (context);
- free (mode);
+ free (context);
}
void
-show_linux_cgroups (void)
+show_cgroups_linux (void)
{
- char *file = "/proc/self/cgroup";
- FILE *f;
- char buffer[1024];
- size_t len;
+ const char *delim = ":";
+ char *file = "/proc/self/cgroup";
+ FILE *f;
+ char buffer[1024];
+ size_t len;
- header ("cgroup(linux)");
+ header ("cgroups");
f = fopen (file, "r");
- if (! f) {
- show ("%s", UNKNOWN_STR);
- return;
- }
+
+ if (! f)
+ goto out;
while (fgets (buffer, sizeof (buffer), f)) {
+ char *buf, *b;
+ char *hierarchy;
+ char *subsystems;
+ char *path;
+
len = strlen (buffer);
+ /* Remove NL */
buffer[len-1] = '\0';
- show ("%s", buffer);
+
+ buf = b = strdup (buffer);
+ if (! buf)
+ die ("failed to alloate storage");
+
+ hierarchy = strsep (&b, delim);
+ if (! hierarchy)
+ goto next;
+
+ subsystems = strsep (&b, delim);
+ if (! subsystems)
+ goto next;
+
+ path = strsep (&b, delim);
+ if (! path)
+ goto next;
+
+ /* FIXME: should sort by hierarchy */
+ container_open (hierarchy);
+
+ object_open (FALSE);
+
+ /* FIXME: should split this on comma */
+ entry ("subsystems", "%s", subsystems);
+
+ entry ("path", "%s", path);
+
+ object_close (FALSE);
+
+ container_close ();
+
+next:
+ free (buf);
}
fclose (f);
+
+out:
+
+ footer ();
}
void
-dump_linux_proc_fds (void)
+show_fds_linux (void)
{
- DIR *dir;
- struct dirent *ent;
- struct stat st;
- char *prefix_path = "/proc/self/fd";
- char path[MAXPATHLEN];
- char link[MAXPATHLEN];
- ssize_t len;
+ DIR *dir;
+ struct dirent *ent;
+ char *prefix_path = "/proc/self/fd";
+ struct stat st;
+ char path[MAXPATHLEN];
+ char link[MAXPATHLEN];
+ ssize_t len;
- header ("fds (linux/proc)");
+ container_open ("file descriptors");
dir = opendir (prefix_path);
- if (! dir) {
- show ("%s", UNKNOWN_STR);
+ if (! dir)
return;
- }
while ((ent=readdir (dir)) != NULL) {
- int fd;
+ int fd;
+ char *num = NULL;
if (! strcmp (ent->d_name, ".") || ! strcmp (ent->d_name, ".."))
continue;
@@ -4172,31 +7703,126 @@ dump_linux_proc_fds (void)
/* ignore errors */
continue;
+ appendf (&num, "%d", fd);
+
assert (len);
link[len] = '\0';
if (link[0] == '/') {
- if (stat (link, &st) < 0)
+ if (stat (link, &st) < 0) {
+ free (num);
continue;
+ }
/* Ignore the last (invalid) entry */
- if (S_ISDIR (st.st_mode))
+ if (S_ISDIR (st.st_mode)) {
+ free (num);
continue;
-
+ }
}
- show ("'%s' -> '%s' (terminal=%s, valid=%s)",
- path, link,
- isatty (fd) ? YES_STR : NO_STR,
- fd_valid (fd) ? YES_STR : NO_STR);
+ object_open (FALSE);
+
+ section_open (num);
+ free (num);
+
+ entry ("terminal", "%s", isatty (fd) ? YES_STR : NO_STR);
+ entry ("valid", "%s", fd_valid (fd) ? YES_STR : NO_STR);
+ entry ("device", "%s", link);
+
+ section_close ();
+
+ object_close (FALSE);
}
closedir (dir);
+
+ container_close ();
}
void
-show_oom (void)
+show_namespaces_linux (void)
+{
+ DIR *dir;
+ struct dirent *ent;
+ char *prefix_path = "/proc/self/ns";
+ char path[MAXPATHLEN];
+ char link[MAXPATHLEN];
+ ssize_t len;
+ PRList *list = NULL;
+
+ container_open ("namespaces");
+
+ dir = opendir (prefix_path);
+ if (! dir)
+ goto end;
+
+ list = pr_list_new (NULL);
+ assert (list);
+
+ while ((ent=readdir (dir)) != NULL) {
+ PRList *entry;
+
+ if (! strcmp (ent->d_name, ".") || ! strcmp (ent->d_name, ".."))
+ continue;
+
+ sprintf (path, "%s/%s", prefix_path, ent->d_name);
+
+ len = readlink (path, link, sizeof (link)-1);
+ if (len < 0)
+ /* ignore errors */
+ continue;
+
+ assert (len);
+ link[len] = '\0';
+
+ entry = pr_list_new (strdup (link));
+ assert (entry);
+
+ assert (pr_list_prepend_str_sorted (list, entry));
+ }
+
+ closedir (dir);
+
+ PR_LIST_FOREACH_SAFE (list, iter) {
+ char *tmp;
+ char *name;
+ char *value;
+
+ pr_list_remove (iter);
+
+ tmp = iter->data;
+
+ name = strsep (&tmp, ":");
+ if (! name)
+ goto give_up;
+
+ value = strsep (&tmp, "]");
+ if (! value)
+ goto give_up;
+
+ if (*value == '[' && value+1 && *(value+1)) {
+ value++;
+ }
+
+ object_open (FALSE);
+ entry (name, "%s", value);
+ object_close (FALSE);
+
+give_up:
+ free ((char *)iter->data);
+ free(iter);
+ }
+
+ free_if_set (list);
+
+end:
+ container_close ();
+}
+
+void
+show_oom_linux (void)
{
char *dir = "/proc/self";
char *files[] = { "oom_score", "oom_adj", "oom_score_adj", NULL };
@@ -4208,7 +7834,7 @@ show_oom (void)
int ret;
int seen = FALSE;
- header ("oom(linux)");
+ header ("oom");
for (file = files; file && *file; file++) {
ret = sprintf (path, "%s/%s", dir, *file);
@@ -4224,14 +7850,16 @@ show_oom (void)
while (fgets (buffer, sizeof (buffer), f)) {
len = strlen (buffer);
buffer[len-1] = '\0';
- show ("%s=%s", *file, buffer);
+ entry (*file, "%s", buffer);
}
fclose (f);
}
if (! seen)
- show ("%s", UNKNOWN_STR);
+ entry ("%s", UNKNOWN_STR);
+
+ footer ();
}
char *
@@ -4248,20 +7876,9 @@ get_scheduler_name (int sched)
}
void
-show_linux_scheduler (void)
+show_cpu_linux (void)
{
- int sched;
-
- sched = sched_getscheduler (0);
- show ("scheduler: %s",
- sched < 0 ? UNKNOWN_STR :
- get_scheduler_name (sched));
-}
-
-void
-show_linux_cpu (void)
-{
- int cpu;
+ int cpu = -1;
long max;
max = get_sysconf (_SC_NPROCESSORS_ONLN);
@@ -4271,36 +7888,102 @@ show_linux_cpu (void)
if (cpu < 0)
goto unknown_sched_cpu;
+#else
+ cpu = procenv_getcpu ();
+ if (cpu < 0)
+ goto unknown_sched_cpu;
+#endif
+
/* adjust to make 1-based */
cpu++;
- show ("cpu: %u of %lu", cpu, max);
+ entry ("number", "%u of %ld", cpu, max);
return;
unknown_sched_cpu:
-#endif
- show ("cpu: %s of %lu", UNKNOWN_STR, max);
+
+ entry ("number", "%s of %ld", UNKNOWN_STR, max);
+}
+
+#if ! defined (HAVE_SCHED_GETCPU)
+
+/* Crutch function for RHEL 5 */
+int
+procenv_getcpu (void)
+{
+ int cpu = -1;
+ FILE *f;
+ char **fields;
+ const char *field;
+ char buffer[1024];
+ size_t len;
+ size_t count;
+
+ f = fopen ("/proc/self/stat", "r");
+ if (! f)
+ goto out;
+
+ if (! fgets (buffer, sizeof (buffer), f))
+ goto out;
+
+ fclose (f);
+
+ len = strlen (buffer);
+ buffer[len-1] = '\0';
+
+ count = split_fields (buffer, ' ', TRUE, &fields);
+
+ if (! count)
+ return -1;
+
+ if (count != 42)
+ goto cleanup;
+
+ field = fields[41];
+ assert (field);
+
+ cpu = atoi (field);
+
+cleanup:
+
+ for (len = 0; len < count; len++)
+ free (fields[len]);
+ free (fields);
+
+out:
+ return cpu;
}
+#endif
/**
- * get_root:
+ * get_canonical:
+ *
+ * @path: path to convert to canonical form,
+ * @canonical [out]: canonical version of @path,
+ * @len: Size of @canonical (should be atleast PATH_MAX).
*
- * @root [out]: path of root directory,
- * @len: Size of @root (should be atleast PATH_MAX).
+ * FIXME: this should fully resolve not just sym links but replace all
+ * occurences of '../' by the appropriate direcotry!
**/
-void
-get_root (char *root, size_t len)
+int
+get_canonical (const char *path, char *canonical, size_t len)
{
- char self[] = "/proc/self/root";
ssize_t bytes;
+ int ret = TRUE;
- assert (root);
+ assert (path);
+ assert (canonical);
+ assert (len);
- bytes = readlink (self, root, len);
- if (bytes < 0)
- sprintf (root, UNKNOWN_STR);
- else
- root[bytes] = '\0';
+ bytes = readlink (path, canonical, len);
+ if (bytes < 0) {
+ sprintf (canonical, UNKNOWN_STR);
+ ret = FALSE;
+ } else {
+ canonical[bytes <= len ? bytes : len] = '\0';
+ }
+
+ return ret;
}
void
@@ -4309,8 +7992,66 @@ get_tty_locked_status (struct termios *lock_status)
assert (lock_status);
assert (user.tty_fd != -1);
- if (ioctl (user.tty_fd, TIOCGLCKTRMIOS, lock_status) < 0)
- die ("failed to query terminal lock status");
+ if (ioctl (user.tty_fd, TIOCGLCKTRMIOS, lock_status) < 0) {
+ /* Set to unlocked */
+ memset (lock_status, '\0', sizeof (struct termios));
+ }
+}
+#else
+
+void
+show_namespaces_stub (void)
+{
+ header ("namespaces");
+ footer ();
+}
+void
+show_cgroups_stub (void)
+{
+ header ("cgroups");
+ footer ();
+}
+
+void
+show_oom_stub (void)
+{
+ header ("oom");
+ footer ();
+}
+
+void
+show_timezone_stub (void)
+{
+ header ("timezone");
+ footer ();
+}
+
+void
+show_capabilities_stub (void)
+{
+ header ("capabilities");
+ footer ();
+}
+
+void
+show_shared_mem_stub (void)
+{
+ header ("shared memory");
+ footer ();
+}
+
+void
+show_semaphores_stub (void)
+{
+ header ("semaphores");
+ footer ();
+}
+
+void
+show_msg_queues_stub (void)
+{
+ header ("message queues");
+ footer ();
}
#endif /* PROCENV_LINUX */
@@ -4329,9 +8070,9 @@ has_ctty (void)
return TRUE;
}
-#if defined (PROCENV_BSD) || defined (__FreeBSD_kernel__)
+#if defined (PROCENV_BSD) || defined (PROCENV_GNU_BSD)
void
-show_bsd_cpu (void)
+show_cpu_bsd (void)
{
long max;
kvm_t *kvm;
@@ -4358,11 +8099,11 @@ show_bsd_cpu (void)
if (kvm_close (kvm) < 0)
die ("failed to close kvm");
- show ("cpu: %u of %lu", cpu, max);
+ entry ("number", "%u of %lu", cpu, max);
}
void
-get_bsd_misc (void)
+get_misc_bsd (void)
{
char errors[_POSIX2_LINE_MAX];
kvm_t *kvm;
@@ -4399,6 +8140,43 @@ get_output_value (const char *name)
}
}
die ("invalid output value: '%s'", name);
+
+ /* compiler appeasement */
+ return -1;
+}
+
+int
+get_output_format (const char *name)
+{
+ struct procenv_map *p;
+
+ assert (name);
+
+ for (p = output_format_map; p && p->name; p++) {
+ if (! strcmp (name, p->name)) {
+ return p->num;
+ }
+ }
+ die ("invalid output format value: '%s'", name);
+
+ /* compiler appeasement */
+ return -1;
+}
+
+const char *
+get_output_format_name (void)
+{
+ struct procenv_map *p;
+
+ for (p = output_format_map; p && p->name; p++) {
+ if (output_format == p->num)
+ return p->name;
+ }
+
+ bug ("invalid output format: %d", output_format);
+
+ /* compiler appeasement */
+ return NULL;
}
void
@@ -4420,6 +8198,39 @@ check_envvars (void)
output_file = e;
output = OUTPUT_FILE;
}
+
+ e = getenv (PROCENV_FORMAT_ENV);
+ if (e && *e) {
+ output_format = get_output_format (e);
+ }
+
+ e = getenv (PROCENV_INDENT_ENV);
+ if (e && *e) {
+ indent_amount = atoi (e);
+ }
+
+ e = getenv (PROCENV_INDENT_CHAR_ENV);
+ if (e && *e) {
+ /* Special character handling */
+ if (! strcmp (e, "\\t"))
+ indent_char = "\t";
+ else
+ indent_char = e;
+ }
+
+ e = getenv (PROCENV_SEPARATOR_ENV);
+ if (e && *e) {
+ text_separator = e;
+ }
+
+ e = getenv (PROCENV_CRUMB_SEPARATOR_ENV);
+ if (e && *e) {
+ if (! strcmp (e, "\\t"))
+ crumb_separator = "\t";
+ else
+ crumb_separator = e;
+ }
+
e = getenv (PROCENV_EXEC_ENV);
if (e && *e) {
char *tmp;
@@ -4461,7 +8272,7 @@ check_envvars (void)
}
}
-void
+int
get_major_minor (const char *path, unsigned int *_major, unsigned int *_minor)
{
struct stat st;
@@ -4474,13 +8285,14 @@ get_major_minor (const char *path, unsigned int *_major, unsigned int *_minor)
/* Don't fail as this query may be for a mount which the
* user does not have permission to check.
*/
- warn ("unable to stat path '%s'", path);
*_major = *_minor = 0;
- return;
+ return FALSE;
}
*_major = major (st.st_dev);
*_minor = minor (st.st_dev);
+
+ return TRUE;
}
/**
@@ -4580,7 +8392,7 @@ show_threads (void)
(void) pthread_attr_init (&attr);
(void) pthread_attr_getstacksize (&attr, &stack_size);
- show ("thread stack size: %lu bytes",
+ entry ("stack size", "%lu bytes",
(unsigned long int)stack_size);
#if defined (PROCENV_ANDROID)
@@ -4589,43 +8401,52 @@ show_threads (void)
#else
ret = pthread_attr_getscope (&attr, &scope);
#endif
- show ("thread scope: %s",
+ entry ("scope", "%s",
ret != 0 ? UNKNOWN_STR :
scope == PTHREAD_SCOPE_SYSTEM ? "PTHREAD_SCOPE_SYSTEM"
: "PTHREAD_SCOPE_PROCESS");
ret = pthread_attr_getguardsize (&attr, &guard_size);
if (ret == 0) {
- show ("thread guard size: %lu bytes",
+ entry ("guard size", "%lu bytes",
(unsigned long int)guard_size);
} else {
- show ("thread guard size: %s", UNKNOWN_STR);
+ entry ("guard size", "%s", UNKNOWN_STR);
}
ret = pthread_getschedparam (pthread_self (), &sched, &param);
- show ("thread scheduler: %s",
+
+ section_open ("scheduler");
+
+ entry ("type", "%s",
ret != 0
? UNKNOWN_STR
: get_thread_scheduler_name (sched));
if (ret != 0)
- show ("thread scheduler priority: %s", UNKNOWN_STR);
+ entry ("priority", "%s", UNKNOWN_STR);
else
- show ("thread scheduler priority: %d", param.sched_priority);
+ entry ("priority", "%d", param.sched_priority);
-#ifndef PROCENV_ANDROID
+#ifdef PROCENV_ANDROID
+ section_close ();
+#else
ret = pthread_attr_getinheritsched (&attr, &inherit_sched);
- show ("thread inherit scheduler: %s",
+ entry ("inherit-scheduler attribute", "%s",
ret != 0 ? UNKNOWN_STR :
inherit_sched == PTHREAD_INHERIT_SCHED
? "PTHREAD_INHERIT_SCHED"
: "PTHREAD_EXPLICIT_SCHED");
- show ("thread concurrency: %d", pthread_getconcurrency ());
+ section_close ();
+
+ entry ("concurrency", "%d", pthread_getconcurrency ());
#endif
+
+ footer ();
}
-char *
+const char *
get_thread_scheduler_name (int sched)
{
struct procenv_map *p;
@@ -4645,7 +8466,7 @@ void
show_data_model (void)
{
int ilp[3];
- char data_model[8];
+ char data_model[16];
size_t pointer_size;
ilp[0] = sizeof (int);
@@ -4670,7 +8491,7 @@ show_data_model (void)
if (pointer_size > 8)
die ("%d-byte pointers not supported", (int)pointer_size);
- show ("data model: %s (%d/%d/%d)",
+ entry ("data model", "%s (%d/%d/%d)",
data_model,
ilp[0], ilp[1], ilp[2]);
}
@@ -4678,61 +8499,69 @@ show_data_model (void)
int
main (int argc,
- char *argv[])
+ char *argv[])
{
- int option;
- int long_index;
- int done = FALSE;
+ int option;
+ int long_index;
+ int done = FALSE;
struct option long_options[] = {
- {"meta" , no_argument, NULL, 'a'},
- {"arguments" , no_argument, NULL, 'A'},
- {"libs" , no_argument, NULL, 'b'},
- {"cgroup" , no_argument, NULL, 'c'},
- {"cgroups" , no_argument, NULL, 'c'},
- {"compiler" , no_argument, NULL, 'd'},
- {"env" , no_argument, NULL, 'e'},
- {"environment" , no_argument, NULL, 'e'},
- {"fds" , no_argument, NULL, 'f'},
- {"sizeof" , no_argument, NULL, 'g'},
- {"help" , no_argument, NULL, 'h'},
- {"misc" , no_argument, NULL, 'i'},
- {"uname" , no_argument, NULL, 'j'},
- {"clock" , no_argument, NULL, 'k'},
- {"clocks" , no_argument, NULL, 'k'},
- {"limits" , no_argument, NULL, 'l'},
- {"locale" , no_argument, NULL, 'L'},
- {"mount" , no_argument, NULL, 'm'},
- {"mounts" , no_argument, NULL, 'm'},
- {"confstr" , no_argument, NULL, 'n'},
- {"network" , no_argument, NULL, 'N'},
- {"oom" , no_argument, NULL, 'o'},
- {"proc" , no_argument, NULL, 'p'},
- {"process" , no_argument, NULL, 'p'},
- {"platform" , no_argument, NULL, 'P'},
- {"time" , no_argument, NULL, 'q'},
- {"range" , no_argument, NULL, 'r'},
- {"ranges" , no_argument, NULL, 'r'},
- {"signal" , no_argument, NULL, 's'},
- {"signals" , no_argument, NULL, 's'},
- {"tty" , no_argument, NULL, 't'},
- {"threads" , no_argument, NULL, 'T'},
- {"stat" , no_argument, NULL, 'u'},
- {"rusage" , no_argument, NULL, 'U'},
- {"version" , no_argument, NULL, 'v'},
- {"capabilities" , no_argument, NULL, 'w'},
- {"pathconf" , no_argument, NULL, 'x'},
- {"sysconf" , no_argument, NULL, 'y'},
- {"timezone" , no_argument, NULL, 'z'},
-
- {"output" , required_argument, NULL, 0},
- {"file" , required_argument, NULL, 0},
- {"exec" , no_argument , NULL, 0},
+ {"meta" , no_argument, NULL, 'a'},
+ {"arguments" , no_argument, NULL, 'A'},
+ {"libs" , no_argument, NULL, 'b'},
+ {"libc" , no_argument, NULL, 'B'},
+ {"cgroups" , no_argument, NULL, 'c'},
+ {"cpu" , no_argument, NULL, 'C'},
+ {"compiler" , no_argument, NULL, 'd'},
+ {"crumb-separator" , required_argument, NULL, 0},
+ {"environment" , no_argument, NULL, 'e'},
+ {"semaphores" , no_argument, NULL, 'E'},
+ {"fds" , no_argument, NULL, 'f'},
+ {"namespaces" , no_argument, NULL, 'F'},
+ {"sizeof" , no_argument, NULL, 'g'},
+ {"help" , no_argument, NULL, 'h'},
+ {"misc" , no_argument, NULL, 'i'},
+ {"uname" , no_argument, NULL, 'j'},
+ {"clocks" , no_argument, NULL, 'k'},
+ {"limits" , no_argument, NULL, 'l'},
+ {"locale" , no_argument, NULL, 'L'},
+ {"mounts" , no_argument, NULL, 'm'},
+ {"message-queues" , no_argument, NULL, 'M'},
+ {"confstr" , no_argument, NULL, 'n'},
+ {"network" , no_argument, NULL, 'N'},
+ {"oom" , no_argument, NULL, 'o'},
+ {"process" , no_argument, NULL, 'p'},
+ {"platform" , no_argument, NULL, 'P'},
+ {"time" , no_argument, NULL, 'q'},
+ {"ranges" , no_argument, NULL, 'r'},
+ {"signals" , no_argument, NULL, 's'},
+ {"shared-memory" , no_argument, NULL, 'S'},
+ {"tty" , no_argument, NULL, 't'},
+ {"threads" , no_argument, NULL, 'T'},
+ {"stat" , no_argument, NULL, 'u'},
+ {"rusage" , no_argument, NULL, 'U'},
+ {"version" , no_argument, NULL, 'v'},
+ {"capabilities" , no_argument, NULL, 'w'},
+ {"pathconf" , no_argument, NULL, 'x'},
+ {"sysconf" , no_argument, NULL, 'y'},
+ {"memory" , no_argument, NULL, 'Y'},
+ {"timezone" , no_argument, NULL, 'z'},
+ {"exec" , no_argument , NULL, 0},
+ {"file" , required_argument, NULL, 0},
+ {"format" , required_argument, NULL, 0},
+ {"indent" , required_argument, NULL, 0},
+ {"indent-char" , required_argument, NULL, 0},
+ {"output" , required_argument, NULL, 0},
+ {"separator" , required_argument, NULL, 0},
/* terminator */
- {NULL, no_argument, NULL, 0}
+ {NULL , no_argument , NULL, 0}
};
+ doc = pstring_new ();
+ if (! doc)
+ die ("failed to allocate string");
+
program_name = argv[0];
argvp = argv;
argvc = argc;
@@ -4746,20 +8575,29 @@ main (int argc,
while (TRUE) {
option = getopt_long (argc, argv,
- "aAbcdefghijklLmnNopPqrstTuUvwxyz",
+ "aAbBcCdeEfFghijklLmMnNopPqrsStTuUvwxyYz",
long_options, &long_index);
if (option == -1)
break;
- done = TRUE;
+ /* If the user has specified a display option, only
+ * display that particular group (but crucially don't
+ * count non-display options).
+ */
+ if (option) {
+ done = TRUE;
+ master_header (&doc);
+ }
selected_option = option;
- set_indent ();
-
switch (option)
{
case 0:
+ /* The exception is '--exec' */
+ if (done && strcmp ("exec", long_options[long_index].name))
+ die ("Must specify non-display options before display options");
+
if (! strcmp ("output", long_options[long_index].name)) {
output = get_output_value (optarg);
} else if (! strcmp ("file", long_options[long_index].name)) {
@@ -4767,18 +8605,46 @@ main (int argc,
output_file = optarg;
} else if (! strcmp ("exec", long_options[long_index].name)) {
reexec = TRUE;
- }
+ } else if (! strcmp ("format", long_options[long_index].name)) {
+ output_format = get_output_format (optarg);
+ } else if (! strcmp ("indent", long_options[long_index].name)) {
+ indent_amount = atoi (optarg);
+ if (indent_amount <= 0)
+ die ("cannot specify indent <= 0");
+ } else if (! strcmp ("indent-char", long_options[long_index].name)) {
+ /* Special character handling */
+ if (! strcmp (optarg, "\\t")) {
+ indent_char = "\t";
+ } else {
+ indent_char = optarg;
+ }
+ if (! indent_char)
+ die ("cannot use nul indent character");
- done = FALSE;
+ /* call again */
+ handle_indent_char ();
+ } else if (! strcmp ("separator", long_options[long_index].name)) {
+ if (! strcmp (optarg, "\\t")) {
+ text_separator = "\t";
+ } else {
+ text_separator = optarg;
+ }
+ } else if (! strcmp ("crumb-separator", long_options[long_index].name)) {
+ if (! strcmp (optarg, "\\t")) {
+ crumb_separator = "\t";
+ } else {
+ crumb_separator = optarg;
+ }
+ }
/* reset */
selected_option = 0;
- set_indent ();
+ indent = 0;
break;
case 'a':
- dump_meta ();
+ show_meta ();
break;
case 'A':
@@ -4791,10 +8657,16 @@ main (int argc,
#endif
break;
+ case 'B':
+ show_libc ();
+ break;
+
case 'c':
-#if defined (PROCENV_LINUX)
- show_linux_cgroups ();
-#endif
+ show_cgroups ();
+ break;
+
+ case 'C':
+ show_cpu ();
break;
case 'd':
@@ -4805,8 +8677,16 @@ main (int argc,
show_env ();
break;
+ case 'E':
+ show_semaphores ();
+ break;
+
case 'f':
- dump_fds ();
+ show_fds ();
+ break;
+
+ case 'F':
+ show_namespaces ();
break;
case 'g':
@@ -4821,11 +8701,11 @@ main (int argc,
get_uname ();
get_user_info ();
get_misc ();
- dump_misc ();
+ show_misc ();
break;
case 'j':
- dump_uname ();
+ show_uname ();
break;
case 'k':
@@ -4844,6 +8724,10 @@ main (int argc,
show_mounts (SHOW_MOUNTS);
break;
+ case 'M':
+ show_msg_queues ();
+ break;
+
case 'n':
#ifndef PROCENV_ANDROID
show_confstrs ();
@@ -4855,18 +8739,16 @@ main (int argc,
break;
case 'o':
-#if defined (PROCENV_LINUX)
show_oom ();
-#endif
break;
case 'p':
get_misc ();
- dump_user ();
+ show_proc ();
break;
case 'P':
- dump_platform ();
+ show_platform ();
break;
case 'q':
@@ -4881,6 +8763,10 @@ main (int argc,
show_signals ();
break;
+ case 'S':
+ show_shared_mem ();
+ break;
+
case 't':
show_tty_attrs ();
break;
@@ -4898,17 +8784,11 @@ main (int argc,
break;
case 'v':
- show ("%s %s: %s",
- PACKAGE_NAME,
- _("version"),
- PACKAGE_VERSION);
- show ("%s: %s\n", _("Written by"), PROGRAM_AUTHORS);
+ show_version ();
break;
case 'w':
-#if defined (PROCENV_LINUX)
show_capabilities ();
-#endif
break;
case 'x':
@@ -4916,7 +8796,11 @@ main (int argc,
break;
case 'y':
- dump_sysconf ();
+ show_sysconf ();
+ break;
+
+ case 'Y':
+ show_memory ();
break;
case 'z':
@@ -4929,8 +8813,20 @@ main (int argc,
}
}
- if (done)
- exit (EXIT_SUCCESS);
+ if (done) {
+ common_assert ();
+
+ master_footer (&doc);
+
+ chomp (doc);
+
+
+ if (output_format != OUTPUT_FORMAT_XML && output_format != OUTPUT_FORMAT_JSON) {
+ compress (&doc, wide_indent_char);
+ }
+
+ goto finish;
+ }
if (output == OUTPUT_SYSLOG)
openlog (PACKAGE_NAME, LOG_CONS | LOG_PID, LOG_USER);
@@ -4948,6 +8844,12 @@ main (int argc,
dump ();
+ chomp (doc);
+
+ compress (&doc, wide_indent_char);
+
+finish:
+ _show_output_pstring (doc);
cleanup ();
/* Perform re-exec */
@@ -4964,7 +8866,7 @@ char *
get_user_name (uid_t uid)
{
struct passwd *p;
-
+
p = getpwuid (uid);
return p ? p->pw_name : NULL;
@@ -4974,8 +8876,1875 @@ char *
get_group_name (gid_t gid)
{
struct group *g;
-
+
g = getgrgid (gid);
return g ? g->gr_name : NULL;
}
+
+/**
+ * encode_string:
+ *
+ * @str: string to encode.
+ *
+ * Returns: 0 on success, -1 on failure.
+ *
+ * Convert the specified string to its encoded form. If no encoding is
+ * necessary, the string will not be modified.
+ *
+ * Notes:
+ *
+ * - By encoding, we mean replacing literals with their
+ * format-langage-specific encodings. For example for XML output,
+ * '<' is converted to '&lt;'.
+ *
+ * - It is the callers responsibility to free @str iff this function
+ * is successful. any previous value of @str will be freed by
+ * encode_string().
+ *
+ * BUGS: this is just horribly, horribly gross :(
+ **/
+int
+encode_string (pstring **pstr)
+{
+ int ret = 0;
+ pstring *new = NULL;
+ wchar_t *p, *q;
+ size_t non_printables;
+ size_t len = 0;
+ size_t bytes;
+
+ assert (pstr);
+ assert (*pstr);
+
+ if ((*pstr)->len <= 1) {
+ /* Nothing to do */
+ return 0;
+ }
+
+ switch (output_format) {
+
+ case OUTPUT_FORMAT_CRUMB: /* FALL */
+ case OUTPUT_FORMAT_TEXT:
+ /* Nothing to do */
+ ret = 0;
+ break;
+
+ case OUTPUT_FORMAT_JSON: /* FALL THROUGH */
+ case OUTPUT_FORMAT_XML:
+ new = translate (*pstr);
+ if (new) {
+ pstring_free (*pstr);
+ *pstr = new;
+ new = NULL;
+ } else {
+ ret = -1;
+ }
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ /* Now, search for evil non-printable characters and encode those
+ * appropriately.
+ */
+ for (p = (*pstr)->buf, non_printables = 0; p && *p; p++) {
+ if (! iswprint (*p))
+ non_printables++;
+ }
+
+ if (non_printables &&
+ (output_format == OUTPUT_FORMAT_XML
+ || output_format == OUTPUT_FORMAT_JSON)) {
+
+ size_t new_size = 0;
+
+ wchar_t *json_format = L"\\u%4.4x";
+
+ /* XXX:
+ *
+ * Although this format spec _may_ produce valid XML,
+ * the rules are arcane and some(?) control characters
+ * cannot be used within an XML document, hence the
+ * "may".
+ *
+ * Aside from simply discarding non-printable characters
+ * (thus distorting the output), we are left with
+ * attempting to produce some sort of encoded
+ * representation which may well choke a validating
+ * parser.
+ *
+ * Realistically, the problem is confined to handling
+ * control characters set in environment variables when
+ * attempting to output XML. This may occur if you run
+ * GNU Screen since it sets $TERMCAP which includes
+ * binary characters.
+ *
+ * FIXME:
+ *
+ * If you hit this issue, raise a bug so we can consider
+ * simply discarding all non-printables when attempting
+ * XML output.
+ */
+ wchar_t *xml_format = L"&#x%2.2x;";
+
+ len = (*pstr)->len;
+
+ /* Calculate expanded size of string by removing
+ * count of non-printable byte and adding back the
+ * number of bytes required to encode them in expanded
+ * form.
+ */
+ switch (output_format) {
+ case OUTPUT_FORMAT_XML:
+ new_size = (len - non_printables) + (non_printables * wcslen (L"&#x..;"));
+ break;
+
+ case OUTPUT_FORMAT_JSON:
+ new_size = (len - non_printables) + (non_printables * wcslen (L"\\u...."));
+ break;
+ default:
+ break;
+ }
+
+ new = pstring_new ();
+ if (! new)
+ return -1;
+
+ bytes = (1 + new_size) * sizeof (wchar_t);
+
+ new->buf = malloc (bytes);
+ if (! new->buf) {
+ free (new);
+ return -1;
+ }
+
+ new->size = bytes;
+
+ memset (new->buf, '\0', bytes);
+
+ for (p = (*pstr)->buf, q = new->buf; p && *p; p++) {
+ if (iswprint (*p)) {
+ *q = *p;
+ q++;
+ new->len++;
+ } else {
+ ret = swprintf (q,
+ new_size,
+ output_format == OUTPUT_FORMAT_JSON
+ ? json_format : xml_format,
+ *p);
+ q += ret;
+ }
+ }
+
+ /* include terminator */
+ new->len = wcslen (new->buf) + 1;
+
+ pstring_free (*pstr);
+ *pstr = new;
+ }
+
+ return ret;
+}
+
+/* Performs simple substitution on the input */
+pstring *
+translate (const pstring *pstr)
+{
+ pstring *result = NULL;
+ const wchar_t *start;
+ const wchar_t *p;
+ TranslateTable *table;
+ size_t i;
+ size_t len;
+ size_t extra;
+ size_t bytes;
+ size_t amount;
+ wchar_t from;
+
+ assert (pstr);
+ assert (output_format != OUTPUT_FORMAT_TEXT);
+ assert (output_format != OUTPUT_FORMAT_CRUMB);
+
+ /* Find the correct translation table for the chosen output format */
+ for (i = 0; i < sizeof (translate_table) / sizeof (translate_table[0]); i++) {
+ table = &translate_table[i];
+ if (table && table->output_format == output_format)
+ break;
+ }
+
+ if (! table)
+ return NULL;
+
+ len = pstr->len;
+ start = pstr->buf;
+
+ /* First, calculate the amount of space needed for the expanded
+ * buffer.
+ */
+ extra = 0;
+ while (start && *start) {
+ for (i = 0; i < TRANSLATE_MAP_ENTRIES; i++) {
+ from = table->map[i].from;
+ if (*start == from) {
+ /* Subtract one to take account of the
+ * pre-existing character we're going to
+ * replace.
+ */
+ extra += (wcslen (table->map[i].to) - 1);
+ }
+ }
+ start++;
+ }
+
+ if (! extra) {
+ /* No translation required.
+ *
+ * FIXME: this is inefficient - we should really have
+ * the function accept a 'pstring **' to avoid
+ * re-copying.
+ */
+ return pstring_create (pstr->buf);
+ }
+
+ len += extra;
+
+ result = pstring_new ();
+ if (! result)
+ return NULL;
+
+ /* Note that this includes the space for the terminator
+ * (since a pstring's len includes the terminator)
+ */
+ bytes = len * sizeof (wchar_t);
+
+ result->buf = malloc (bytes);
+ if (! result->buf) {
+ pstring_free (result);
+ return NULL;
+ }
+
+ /* We're using wcsncat() so we'd better make sure there is a
+ * nul for it to find!
+ *
+ * Note: we could have used calloc to do this for us, but
+ * the code is clearer using the @bytes idiom.
+ */
+ memset (result->buf, '\0', bytes);
+
+ result->size = bytes;
+
+ /* Sanity check for upcoming overrun check */
+ assert (result->buf[len-1] == L'\0');
+
+ /* Now, iterate the string again, performing the actual
+ * replacements.
+ */
+ p = start = pstr->buf;
+
+ while (p && *p) {
+ for (i = 0; i < TRANSLATE_MAP_ENTRIES; i++) {
+ wchar_t *to;
+ size_t len;
+
+ from = table->map[i].from;
+
+ if (*p != from)
+ continue;
+
+ to = table->map[i].to;
+
+ amount = p - start;
+
+ /* Copy from start to match */
+ wcsncat (result->buf + result->len, start, amount);
+
+ result->len += amount;
+
+ /* Copy replacement text */
+ len = wcslen (to);
+ wcsncat (result->buf + result->len, to, len);
+ result->len += len;
+
+ /* Jump over the matching character */
+ start = p + 1;
+
+ break;
+ }
+ p++;
+ }
+
+ /* Copy remaining non-matching chars */
+ amount = p - start;
+ wcsncat (result->buf + result->len, start, amount);
+ result->len += amount;
+
+ /* Account for terminator */
+ result->len += 1;
+
+ /* check for buffer overrun */
+ assert (result->buf[len-1] == L'\0');
+
+ return result;
+}
+/**
+ * change_element:
+ *
+ * Handle changing to a new element type. Depending on the output
+ * format, this may require separators and newlines to be emitted to
+ * produce well-formatted output.
+ **/
+void
+change_element (ElementType new)
+{
+ common_assert ();
+
+ last_element = current_element;
+
+ current_element = new;
+
+ format_element ();
+}
+
+void
+format_element (void)
+{
+ switch (output_format) {
+
+ case OUTPUT_FORMAT_TEXT:
+ format_text_element ();
+ break;
+
+ case OUTPUT_FORMAT_CRUMB:
+ /* NOP */
+ break;
+
+ case OUTPUT_FORMAT_JSON:
+ format_json_element ();
+ break;
+
+ case OUTPUT_FORMAT_XML:
+ format_xml_element ();
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+}
+
+void
+format_text_element (void)
+{
+ common_assert ();
+ switch (last_element) {
+
+ case ELEMENT_TYPE_ENTRY:
+ {
+ switch (current_element) {
+ case ELEMENT_TYPE_ENTRY: /* FALL */
+ case ELEMENT_TYPE_SECTION_OPEN: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_OPEN:
+ wappend (&doc, L"\n");
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_CONTAINER_CLOSE: /* FALL */
+ case ELEMENT_TYPE_SECTION_CLOSE:
+ wappend (&doc, L"\n");
+ dec_indent ();
+ add_indent (&doc);
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+ }
+ break;
+
+ case ELEMENT_TYPE_SECTION_OPEN:
+ {
+ switch (current_element) {
+ case ELEMENT_TYPE_ENTRY: /* FALL */
+ case ELEMENT_TYPE_SECTION_OPEN: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_OPEN:
+ wappend (&doc, L"\n");
+ inc_indent ();
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_SECTION_CLOSE:
+ /* NOP */
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+ }
+ break;
+
+ case ELEMENT_TYPE_SECTION_CLOSE:
+ {
+ switch (current_element) {
+ case ELEMENT_TYPE_SECTION_CLOSE: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_CLOSE: /* FALL */
+ wappend (&doc, L"\n");
+ dec_indent ();
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_ENTRY: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_OPEN: /* FALL */
+ case ELEMENT_TYPE_SECTION_OPEN:
+ wappend (&doc, L"\n");
+ add_indent (&doc);
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+ }
+ break;
+
+ case ELEMENT_TYPE_CONTAINER_OPEN:
+ {
+ switch (current_element) {
+ case ELEMENT_TYPE_ENTRY: /* FALL */
+ case ELEMENT_TYPE_SECTION_OPEN: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_OPEN: /* FALL */
+ wappend (&doc, L"\n");
+ inc_indent ();
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_CONTAINER_CLOSE:
+ /* NOP */
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+ }
+ break;
+
+ case ELEMENT_TYPE_CONTAINER_CLOSE:
+ {
+ switch (current_element) {
+ case ELEMENT_TYPE_SECTION_CLOSE: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_CLOSE:
+ wappend (&doc, L"\n");
+ dec_indent ();
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_SECTION_OPEN: /* FALL */
+ case ELEMENT_TYPE_ENTRY: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_OPEN:
+ wappend (&doc, L"\n");
+ add_indent (&doc);
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+ }
+ break;
+
+ case ELEMENT_TYPE_NONE:
+ {
+ switch (current_element) {
+ case ELEMENT_TYPE_ENTRY: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_OPEN: /* FALL */
+ case ELEMENT_TYPE_SECTION_OPEN: /* FALL */
+ case ELEMENT_TYPE_SECTION_CLOSE: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_CLOSE: /* FALL */
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_OBJECT_OPEN: /* FALL */
+ case ELEMENT_TYPE_OBJECT_CLOSE:
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+ }
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+}
+
+void
+format_json_element (void)
+{
+ common_assert ();
+
+ switch (last_element) {
+
+ case ELEMENT_TYPE_ENTRY:
+ {
+ switch (current_element) {
+ case ELEMENT_TYPE_ENTRY: /* FALL */
+ case ELEMENT_TYPE_SECTION_OPEN: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_OPEN:
+ wappend (&doc, L",\n");
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_SECTION_CLOSE: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_CLOSE: /* FALL */
+ case ELEMENT_TYPE_OBJECT_CLOSE:
+ wappend (&doc, L"\n");
+ dec_indent ();
+ add_indent (&doc);
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+ }
+ break;
+
+ case ELEMENT_TYPE_SECTION_OPEN:
+ {
+ switch (current_element) {
+ case ELEMENT_TYPE_ENTRY: /* FALL */
+ case ELEMENT_TYPE_SECTION_OPEN: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_OPEN:
+ wappend (&doc, L"\n");
+ inc_indent ();
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_SECTION_CLOSE:
+ case ELEMENT_TYPE_OBJECT_OPEN:
+ /* NOP */
+ break;
+
+ case ELEMENT_TYPE_CONTAINER_CLOSE:
+ assert_not_reached ();
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+ }
+ break;
+
+ case ELEMENT_TYPE_SECTION_CLOSE:
+ {
+ switch (current_element) {
+ case ELEMENT_TYPE_ENTRY: /* FALL */
+ case ELEMENT_TYPE_SECTION_OPEN: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_OPEN:
+ wappend (&doc, L",\n");
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_OBJECT_OPEN:
+ /* NOP */
+ break;
+
+ case ELEMENT_TYPE_SECTION_CLOSE: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_CLOSE:
+ wappend (&doc, L"\n");
+ dec_indent ();
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_OBJECT_CLOSE:
+ wappend (&doc, L"\n");
+ dec_indent ();
+ add_indent (&doc);
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+ }
+ break;
+
+ case ELEMENT_TYPE_CONTAINER_OPEN:
+ {
+ switch (current_element) {
+ case ELEMENT_TYPE_ENTRY: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_OPEN: /* FALL */
+ case ELEMENT_TYPE_SECTION_OPEN: /* FALL */
+ case ELEMENT_TYPE_OBJECT_OPEN:
+ wappend (&doc, L"\n");
+ inc_indent ();
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_OBJECT_CLOSE:
+ case ELEMENT_TYPE_SECTION_CLOSE:
+ assert_not_reached ();
+ break;
+
+ case ELEMENT_TYPE_CONTAINER_CLOSE:
+ /* NOP */
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+ }
+ break;
+
+ case ELEMENT_TYPE_CONTAINER_CLOSE:
+ {
+ switch (current_element) {
+ case ELEMENT_TYPE_ENTRY: /* FALL */
+ case ELEMENT_TYPE_SECTION_OPEN: /* FALL */
+ case ELEMENT_TYPE_OBJECT_OPEN: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_OPEN:
+ wappend (&doc, L",\n");
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_SECTION_CLOSE: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_CLOSE: /* FALL */
+ case ELEMENT_TYPE_OBJECT_CLOSE:
+ wappend (&doc, L"\n");
+ dec_indent ();
+ add_indent (&doc);
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+ }
+ break;
+
+ case ELEMENT_TYPE_OBJECT_OPEN:
+ {
+ switch (current_element) {
+ case ELEMENT_TYPE_ENTRY: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_OPEN: /* FALL */
+ case ELEMENT_TYPE_SECTION_OPEN:
+ wappend (&doc, L"\n");
+ inc_indent ();
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_OBJECT_CLOSE:
+ /* NOP */
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+ }
+ break;
+
+ case ELEMENT_TYPE_OBJECT_CLOSE:
+ {
+ switch (current_element) {
+ case ELEMENT_TYPE_CONTAINER_CLOSE:
+ case ELEMENT_TYPE_SECTION_CLOSE:
+ wappend (&doc, L"\n");
+ dec_indent ();
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_OBJECT_OPEN:
+ case ELEMENT_TYPE_SECTION_OPEN:
+ wappend (&doc, L",\n");
+ add_indent (&doc);
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+ }
+ break;
+
+ case ELEMENT_TYPE_NONE:
+ {
+ switch (current_element) {
+ case ELEMENT_TYPE_ENTRY: /* FALL */
+ case ELEMENT_TYPE_SECTION_OPEN: /* FALL */
+ case ELEMENT_TYPE_SECTION_CLOSE: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_OPEN: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_CLOSE: /* FALL */
+ case ELEMENT_TYPE_OBJECT_OPEN: /* FALL */
+ case ELEMENT_TYPE_OBJECT_CLOSE:
+ add_indent (&doc);
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+ }
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+}
+
+void
+format_xml_element (void)
+{
+ common_assert ();
+
+ switch (last_element) {
+
+ case ELEMENT_TYPE_ENTRY:
+ {
+ switch (current_element) {
+ case ELEMENT_TYPE_ENTRY: /* FALL */
+ case ELEMENT_TYPE_SECTION_OPEN: /* FALL */
+ case ELEMENT_TYPE_OBJECT_OPEN: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_OPEN:
+ wappend (&doc, L"\n");
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_SECTION_CLOSE: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_CLOSE: /* FALL */
+ case ELEMENT_TYPE_OBJECT_CLOSE:
+ wappend (&doc, L"\n");
+ dec_indent ();
+ add_indent (&doc);
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+ }
+ break;
+
+ case ELEMENT_TYPE_SECTION_OPEN:
+ {
+ switch (current_element) {
+ case ELEMENT_TYPE_ENTRY: /* FALL */
+ case ELEMENT_TYPE_SECTION_OPEN: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_OPEN:
+ wappend (&doc, L"\n");
+ inc_indent ();
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_SECTION_CLOSE:
+ wappend (&doc, L"\n");
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_CONTAINER_CLOSE:
+ assert_not_reached ();
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+ }
+ break;
+
+ case ELEMENT_TYPE_SECTION_CLOSE:
+ {
+ switch (current_element) {
+ case ELEMENT_TYPE_SECTION_CLOSE: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_CLOSE:
+ wappend (&doc, L"\n");
+ dec_indent ();
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_OBJECT_CLOSE:
+ wappend (&doc, L"\n");
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_SECTION_OPEN: /* FALL */
+ case ELEMENT_TYPE_ENTRY: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_OPEN:
+ wappend (&doc, L"\n");
+ add_indent (&doc);
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+ }
+ break;
+
+ case ELEMENT_TYPE_CONTAINER_OPEN:
+ {
+ switch (current_element) {
+ case ELEMENT_TYPE_ENTRY: /* FALL */
+ case ELEMENT_TYPE_SECTION_OPEN: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_OPEN:
+ wappend (&doc, L"\n");
+ inc_indent ();
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_SECTION_CLOSE:
+ assert_not_reached ();
+ break;
+
+ case ELEMENT_TYPE_CONTAINER_CLOSE:
+ wappend (&doc, L"\n");
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_OBJECT_OPEN:
+ add_indent (&doc);
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+ }
+ break;
+
+ case ELEMENT_TYPE_CONTAINER_CLOSE:
+ {
+ switch (current_element) {
+ case ELEMENT_TYPE_SECTION_CLOSE: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_CLOSE: /* FALL */
+ case ELEMENT_TYPE_OBJECT_CLOSE:
+ wappend (&doc, L"\n");
+ dec_indent ();
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_ENTRY: /* FALL */
+ case ELEMENT_TYPE_SECTION_OPEN: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_OPEN:
+ wappend (&doc, L"\n");
+ add_indent (&doc);
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+ }
+ break;
+
+ case ELEMENT_TYPE_OBJECT_OPEN:
+ {
+ switch (current_element) {
+ case ELEMENT_TYPE_ENTRY: /* FALL */
+ case ELEMENT_TYPE_SECTION_OPEN:
+ wappend (&doc, L"\n");
+ inc_indent ();
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_CONTAINER_OPEN:
+ wappend (&doc, L"\n");
+ inc_indent ();
+ add_indent (&doc);
+ break;
+
+ case ELEMENT_TYPE_OBJECT_CLOSE:
+ /* NOP */
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+ }
+ break;
+
+ case ELEMENT_TYPE_OBJECT_CLOSE:
+ {
+ switch (current_element) {
+ case ELEMENT_TYPE_OBJECT_OPEN: /* FALL */
+ case ELEMENT_TYPE_SECTION_CLOSE:
+ /* NOP */
+ break;
+
+ case ELEMENT_TYPE_CONTAINER_CLOSE:
+ case ELEMENT_TYPE_ENTRY:
+ wappend (&doc, L"\n");
+ dec_indent ();
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+ }
+ break;
+
+ case ELEMENT_TYPE_NONE:
+ {
+ switch (current_element) {
+ case ELEMENT_TYPE_ENTRY: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_OPEN: /* FALL */
+ case ELEMENT_TYPE_SECTION_OPEN: /* FALL */
+ case ELEMENT_TYPE_SECTION_CLOSE: /* FALL */
+ case ELEMENT_TYPE_CONTAINER_CLOSE: /* FALL */
+ case ELEMENT_TYPE_OBJECT_OPEN: /* FALL */
+ case ELEMENT_TYPE_OBJECT_CLOSE:
+ add_indent (&doc);
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+ }
+ break;
+
+ default:
+ assert_not_reached ();
+ break;
+ }
+}
+
+/**
+ * compress:
+ *
+ * Remove lines composed entirely of whitespace from @str.
+ *
+ * This is required specifically for '--output=text' which in some
+ * scenarios generates lines comprising pure whitespace. This is
+ * unecessary and results from the fact that when an
+ * ELEMENT_TYPE_OBJECT_* is encountered, formatting is applied for the
+ * previously seen element, but sometimes such "objects" should be
+ * invisible.
+ **/
+void
+compress (pstring **wstr, wchar_t remove_char)
+{
+ wchar_t *from;
+ wchar_t *to;
+ wchar_t *p;
+ wchar_t *start;
+ size_t count = 0;
+ size_t blanks = 0;
+ size_t new_len;
+ size_t bytes;
+
+ assert (wstr);
+
+ to = from = (*wstr)->buf;
+
+ while (to && *to) {
+again:
+ while (*to == L'\n' && *(to+1) == L'\n') {
+ /* skip over blank lines */
+ to++;
+ blanks++;
+ }
+
+ start = to;
+
+ while (*to == remove_char) {
+ /* skip runs of contiguous characters */
+ to++;
+ count++;
+ }
+
+ if (to != start) {
+ /* Only start consuming NLs at the end of a
+ * contiguous run *iff* there was more than a
+ * single removed char. This is a heuristic to
+ * avoid removing valid entries for example env
+ * vars that are set to nul are shown as:
+ *
+ * 'var: '
+ *
+ * Shudder.
+ */
+ if (*to == L'\n' && to != start+1) {
+ while (*to == L'\n') {
+ /* consume the NL at the end of the contiguous run */
+ to++;
+ }
+
+ /* check to ensure that we haven't entered a new line
+ * containing another block of chars to remove.
+ */
+ if (*to == remove_char)
+ goto again;
+
+ blanks++;
+
+ } else {
+ /* not a full line so backtrack */
+ to = start;
+ count = 0;
+ }
+ }
+
+ *from++ = *to++;
+ }
+
+ /* terminate */
+ *from = L'\0';
+
+ if (blanks || count) {
+ new_len = (*wstr)->len - (blanks + count);
+
+ bytes = new_len * sizeof (wchar_t);
+
+ p = realloc ((*wstr)->buf, bytes);
+ assert (p);
+
+ (*wstr)->buf = p;
+
+ (*wstr)->buf[new_len-1] = L'\0';
+
+ (*wstr)->len = new_len;
+ (*wstr)->size = bytes;
+ }
+}
+/**
+ * chomp:
+ *
+ * Remove trailing extraneous newlines and indent_chars from @str.
+ **/
+void
+chomp (pstring *str)
+{
+ size_t len;
+ int removable = 0;
+ wchar_t *p;
+
+ assert (str);
+
+ /* Unable to add '\n' in this scenario */
+ if (str->len < 2)
+ return;
+
+ for (p = str->buf+str->len-1; *p == L'\n' || *p == wide_indent_char;
+ p--, removable++)
+ ;
+
+ /* Chop string at the appropriate place after first adding a new
+ * newline.
+ */
+ if (removable > 1) {
+ len = str->len - (removable-1);
+ str->buf[len-1] = L'\n';
+ str->buf[len] = L'\0';
+ str->len = len;
+ }
+}
+
+void
+show_version (void)
+{
+ common_assert ();
+
+ header ("version");
+
+ entry (_("name"), "%s", PACKAGE_NAME);
+ entry (_("version"), "%s", PACKAGE_VERSION);
+ entry (_("author"), "%s", PROGRAM_AUTHORS);
+
+ footer ();
+}
+
+void
+show_shared_mem (void)
+{
+#if defined (PROCENV_LINUX) || defined (PROCENV_HURD)
+ show_shared_mem_linux ();
+#else
+ show_shared_mem_stub ();
+#endif
+}
+
+void
+show_semaphores (void)
+{
+#if defined (PROCENV_LINUX) || defined (PROCENV_HURD)
+ show_semaphores_linux ();
+#else
+ show_semaphores_stub ();
+#endif
+}
+
+void
+show_msg_queues (void)
+{
+#if defined (PROCENV_LINUX) || defined (PROCENV_HURD)
+ show_msg_queues_linux ();
+#else
+ show_msg_queues_stub ();
+#endif
+}
+
+
+#if defined (PROCENV_LINUX) || defined (PROCENV_HURD)
+void
+show_shared_mem_linux (void)
+{
+ int i;
+ int id;
+ int max;
+ struct shm_info info;
+ struct shmid_ds shmid_ds;
+ struct ipc_perm *perm;
+ char formatted_atime[CTIME_BUFFER];
+ char formatted_ctime[CTIME_BUFFER];
+ char formatted_dtime[CTIME_BUFFER];
+ char *modestr = NULL;
+ int locked = -1;
+ int destroy = -1;
+ char *cpid = NULL;
+ char *lpid = NULL;
+
+ header ("shared memory");
+
+ max = shmctl (0, SHM_INFO, (void *)&info);
+ if (max < 0)
+ goto out;
+
+ /* Display summary details */
+
+ section_open ("info");
+
+ entry ("segments", "%u", info.used_ids);
+ entry ("pages", "%lu", info.shm_tot);
+ entry ("shm_rss", "%lu", info.shm_rss);
+ entry ("shm_swp", "%lu", info.shm_swp);
+
+ /* Apparently unused */
+ entry ("swap_attempts", "%lu", info.swap_attempts);
+ entry ("swap_successes", "%lu", info.swap_successes);
+
+ section_close ();
+
+ container_open ("segments");
+
+ object_open (FALSE);
+
+ for (i = 0; i <= max; i++) {
+ char *id_str = NULL;
+
+ id = shmctl (i, SHM_STAT, &shmid_ds);
+ if (id < 0) {
+ /* found an unused slot, so ignore it */
+ continue;
+ }
+
+ perm = &shmid_ds.shm_perm;
+
+ modestr = format_perms (perm->mode);
+ if (! modestr)
+ die ("failed to allocate space for permissions string");
+
+#ifdef PROCENV_LINUX
+ locked = (perm->mode & SHM_LOCKED);
+ destroy = (perm->mode & SHM_DEST);
+#endif
+
+ format_time (&shmid_ds.shm_atime, formatted_atime, sizeof (formatted_atime));
+ format_time (&shmid_ds.shm_ctime, formatted_ctime, sizeof (formatted_ctime));
+ format_time (&shmid_ds.shm_dtime, formatted_dtime, sizeof (formatted_dtime));
+
+ cpid = pid_to_name (shmid_ds.shm_cpid);
+ lpid = pid_to_name (shmid_ds.shm_lpid);
+
+ appendf (&id_str, "%d", id);
+
+ container_open (id_str);
+ free (id_str);
+
+ object_open (FALSE);
+
+ /* pad out to max pointer size represented in hex.
+ */
+ entry ("key", "0x%.*x", POINTER_SIZE * 2, perm->__key);
+ entry ("sequence", "%u", perm->__seq);
+
+ section_open ("permissions");
+ entry ("octal", "%4.4o", perm->mode);
+ entry ("symbolic", "%s", modestr);
+ section_close ();
+
+ section_open ("pids");
+ entry ("create", "%d (%s)", shmid_ds.shm_cpid, cpid ? cpid : UNKNOWN_STR);
+ entry ("last", "%d (%s)", shmid_ds.shm_lpid, lpid ? lpid : UNKNOWN_STR);
+ section_close ();
+
+ entry ("attachers", "%lu", shmid_ds.shm_nattch);
+
+ section_open ("creator");
+ entry ("euid", "%u ('%s')", perm->cuid, get_user_name (perm->cuid));
+ entry ("egid", "%u ('%s')", perm->cgid, get_group_name (perm->cgid));
+ section_close ();
+
+ section_open ("owner");
+ entry ("uid", "%u ('%s')", perm->uid, get_user_name (perm->uid));
+ entry ("gid", "%u ('%s')", perm->gid, get_group_name (perm->gid));
+ section_close ();
+
+ entry ("segment size", "%lu", shmid_ds.shm_segsz);
+
+ section_open ("times");
+ entry ("last attach (atime)", "%lu (%s)", shmid_ds.shm_atime, formatted_atime);
+ entry ("last detach (dtime)", "%lu (%s)", shmid_ds.shm_dtime, formatted_dtime);
+ entry ("last change (ctime)", "%lu (%s)", shmid_ds.shm_ctime, formatted_ctime);
+ section_close ();
+
+ entry ("locked", "%s", locked == 0 ? NO_STR
+ : locked > 0 ? YES_STR
+ : NA_STR);
+ entry ("destroy", "%s", destroy == 0 ? NO_STR
+ : destroy > 0 ? YES_STR
+ : NA_STR);
+
+ object_close (FALSE);
+
+ container_close ();
+
+ free (modestr);
+ if (cpid)
+ free (cpid);
+ if (lpid)
+ free (lpid);
+ }
+
+ object_close (FALSE);
+
+ container_close ();
+
+out:
+ footer ();
+}
+
+void
+show_semaphores_linux (void)
+{
+ int i;
+ int id;
+ int max;
+ struct semid_ds semid_ds;
+ struct seminfo info;
+ struct ipc_perm *perm;
+ char formatted_otime[CTIME_BUFFER];
+ char formatted_ctime[CTIME_BUFFER];
+ char *modestr = NULL;
+ union semun arg;
+
+ header ("semaphores");
+
+ arg.array = (unsigned short int *)(void *)&info;
+ max = semctl (0, 0, SEM_INFO, arg);
+ if (max < 0)
+ goto out;
+
+ section_open ("info");
+
+ entry ("semmap", "%d", info.semmap);
+ entry ("semmni", "%d", info.semmni);
+ entry ("semmns", "%d", info.semmns);
+ entry ("semmnu", "%d", info.semmnu);
+ entry ("semmsl", "%d", info.semmsl);
+ entry ("semopm", "%d", info.semopm);
+ entry ("semume", "%d", info.semume);
+ entry ("semusz", "%d", info.semusz);
+ entry ("semvmx", "%d", info.semvmx);
+ entry ("semaem", "%d", info.semaem);
+
+ section_close ();
+
+ container_open ("set");
+
+ object_open (FALSE);
+
+ for (i = 0; i <= max; i++) {
+ char *id_str = NULL;
+
+ /* see semctl(2) */
+ arg.buf = (struct semid_ds *)&semid_ds;
+
+ id = semctl (i, 0, SEM_STAT, arg);
+ if (id < 0) {
+ /* found an unused slot, so ignore it */
+ continue;
+ }
+
+ perm = &semid_ds.sem_perm;
+
+ modestr = format_perms (perm->mode);
+ if (! modestr)
+ die ("failed to allocate space for permissions string");
+
+ /* May not have been set */
+ if (semid_ds.sem_otime)
+ format_time (&semid_ds.sem_otime, formatted_otime, sizeof (formatted_otime));
+ else
+ sprintf (formatted_otime, "%s", NA_STR);
+
+ format_time (&semid_ds.sem_ctime, formatted_ctime, sizeof (formatted_ctime));
+
+ appendf (&id_str, "%d", id);
+
+ container_open (id_str);
+ free (id_str);
+
+ object_open (FALSE);
+
+ /* pad out to max pointer size represented in hex.
+ */
+ entry ("key", "0x%.*x", POINTER_SIZE * 2, perm->__key);
+ entry ("sequence", "%u", perm->__seq);
+
+ entry ("number in set", "%lu", semid_ds.sem_nsems);
+
+ section_open ("permissions");
+ entry ("octal", "%4.4o", perm->mode);
+ entry ("symbolic", "%s", modestr);
+ free (modestr);
+ section_close ();
+
+ section_open ("creator");
+ entry ("euid", "%u ('%s')", perm->cuid, get_user_name (perm->cuid));
+ entry ("egid", "%u ('%s')", perm->cgid, get_group_name (perm->cgid));
+ section_close ();
+
+ section_open ("owner");
+ entry ("uid", "%u ('%s')", perm->uid, get_user_name (perm->uid));
+ entry ("gid", "%u ('%s')", perm->gid, get_group_name (perm->gid));
+ section_close ();
+
+ section_open ("times");
+ entry ("last semop (otime)", "%lu (%s)", semid_ds.sem_otime, formatted_otime);
+ entry ("last change (ctime)", "%lu (%s)", semid_ds.sem_ctime, formatted_ctime);
+ section_close ();
+
+ object_close (FALSE);
+
+ container_close ();
+ }
+
+ object_close (FALSE);
+
+ container_close ();
+
+out:
+ footer ();
+}
+
+void
+show_msg_queues_linux (void)
+{
+ int i;
+ int id;
+ int max;
+ struct msginfo info;
+ struct msqid_ds msqid_ds;
+ struct ipc_perm *perm;
+ char formatted_stime[CTIME_BUFFER];
+ char formatted_rtime[CTIME_BUFFER];
+ char formatted_ctime[CTIME_BUFFER];
+ char *modestr = NULL;
+ char *lspid = NULL;
+ char *lrpid = NULL;
+
+ header ("message queues");
+
+ max = msgctl (0, MSG_INFO, (void *)&info);
+ if (max < 0)
+ goto out;
+
+ section_open ("info");
+
+ entry ("msgpool", "%d", info.msgpool);
+ entry ("msgmap", "%d", info.msgmap);
+ entry ("msgmax", "%d", info.msgmax);
+ entry ("msgmnb", "%d", info.msgmnb);
+ entry ("msgmni", "%d", info.msgmni);
+ entry ("msgssz", "%d", info.msgssz);
+ entry ("msgtql", "%d", info.msgtql);
+ entry ("msgseg", "%d", info.msgseg);
+
+ section_close ();
+
+ container_open ("sets");
+
+ object_open (FALSE);
+
+ for (i = 0; i <= max; i++) {
+ char *id_str = NULL;
+
+ id = msgctl (i, MSG_STAT, &msqid_ds);
+ if (id < 0) {
+ /* found an unused slot, so ignore it */
+ continue;
+ }
+
+ perm = &msqid_ds.msg_perm;
+
+ modestr = format_perms (perm->mode);
+ if (! modestr)
+ die ("failed to allocate space for permissions string");
+
+ /* May not have been set */
+ if (msqid_ds.msg_stime)
+ format_time (&msqid_ds.msg_stime, formatted_stime, sizeof (formatted_stime));
+ else
+ sprintf (formatted_stime, "%s", NA_STR);
+
+ /* May not have been set */
+ if (msqid_ds.msg_rtime)
+ format_time (&msqid_ds.msg_rtime, formatted_rtime, sizeof (formatted_rtime));
+ else
+ sprintf (formatted_rtime, "%s", NA_STR);
+
+ /* May not have been set */
+ if (msqid_ds.msg_ctime)
+ format_time (&msqid_ds.msg_ctime, formatted_ctime, sizeof (formatted_ctime));
+ else
+ sprintf (formatted_ctime, "%s", NA_STR);
+
+ lspid = pid_to_name (msqid_ds.msg_lspid);
+ lrpid = pid_to_name (msqid_ds.msg_lrpid);
+
+ appendf (&id_str, "%d", id);
+
+ container_open (id_str);
+ free (id_str);
+
+ object_open (FALSE);
+
+ /* pad out to max pointer size represented in hex */
+ entry ("key", "0x%.*x", POINTER_SIZE * 2, perm->__key);
+ entry ("sequence", "%u", perm->__seq);
+
+ section_open ("permissions");
+ entry ("octal", "%4.4o", perm->mode);
+ entry ("symbolic", "%s", modestr);
+ section_close ();
+
+ section_open ("creator");
+ entry ("euid", "%u ('%s')", perm->cuid, get_user_name (perm->cuid));
+ entry ("egid", "%u ('%s')", perm->cgid, get_group_name (perm->cgid));
+ section_close ();
+
+ section_open ("owner");
+ entry ("uid", "%u ('%s')", perm->uid, get_user_name (perm->uid));
+ entry ("gid", "%u ('%s')", perm->gid, get_group_name (perm->gid));
+ section_close ();
+
+ section_open ("times");
+ entry ("last send (stime)", "%lu (%s)", msqid_ds.msg_stime, formatted_stime);
+ entry ("last receive (rtime)", "%lu (%s)", msqid_ds.msg_rtime, formatted_rtime);
+ entry ("last change (ctime)", "%lu (%s)", msqid_ds.msg_ctime, formatted_ctime);
+ section_close ();
+
+ entry ("queue_bytes", "%lu", msqid_ds.__msg_cbytes);
+
+ entry ("msg_qnum", "%lu", msqid_ds.msg_qnum);
+ entry ("msg_qbytes", "%lu", msqid_ds.msg_qbytes);
+
+ entry ("last msgsnd pid", "%d (%s)", msqid_ds.msg_lspid,
+ lspid ? lspid : UNKNOWN_STR);
+
+ entry ("last msgrcv pid", "%d (%s)", msqid_ds.msg_lrpid,
+ lrpid ? lrpid : UNKNOWN_STR);
+
+ object_close (FALSE);
+
+ container_close ();
+
+ free (modestr);
+ if (lspid)
+ free (lspid);
+ if (lrpid)
+ free (lrpid);
+ }
+
+ object_close (FALSE);
+
+ container_close ();
+
+out:
+ footer ();
+}
+#endif /* PROCENV_LINUX || PROCENV_HURD */
+
+void
+format_time (const time_t *t, char *buffer, size_t len)
+{
+ char *str = NULL;
+ size_t l;
+
+ assert (t);
+ assert (buffer);
+
+ str = ctime (t);
+ if (! str)
+ die ("failed to format time");
+
+ l = strlen (str);
+
+ if (len < l)
+ bug ("buffer too small");
+
+ /* Ensure nul byte copied */
+ strncpy (buffer, str, l+1);
+
+ /* Overwrite NL */
+ buffer[strlen (buffer)-1] = '\0';
+}
+
+char *
+format_perms (mode_t mode)
+{
+ char *modestr = NULL;
+ mode_t perms;
+ int i = 0;
+
+ /*
+ * "-rwxrwxrwx" = 10+1 bytes.
+ */
+ modestr = calloc ((1+3+3+3)+1, sizeof (char));
+
+ if (! modestr)
+ return NULL;
+
+ modestr[i++] = (S_ISLNK (mode & S_IFMT)) ? 'l' : '-';
+
+ perms = (mode & S_IRWXU);
+ modestr[i++] = (perms & S_IRUSR) ? 'r' : '-';
+ modestr[i++] = (perms & S_IWUSR) ? 'w' : '-';
+ modestr[i++] = (perms & S_IXUSR) ? 'x' : '-';
+
+ perms = (mode & S_IRWXG);
+ modestr[i++] = (perms & S_IRGRP) ? 'r' : '-';
+ modestr[i++] = (perms & S_IWGRP) ? 'w' : '-';
+ modestr[i++] = (perms & S_IXGRP) ? 'x' : '-';
+
+ perms = (mode & S_IRWXO);
+ modestr[i++] = (perms & S_IROTH) ? 'r' : '-';
+ modestr[i++] = (perms & S_IWOTH) ? 'w' : '-';
+ modestr[i++] = (perms & S_IXOTH) ? 'x' : '-';
+
+ perms = (mode &= ~S_IFMT);
+ if (perms & S_ISUID)
+ modestr[3] = 's';
+ if (perms & S_ISGID)
+ modestr[6] = 's';
+ if (perms & S_ISVTX)
+ modestr[9] = 't';
+
+ return modestr;
+}
+
+char *
+pid_to_name (pid_t pid)
+{
+ char path[PATH_MAX];
+ char *name = NULL;
+ FILE *f = NULL;
+
+ sprintf (path, "/proc/%d/cmdline", (int)pid);
+
+ f = fopen (path, "r");
+ if (! f)
+ goto out;
+
+ /* Reuse buffer */
+ if (! fgets (path, sizeof (path), f))
+ goto out;
+
+ /* Nul delimiting within /proc file will ensure we only get the
+ * program name.
+ */
+ append (&name, path);
+
+out:
+ if (f)
+ fclose (f);
+
+ return name;
+}
+
+
+void
+add_breadcrumb (const char *name)
+{
+ assert (name);
+
+ if (! crumb_list)
+ crumb_list = pr_list_new (NULL);
+
+ assert (crumb_list);
+
+ pr_list_prepend_str (crumb_list, name);
+}
+
+void
+remove_breadcrumb (void)
+{
+ PRList *entry;
+
+ assert (crumb_list);
+
+ entry = pr_list_remove (crumb_list->prev);
+ assert (entry);
+
+ free ((char *)entry->data);
+ free (entry);
+}
+
+void
+clear_breadcrumbs (void)
+{
+ assert (crumb_list);
+
+ while (crumb_list->prev != crumb_list)
+ remove_breadcrumb ();
+}
+
+wchar_t *
+char_to_wchar (const char *str)
+{
+ const char *p;
+ wchar_t *wstr = NULL;
+ size_t len;
+ size_t bytes;
+
+ assert (str);
+
+ len = mbsrtowcs (NULL, &str, 0, NULL);
+ if (len <= 0)
+ return NULL;
+
+ /* include space for terminator */
+ bytes = (1 + len) * sizeof (wchar_t);
+
+ wstr = malloc (bytes);
+ if (! wstr)
+ return NULL;
+
+ p = str;
+
+ if (mbsrtowcs (wstr, &p, len, NULL) != len)
+ goto error;
+
+ /* ensure it's terminated */
+ wstr[len] = L'\0';
+
+ return wstr;
+
+error:
+ free (wstr);
+ return NULL;
+}
+
+pstring *
+pstring_new (void)
+{
+ pstring *pstr = NULL;
+
+ pstr = calloc (1, sizeof (pstring));
+ if (! pstr)
+ return NULL;
+
+ pstr->len = 0;
+ pstr->size = 0;
+ pstr->buf = NULL;
+
+ return pstr;
+}
+
+pstring *
+pstring_create (const wchar_t *str)
+{
+ pstring *pstr = NULL;
+
+ assert (str);
+
+ pstr = pstring_new ();
+
+ if (! pstr)
+ return NULL;
+
+ pstr->buf = wcsdup (str);
+ if (! pstr->buf) {
+ pstring_free (pstr);
+ return NULL;
+ }
+
+ /* include the L'\0' terminator */
+ pstr->len = 1 + wcslen (pstr->buf);
+
+ pstr->size = pstr->len * sizeof (wchar_t);
+
+ return pstr;
+}
+
+void
+pstring_free (pstring *str)
+{
+ assert (str);
+
+ if (str->buf)
+ free (str->buf);
+
+ free (str);
+}
+
+pstring *
+char_to_pstring (const char *str)
+{
+ pstring *pstr = NULL;
+ wchar_t *s;
+
+ assert (str);
+
+ s = char_to_wchar (str);
+ if (! s)
+ return NULL;
+
+ pstr = pstring_create (s);
+
+ free (s);
+
+ return pstr;
+}
+
+char *
+pstring_to_char (const pstring *str)
+{
+ assert (str);
+
+ return wchar_to_char (str->buf);
+}
+
+char *
+wchar_to_char (const wchar_t *wstr)
+{
+ char *str = NULL;
+ size_t len;
+ size_t bytes;
+ size_t ret;
+
+ assert (wstr);
+
+ len = wcslen (wstr);
+
+ /* determine number of MBS (char) bytes requires to hold the
+ * wchar_t string.
+ */
+ bytes = wcstombs (NULL, wstr, len);
+ if (! bytes)
+ return NULL;
+
+ str = calloc (bytes + 1, sizeof (char));
+ if (! str)
+ return NULL;
+
+ /* actually perform the conversion */
+ ret = wcstombs (str, wstr, bytes);
+
+ if (! ret)
+ goto error;
+
+ return str;
+
+error:
+ free (str);
+ return NULL;
+}
+
+#if ! defined (HAVE_SCHED_GETCPU)
+
+/**
+ * @string: input,
+ * @delimiter: field delimiter,
+ * @compress: if TRUE, ignore repeated contiguous delimiter characters,
+ * @array: [output] array of fields, which this function will allocate.
+ *
+ * Notes: it is the callers responsibility to free @array
+ * if the returned value is >0.
+ *
+ * Returns: number of fields in @string.
+ **/
+size_t
+split_fields (const char *string, char delimiter, int compress, char ***array)
+{
+ const char *p = NULL;
+ const char *start = NULL;
+ size_t count = 0;
+ char *elem;
+ char **new;
+
+ assert (string);
+ assert (delimiter);
+ assert (array);
+
+ *array = NULL;
+
+ new = realloc ((*array), sizeof (char *) * (1+count));
+ assert (new);
+
+ new[0] = NULL;
+ *array = new;
+
+ p = string;
+
+ while (p && *p) {
+ /* skip leading prefix */
+ while (compress && p && *p == delimiter)
+ p++;
+
+ if (! *p)
+ break;
+
+ /* found a field */
+ count++;
+
+ if (! compress)
+ p++;
+
+ /* skip over the field */
+ start = p;
+ while (p && *p && *p != delimiter)
+ p++;
+
+ elem = strndup (start, p-start);
+ assert (elem);
+
+ new = realloc ((*array), sizeof (char *) * (1+count));
+ assert (new);
+
+ new[count-1] = elem;
+ *array = new;
+ }
+
+ return count;
+}
+
+#endif