AC_FUNC_REALLOC
AC_CHECK_FUNCS([getmntent gettimeofday localtime_r memset mkdir rmdir strchr strcspn strdup strndup strrchr strspn])
+AC_CHECK_TOOL(GPERF, gperf)
+if test -z "$GPERF" ; then
+ AC_MSG_ERROR([*** gperf not found])
+fi
+
# ------------------------------------------------------------------------------
PKG_CHECK_MODULES(DBUS, [dbus-1 >= 1.3.2])
PKG_CHECK_MODULES(GLIB, [glib-2.0])
BuildRequires: pkgconfig(dbus-1)
BuildRequires: pkgconfig(glib-2.0) >= 2.44
BuildRequires: pkgconfig(gio-2.0) >= 2.44
+BuildRequires: gperf
Requires: /bin/cp
libsystem/libsystem.c \
libsystem/libsystem.h \
libsystem/proc.c \
+ libsystem/proc-smaps-lookup.c \
libsystem/time-util.c
+EXTRA_DIST += \
+ libsystem/proc-smaps-lookup.gperf
+
+CLEANFILES += \
+ libsystem/proc-smaps-lookup.c
+
libsystem_la_CFLAGS = \
$(AM_CFLAGS) \
$(GLIB_CFLAGS)
%.pc: %.pc.in
$(SED_PROCESS)
+%.c: %.gperf
+ $(AM_V_at)$(MKDIR_P) $(dir $@)
+ $(AM_V_GPERF)$(GPERF) < $< > $@
+
install-exec-hook: $(INSTALL_EXEC_HOOKS)
-/libsystem.pc
\ No newline at end of file
+/libsystem.pc
+/proc-smaps-lookup.c
\ No newline at end of file
--- /dev/null
+%{
+#include <assert.h>
+#include "proc.h"
+
+struct smap_mapping {
+ const char* name;
+ enum smap_id id;
+};
+typedef struct smap_mapping smap_mapping;
+
+%}
+smap_mapping;
+%language=ANSI-C
+%define slot-name name
+%define hash-function-name smap_mapping_hash
+%define lookup-function-name smap_mapping_lookup
+%readonly-tables
+%omit-struct-type
+%struct-type
+%includes
+%%
+AnonHugePages, SMAPS_ID_ANON_HUGE_PAGES
+Anonymous, SMAPS_ID_ANONYMOUS
+KernelPageSize, SMAPS_ID_KERNEL_PAGE_SIZE
+Locked, SMAPS_ID_LOCKED
+MMUPageSize, SMAPS_ID_MMU_PAGE_SIZE
+PSwap, SMAPS_ID_PSWAP
+Private_Clean, SMAPS_ID_PRIVATE_CLEAN
+Private_Dirty, SMAPS_ID_PRIVATE_DIRTY
+Pss, SMAPS_ID_PSS
+Referenced, SMAPS_ID_REFERENCED
+Rss, SMAPS_ID_RSS
+Shared_Clean, SMAPS_ID_SHARED_CLEAN
+Shared_Dirty, SMAPS_ID_SHARED_DIRTY
+Size, SMAPS_ID_SIZE
+Swap, SMAPS_ID_SWAP
+%%
+static const char* const smaps_string_lookup[SMAPS_ID_MAX] = {
+ [SMAPS_ID_ANON_HUGE_PAGES] = "AnonHugePages",
+ [SMAPS_ID_ANONYMOUS] = "Anonymous",
+ [SMAPS_ID_KERNEL_PAGE_SIZE] = "KernelPageSize",
+ [SMAPS_ID_LOCKED] = "Locked",
+ [SMAPS_ID_MMU_PAGE_SIZE] = "MMUPageSize",
+ [SMAPS_ID_PSWAP] = "PSwap",
+ [SMAPS_ID_PRIVATE_CLEAN] = "Private_Clean",
+ [SMAPS_ID_PRIVATE_DIRTY] = "Private_Dirty",
+ [SMAPS_ID_PSS] = "Pss",
+ [SMAPS_ID_REFERENCED] = "Referenced",
+ [SMAPS_ID_RSS] = "Rss",
+ [SMAPS_ID_SHARED_CLEAN] = "Shared_Clean",
+ [SMAPS_ID_SHARED_DIRTY] = "Shared_Dirty",
+ [SMAPS_ID_SIZE] = "Size",
+ [SMAPS_ID_SWAP] = "Swap",
+};
+
+const char *smap_id_to_string(enum smap_id id) {
+
+ assert(id >= 0 && id < SMAPS_ID_MAX);
+
+ return smaps_string_lookup[id];
+}
+
+enum smap_id smap_string_to_id(const char *str) {
+ const struct smap_mapping *m;
+
+ assert(str);
+ m = smap_mapping_lookup(str,
+ strlen(str));
+ return m ? m->id : SMAPS_ID_INVALID;
+}
#include <string.h>
#include <errno.h>
#include <assert.h>
+#include <limits.h>
#include "libsystem.h"
+#include "proc.h"
ssize_t proc_cmdline_get_str(char **buf, const char *op) {
_cleanup_free_ char *cmdline = NULL;
return 0;
}
+
+static void smap_free(struct smap *map) {
+ if (!map)
+ return;
+
+ if (map->mode)
+ free(map->mode);
+
+ if (map->name)
+ free(map->name);
+
+ free(map);
+}
+
+void smaps_free(struct smaps *maps) {
+ int i;
+
+ if (!maps)
+ return;
+
+ for (i = 0; i < maps->n_map; i++)
+ smap_free(maps->maps[i]);
+
+ free(maps->maps);
+ free(maps);
+}
+
+static int add_smap_to_smaps(struct smaps *maps, struct smap *map) {
+ int i;
+
+ assert(maps);
+ assert(map);
+
+ maps->n_map++;
+
+ maps->maps = (struct smap **)realloc(
+ maps->maps,
+ sizeof(struct smap *) * maps->n_map);
+ if (!maps->maps)
+ return -ENOMEM;
+
+ maps->maps[maps->n_map - 1] = map;
+
+ for (i = 0; i < SMAPS_ID_MAX; i++)
+ maps->sum[i] += map->value[i];
+
+ return 0;
+}
+
+int proc_pid_get_smaps(pid_t pid, struct smaps **maps, enum smap_mask mask) {
+ _cleanup_free_ char *path = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ struct smaps *m = NULL;
+ char buf[LINE_MAX];
+ bool get_line = true;
+ int r;
+
+ assert(maps);
+
+ r = asprintf(&path, "/proc/%d/smaps", pid);
+ if (r < 0)
+ return -ENOMEM;
+
+ r = access(path, F_OK);
+ if (r < 0)
+ return -errno;
+
+ f = fopen(path, "re");
+ if (!f)
+ return -errno;
+
+ m = new0(struct smaps, 1);
+ if (!m)
+ return -ENOMEM;
+
+ for (;;) {
+ struct smap *map = NULL;
+ int n;
+
+ if (get_line && !fgets(buf, sizeof(buf), f)) {
+ if (ferror(f)) {
+ r = -errno;
+ goto on_error;
+ }
+ break;
+ } else
+ get_line = true;
+
+ map = new0(struct smap, 1);
+ if (!map) {
+ r = -errno;
+ goto on_error;
+ }
+
+ n = sscanf(buf, "%x-%x %ms %*s %*s %*s %ms",
+ &map->start, &map->end, &map->mode, &map->name);
+
+ if (n == 3 && !map->name)
+ map->name = strdup("[anon]");
+ else if (n != 4) {
+ free(map);
+ r = -EINVAL;
+ goto on_error;
+ }
+
+ for (;;) {
+ unsigned int v = 0;
+ enum smap_id id;
+ size_t l;
+
+ if (!fgets(buf, sizeof(buf), f)) {
+ if (ferror(f)) {
+ free(map);
+ r = -errno;
+ goto on_error;
+ }
+ break;
+ }
+
+ if ((*buf >= '0' && *buf <= '9') ||
+ (*buf >= 'a' && *buf <= 'f')) {
+ get_line = false;
+ break;
+ }
+
+ l = strcspn(buf, ":");
+ if (!l)
+ break;
+
+ buf[l] = 0;
+
+ id = smap_string_to_id(buf);
+ if (id < 0 || id >= SMAPS_ID_MAX)
+ continue;
+
+ if (!(mask & (1 << id)))
+ continue;
+
+ if (sscanf(buf + l + 1, "%d kB", &v) != 1)
+ break;
+
+ map->value[id] = v;
+ }
+
+ r = add_smap_to_smaps(m, map);
+ if (r < 0)
+ goto on_error;
+ }
+
+ *maps = m;
+
+ return 0;
+
+on_error:
+ smaps_free(m);
+ return r;
+}
/*
* libsystem
*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the License);
* you may not use this file except in compliance with the License.
#pragma once
+#include <sys/types.h>
+#include "libsystem.h"
+
#ifdef __cplusplus
extern "C" {
#endif
* -errno is returned on failure.
*/
int proc_pid_of(const char *pname);
+
+/**
+ * smaps id
+ */
+enum smap_id {
+ SMAPS_ID_INVALID = -1,
+ SMAPS_ID_ANON_HUGE_PAGES = 0,
+ SMAPS_ID_ANONYMOUS,
+ SMAPS_ID_KERNEL_PAGE_SIZE,
+ SMAPS_ID_LOCKED,
+ SMAPS_ID_MMU_PAGE_SIZE,
+ SMAPS_ID_PSWAP,
+ SMAPS_ID_PRIVATE_CLEAN,
+ SMAPS_ID_PRIVATE_DIRTY,
+ SMAPS_ID_PSS,
+ SMAPS_ID_REFERENCED,
+ SMAPS_ID_RSS,
+ SMAPS_ID_SHARED_CLEAN,
+ SMAPS_ID_SHARED_DIRTY,
+ SMAPS_ID_SIZE,
+ SMAPS_ID_SWAP,
+ SMAPS_ID_MAX,
+};
+
+/**
+ * smaps mask
+ */
+enum smap_mask {
+ SMAPS_MASK_ANON_HUGE_PAGES = 1 << SMAPS_ID_ANON_HUGE_PAGES,
+ SMAPS_MASK_ANONYMOUS = 1 << SMAPS_ID_ANONYMOUS,
+ SMAPS_MASK_KERNEL_PAGE_SIZE = 1 << SMAPS_ID_KERNEL_PAGE_SIZE,
+ SMAPS_MASK_LOCKED = 1 << SMAPS_ID_LOCKED,
+ SMAPS_MASK_MMU_PAGE_SIZE = 1 << SMAPS_ID_MMU_PAGE_SIZE,
+ SMAPS_MASK_PSWAP = 1 << SMAPS_ID_PSWAP,
+ SMAPS_MASK_PRIVATE_CLEAN = 1 << SMAPS_ID_PRIVATE_CLEAN,
+ SMAPS_MASK_PRIVATE_DIRTY = 1 << SMAPS_ID_PRIVATE_DIRTY,
+ SMAPS_MASK_PSS = 1 << SMAPS_ID_PSS,
+ SMAPS_MASK_REFERENCED = 1 << SMAPS_ID_REFERENCED,
+ SMAPS_MASK_RSS = 1 << SMAPS_ID_RSS,
+ SMAPS_MASK_SHARED_CLEAN = 1 << SMAPS_ID_SHARED_CLEAN,
+ SMAPS_MASK_SHARED_DIRTY = 1 << SMAPS_ID_SHARED_DIRTY,
+ SMAPS_MASK_SIZE = 1 << SMAPS_ID_SIZE,
+ SMAPS_MASK_SWAP = 1 << SMAPS_ID_SWAP,
+ SMAPS_MASK_ALL = (1 << SMAPS_ID_MAX) - 1,
+ SMAPS_MASK_DEFAULT = (SMAPS_MASK_SIZE |
+ SMAPS_MASK_RSS |
+ SMAPS_MASK_PSS |
+ SMAPS_MASK_SHARED_CLEAN |
+ SMAPS_MASK_SHARED_DIRTY |
+ SMAPS_MASK_PRIVATE_CLEAN |
+ SMAPS_MASK_PRIVATE_DIRTY |
+ SMAPS_MASK_SWAP |
+ SMAPS_MASK_PSWAP),
+};
+
+/**
+ * a smap info
+ */
+struct smap {
+ /**
+ * start address
+ */
+ unsigned int start;
+ /**
+ * end address
+ */
+ unsigned int end;
+ /**
+ * smaps mode
+ */
+ char *mode;
+ /**
+ * smaps name
+ */
+ char *name;
+ /**
+ * value of each
+ */
+ unsigned int value[SMAPS_ID_MAX];
+};
+
+/**
+ * a smaps info of pid
+ */
+struct smaps {
+ /**
+ * sum value of each
+ */
+ unsigned int sum[SMAPS_ID_MAX];
+ /**
+ * number of maps
+ */
+ int n_map;
+ /**
+ * maps
+ */
+ struct smap **maps;
+};
+
+/**
+ * @brief Destroy struct smaps
+ *
+ * @param maps a smaps
+ */
+void smaps_free(struct smaps *maps);
+
+static inline void smaps_freep(struct smaps **maps)
+{
+ if (*maps)
+ smaps_free(*maps);
+}
+
+/**
+ * Declare struct smaps with cleanup attribute. Allocated struct smaps
+ * is destroyed on going out the scope.
+ */
+#define _cleanup_smaps_free_ _cleanup_ (smaps_freep)
+
+/**
+ * @brief Convert smap id to string
+ *
+ * @param id smap id
+ *
+ * @return converted string
+ */
+const char *smap_id_to_string(enum smap_id id);
+
+/**
+ * @brief Convert smap string to id
+ *
+ * @param str smap string
+ *
+ * @return converted id
+ */
+enum smap_id smap_string_to_id(const char *str);
+
+/**
+ * @brief Get smaps info of pid
+ *
+ * @param pid a pid to get
+ * @param maps parsed smaps struct. This value has to be destoryed by
+ * caller. #_cleanup_smaps_free_ is useful to make allocated struct to
+ * autofree.
+ * @code{.c}
+ {
+ _cleanup_smaps_free_ struct smaps *maps;
+
+ proc_pid_get_smaps(pid, &maps, SMAPS_MASK_ALL);
+ }
+ * @endcode
+ * @param mask mask to parse smaps.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int proc_pid_get_smaps(pid_t pid, struct smaps **maps, enum smap_mask mask);
+
/**
* @}
*/