summaryrefslogtreecommitdiff
path: root/src/platform/platform-generic.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform/platform-generic.c')
-rw-r--r--src/platform/platform-generic.c973
1 files changed, 973 insertions, 0 deletions
diff --git a/src/platform/platform-generic.c b/src/platform/platform-generic.c
new file mode 100644
index 0000000..de34382
--- /dev/null
+++ b/src/platform/platform-generic.c
@@ -0,0 +1,973 @@
+/*--------------------------------------------------------------------
+ * Copyright © 2016 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *--------------------------------------------------------------------
+ */
+
+#include "procenv.h"
+
+#include "platform-generic.h"
+#include "messages.h"
+
+extern struct procenv_ops *ops;
+
+void
+show_rlimits_generic (void)
+{
+#if defined (RLIMIT_AS)
+ show_limit (RLIMIT_AS);
+#endif
+
+ show_limit (RLIMIT_CORE);
+ show_limit (RLIMIT_CPU);
+ show_limit (RLIMIT_DATA);
+ show_limit (RLIMIT_FSIZE);
+ show_limit (RLIMIT_MEMLOCK);
+ show_limit (RLIMIT_NOFILE);
+ show_limit (RLIMIT_NPROC);
+ show_limit (RLIMIT_RSS);
+ show_limit (RLIMIT_STACK);
+}
+
+#if !defined (PROCENV_PLATFORM_DARWIN)
+
+void
+show_clocks_generic (void)
+{
+ show_clock_res (CLOCK_REALTIME);
+
+#if defined CLOCK_REALTIME_COARSE
+ show_clock_res (CLOCK_REALTIME_COARSE);
+#endif
+
+#if defined CLOCK_REALTIME_HR
+ show_clock_res (CLOCK_REALTIME_HR);
+#endif
+
+ show_clock_res (CLOCK_MONOTONIC);
+
+#if defined CLOCK_MONOTONIC_COARSE
+ show_clock_res (CLOCK_MONOTONIC_COARSE);
+#endif
+
+#if defined CLOCK_MONOTONIC_RAW
+ show_clock_res (CLOCK_MONOTONIC_RAW);
+#endif
+
+#if defined (PROCENV_PLATFORM_LINUX) || defined (PROCENV_PLATFORM_HURD)
+
+#ifdef CLOCK_MONOTONIC_RAW
+ show_clock_res (CLOCK_MONOTONIC_RAW);
+#endif
+ show_clock_res (CLOCK_PROCESS_CPUTIME_ID);
+ show_clock_res (CLOCK_THREAD_CPUTIME_ID);
+#if defined CLOCK_BOOTTIME
+ show_clock_res (CLOCK_BOOTTIME);
+#endif
+
+#endif
+}
+
+#endif
+
+long
+get_kernel_bits_generic (void)
+{
+ long value;
+
+ errno = 0;
+#if defined (_SC_LONG_BIT)
+ value = get_sysconf (_SC_LONG_BIT);
+ if (value == -1 && errno != 0)
+ return -1;
+#else
+ value = sizeof (long) * CHAR_BIT;
+#endif
+ return value;
+}
+
+#if !defined (PROCENV_PLATFORM_MINIX)
+int
+get_mtu_generic (const struct ifaddrs *ifaddr)
+{
+ int sock;
+ struct ifreq ifr;
+ unsigned long request = SIOCGIFMTU;
+
+ assert (ifaddr);
+
+ /* We need to create a socket to query an interfaces MAC
+ * address.
+ */
+ sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_IP);
+
+ if (sock < 0)
+ return -1;
+
+ memset (&ifr, 0, sizeof (struct ifreq));
+ strncpy (ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ-1);
+
+ if (ioctl (sock, request, &ifr) < 0)
+ ifr.ifr_mtu = 0;
+
+ close (sock);
+
+ return ifr.ifr_mtu;
+}
+#endif
+
+#if !defined (PROCENV_PLATFORM_DARWIN)
+
+bool
+get_time_generic (struct timespec *ts)
+{
+ return clock_gettime (CLOCK_REALTIME, ts);
+}
+
+#endif
+
+void
+show_fds_generic (void)
+{
+ int fd;
+ int max;
+
+ 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 HAVE_TTYNAME
+ 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 (ops->show_fd_capabilities)
+ ops->show_fd_capabilities (fd);
+
+ section_close ();
+
+ section_close ();
+
+ object_close (false);
+
+ free (num);
+ }
+}
+
+void
+show_confstrs_generic (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
+}
+
+#if defined (PROCENV_PLATFORM_LINUX) || \
+ defined (PROCENV_PLATFORM_BSD) || \
+ defined (PROCENV_PLATFORM_HURD)
+
+/* 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_generic (void)
+{
+ PROCENV_CPU_SET_TYPE *cpu_set;
+ char *cpu_list = NULL;
+ PROCENV_CPU_TYPE cpu;
+ PROCENV_CPU_TYPE max;
+
+ /* 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;
+
+ if (! ops->get_cpuset)
+ return;
+
+ if (! ops->cpuset_has_cpu)
+ return;
+
+ cpu_set = ops->get_cpuset();
+ if (! cpu_set)
+ return;
+
+ // FIXME: should be handled by get_cpuset()!!
+ max = get_sysconf (_SC_NPROCESSORS_ONLN);
+
+ for (cpu = 0; cpu < max; cpu++) {
+
+ if (ops->cpuset_has_cpu (cpu_set, cpu)) {
+ /* 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);
+ }
+ }
+
+ entry ("affinity list", "%s", cpu_list ? cpu_list : "-1");
+
+ if (ops->free_cpuset)
+ ops->free_cpuset (cpu_set);
+
+ free (cpu_list);
+}
+
+#endif /* PROCENV_PLATFORM_LINUX || PROCENV_PLATFORM_FREEBSD || PROCENV_PLATFORM_HURD */
+
+#if defined (PROCENV_PLATFORM_LINUX) || \
+ defined (PROCENV_PLATFORM_BSD) || \
+ defined (PROCENV_PLATFORM_HURD) || \
+ defined (PROCENV_PLATFORM_MINIX) || \
+ defined (PROCENV_PLATFORM_DARWIN)
+
+void
+show_pathconfs (ShowMountType what,
+ const char *dir)
+{
+ assert (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);
+#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 ();
+}
+
+#endif
+
+#if defined (PROCENV_PLATFORM_BSD) || \
+ defined (PROCENV_PLATFORM_MINIX) || \
+ defined (PROCENV_PLATFORM_DARWIN)
+
+char *
+get_mount_opts_generic_bsd (const struct procenv_map64 *opts, uint64_t flags)
+{
+ const struct procenv_map64 *opt;
+ char *str = NULL;
+ size_t len = 0;
+ size_t total = 0;
+ int count = 0;
+
+ if (! flags)
+ return strdup ("");
+
+ /* Calculate how much space we need to allocate by iterating
+ * array for the first time.
+ */
+ for (opt = opts; opt && opt->name; opt++) {
+ if (flags & opt->num) {
+ count++;
+ len += strlen (opt->name);
+ }
+ }
+
+ if (count > 1) {
+ /* we need space for the option value themselves, plus a
+ * ", " separator between each option (except the first),
+ * and finally space for the nul terminator */
+ total = len + (count-1) + 1;
+ } else {
+ total = len + 1;
+ }
+
+ str = calloc (total, sizeof (char));
+ if (! str)
+ die ("failed to allocate space for mount options");
+
+ /* Re-iterate to construct the string. This is still going to be
+ * a lot quicker than calling malloc a stack of times.
+ */
+ for (opt = opts; opt && opt->name; opt++) {
+ if (flags & opt->num) {
+ strcat (str, opt->name);
+ if (count > 1)
+ strcat (str, ",");
+ count--;
+ }
+ }
+
+ return str;
+}
+
+void
+show_mounts_generic_bsd (ShowMountType what,
+ const struct procenv_map64 *mntopt_map)
+{
+ procenv_mnt_type *mounts;
+ procenv_mnt_type *mnt;
+ int count;
+ unsigned int major = 0;
+ unsigned int minor = 0;
+ int i;
+ unsigned multiplier = 0;
+ PROCENV_STATFS_INT_TYPE blocks;
+ PROCENV_STATFS_INT_TYPE bfree;
+ PROCENV_STATFS_INT_TYPE bavail;
+ PROCENV_STATFS_INT_TYPE used;
+
+ common_assert ();
+ assert (mntopt_map);
+
+ /* Note that returned memory cannot be freed (by us) */
+ count = getmntinfo (&mounts, MNT_WAIT);
+
+ if (! count)
+ die ("unable to query mount info");
+
+ mnt = mounts;
+
+ for (i = 0; i < count; i++) {
+ char *opts = NULL;
+
+ opts = get_mount_opts_generic_bsd (mntopt_map,
+ PROCENV_MNT_GET_FLAGS (mnt));
+ if (! opts)
+ die ("cannot determine FS flags for mountpoint '%s'",
+ mnt->f_mntonname);
+
+ if (what == SHOW_ALL || what == SHOW_MOUNTS) {
+ (void)get_major_minor (mnt->f_mntonname,
+ &major,
+ &minor);
+
+ multiplier = mnt->f_bsize / DF_BLOCK_SIZE;
+ blocks = mnt->f_blocks * multiplier;
+ bfree = mnt->f_bfree * multiplier;
+ bavail = mnt->f_bavail * multiplier;
+ used = blocks - bfree;
+
+ 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",
+ 2 * sizeof (PROCENV_MNT_GET_FSID (mnt)[0]),
+ PROCENV_MNT_GET_FSID (mnt)[0],
+ 2 * sizeof (PROCENV_MNT_GET_FSID (mnt)[1]),
+ PROCENV_MNT_GET_FSID (mnt)[1]);
+
+ entry ("optimal block size", "%" PROCENV_STATFS_INT_FMT,
+ mnt->f_bsize);
+
+ section_open ("blocks");
+
+ entry ("size", "%lu bytes", DF_BLOCK_SIZE);
+
+ entry ("total", "%" PROCENV_STATFS_INT_FMT, blocks);
+ entry ("used", "%"PROCENV_STATFS_INT_FMT, used);
+ entry ("free", "%" PROCENV_STATFS_INT_FMT, bfree);
+ entry ("available", "%" PROCENV_STATFS_INT_FMT, bavail);
+
+ section_close ();
+
+ section_open ("files/inodes");
+
+ entry ("total", "%" PROCENV_STATFS_INT_FMT, mnt->f_files);
+ entry ("used", "%" PROCENV_STATFS_INT_FMT,
+ mnt->f_files - mnt->f_ffree);
+ entry ("free", "%" PROCENV_STATFS_INT_FMT, mnt->f_ffree);
+
+ section_close ();
+
+ section_close ();
+ }
+
+ if (what == SHOW_ALL || what == SHOW_PATHCONF)
+ show_pathconfs (what, mnt->f_mntonname);
+ mnt++;
+
+ free (opts);
+ }
+}
+
+#endif /* PROCENV_PLATFORM_BSD || PROCENV_PLATFORM_MINIX || PROCENV_PLATFORM_DARWIN */
+
+#if defined (PROCENV_PLATFORM_LINUX) || defined (PROCENV_PLATFORM_HURD)
+
+#define MOUNTS "/proc/mounts"
+
+/**
+ * get_canonical:
+ *
+ * @path: path to convert to canonical form,
+ * @canonical [out]: canonical version of @path,
+ * @len: Size of @canonical (should be atleast PATH_MAX).
+ *
+ * FIXME: this should fully resolve not just sym links but replace all
+ * occurences of '../' by the appropriate direcotry!
+ **/
+int
+get_canonical_generic_linux (const char *path, char *canonical, size_t len)
+{
+ ssize_t bytes;
+ int ret = true;
+
+ assert (path);
+ assert (canonical);
+ assert (len);
+
+ bytes = readlink (path, canonical, len);
+ if (bytes < 0) {
+ sprintf (canonical, UNKNOWN_STR);
+ ret = false;
+ } else {
+ canonical[bytes <= len ? bytes : len] = '\0';
+ }
+
+ return ret;
+}
+
+void
+show_mounts_generic_linux (ShowMountType what)
+{
+ FILE *mtab;
+ struct mntent *mnt;
+ struct statvfs fs;
+ unsigned int major = 0;
+ unsigned int minor = 0;
+ int have_stats;
+ char canonical[PATH_MAX];
+
+ mtab = fopen (MOUNTS, "r");
+
+ if (! mtab)
+ return;
+
+ while ((mnt = getmntent (mtab))) {
+ have_stats = true;
+
+ if (what == SHOW_ALL || what == SHOW_MOUNTS) {
+ unsigned multiplier = 0;
+ fsblkcnt_t blocks = 0;
+ fsblkcnt_t bfree = 0;
+ fsblkcnt_t bavail = 0;
+ fsblkcnt_t used_blocks = 0;
+ fsblkcnt_t used_files = 0;
+ int ret;
+
+ if (statvfs (mnt->mnt_dir, &fs) < 0) {
+ have_stats = false;
+ } else {
+ multiplier = fs.f_bsize / DF_BLOCK_SIZE;
+
+ blocks = fs.f_blocks * multiplier;
+ bfree = fs.f_bfree * multiplier;
+ bavail = fs.f_bavail * multiplier;
+ used_blocks = blocks - bfree;
+ used_files = fs.f_files - fs.f_ffree;
+ }
+
+ (void)get_major_minor (mnt->mnt_dir,
+ &major,
+ &minor);
+
+ assert (mnt->mnt_dir);
+ section_open (mnt->mnt_dir);
+
+ entry ("filesystem", "'%s'", mnt->mnt_fsname);
+
+ ret = get_canonical_generic_linux (mnt->mnt_fsname, canonical, sizeof (canonical));
+ entry ("canonical", "%s%s%s",
+ ret ? "'" : "",
+ canonical,
+ ret ? "'" : "");
+
+ 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) {
+ union fsid_u {
+ unsigned long int fsid;
+ unsigned int val[2];
+ } fsid_val;
+
+ memset (&fsid_val, 0, sizeof (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 {
+ entry ("fsid", "%s", UNKNOWN_STR);
+ entry ("optimal block size", "%s", UNKNOWN_STR);
+
+ section_open ("blocks");
+
+ 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);
+}
+
+#endif /* PROCENV_PLATFORM_LINUX || PROCENV_PLATFORM_HURD */