summaryrefslogtreecommitdiff
path: root/src/libsystem
diff options
context:
space:
mode:
authortaeyoung <ty317.kim@samsung.com>2017-01-16 11:39:48 +0900
committertaeyoung <ty317.kim@samsung.com>2017-01-16 11:42:13 +0900
commitda01b82cc005cd39fcb64ab4316a290605ec40df (patch)
tree6414f82b8dc6ea9b3ff95cc90db7903b8358174e /src/libsystem
parentecd23209f31cb87e989e32a414ccd9586e21c332 (diff)
parentf2bbea8b404d188528cbfcef0b40e7b7d9017f58 (diff)
downloadlibsystem-da01b82cc005cd39fcb64ab4316a290605ec40df.tar.gz
libsystem-da01b82cc005cd39fcb64ab4316a290605ec40df.tar.bz2
libsystem-da01b82cc005cd39fcb64ab4316a290605ec40df.zip
Merge branch 'master' into tizen
Change-Id: Ie83044d82e9772c3ec094a5d162cacffe4d7b9a1 Signed-off-by: taeyoung <ty317.kim@samsung.com>
Diffstat (limited to 'src/libsystem')
-rw-r--r--src/libsystem/.gitignore3
-rw-r--r--src/libsystem/config-parser.c373
-rw-r--r--src/libsystem/config-parser.h192
-rw-r--r--src/libsystem/dbus-util.h63
-rw-r--r--src/libsystem/exec.c125
-rw-r--r--src/libsystem/glib-util.c56
-rw-r--r--src/libsystem/glib-util.h94
-rw-r--r--src/libsystem/libsystem.c1116
-rw-r--r--src/libsystem/libsystem.h1428
-rw-r--r--src/libsystem/libsystem.pc.in17
-rw-r--r--src/libsystem/proc-meminfo-lookup.gperf67
-rw-r--r--src/libsystem/proc-smaps-lookup.gperf70
-rw-r--r--src/libsystem/proc.c416
-rw-r--r--src/libsystem/proc.h437
-rw-r--r--src/libsystem/time-util.c87
15 files changed, 4544 insertions, 0 deletions
diff --git a/src/libsystem/.gitignore b/src/libsystem/.gitignore
new file mode 100644
index 0000000..154d18c
--- /dev/null
+++ b/src/libsystem/.gitignore
@@ -0,0 +1,3 @@
+/libsystem.pc
+/proc-meminfo-lookup.c
+/proc-smaps-lookup.c \ No newline at end of file
diff --git a/src/libsystem/config-parser.c b/src/libsystem/config-parser.c
new file mode 100644
index 0000000..2799f0a
--- /dev/null
+++ b/src/libsystem/config-parser.c
@@ -0,0 +1,373 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * libsystem
+ *
+ * Copyright (c) 2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdbool.h>
+#include <limits.h>
+
+#include "libsystem.h"
+#include "config-parser.h"
+
+#define MAX_SECTION 64
+
+static int config_table_lookup(
+ void *table,
+ const char *section,
+ const char *lvalue,
+ ConfigParserCallback *func,
+ int *ltype,
+ void **data) {
+
+ ConfigTableItem *t;
+
+ assert(table);
+ assert(lvalue);
+ assert(func);
+ assert(ltype);
+ assert(data);
+
+ for (t = table; t->lvalue; t++) {
+
+ if (!streq(lvalue, t->lvalue))
+ continue;
+
+ if (!streq_ptr(section, t->section))
+ continue;
+
+ *func = t->cb;
+ *ltype = t->ltype;
+ *data = t->data;
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Run the user supplied parser for an assignment */
+static int config_parse_table(
+ const char *filename,
+ unsigned line,
+ void *table,
+ const char *section,
+ const char *lvalue,
+ const char *rvalue) {
+
+ ConfigParserCallback cb = NULL;
+ int ltype = 0;
+ void *data = NULL;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+
+ r = config_table_lookup(table,
+ section,
+ lvalue,
+ &cb,
+ &ltype,
+ &data);
+ if (r <= 0)
+ return r;
+
+ if (cb)
+ return cb(filename,
+ line,
+ section,
+ lvalue,
+ ltype,
+ rvalue,
+ data);
+
+ return 0;
+}
+
+int config_parse(const char *filename, void *table) {
+
+ _cleanup_fclose_ FILE *f = NULL;
+ char *sections[MAX_SECTION] = { 0 };
+ char *section = NULL, *n, *e, l[LINE_MAX];
+ size_t len;
+ int i, r, num_section = 0;
+ bool already;
+ unsigned line = 0;
+
+ assert(filename);
+
+ f = fopen(filename, "r");
+ if (!f)
+ return -errno;
+
+ while (!feof(f)) {
+ _cleanup_free_ char *lvalue = NULL, *rvalue = NULL;
+
+ if (fgets(l, LINE_MAX, f) == NULL) {
+ if (feof(f))
+ break;
+
+ r = -errno;
+ goto finish;
+ }
+
+ line++;
+ truncate_nl(l);
+
+ if (strchr(COMMENTS NEWLINE, *l))
+ continue;
+
+ if (*l == '[') {
+ len = strlen(l);
+ if (l[len - 1] != ']') {
+ r = -EBADMSG;
+ goto finish;
+ }
+
+ n = strndup(l + 1, len - 2);
+ if (!n) {
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ already = false;
+ for (i = 0; i < num_section; i++) {
+ if (streq(n, sections[i])) {
+ section = sections[i];
+ already = true;
+ free(n);
+ break;
+ }
+ }
+
+ if (already)
+ continue;
+
+ section = n;
+ sections[num_section] = n;
+ num_section++;
+ if (num_section > MAX_SECTION) {
+ r = -EOVERFLOW;
+ goto finish;
+ }
+
+ continue;
+ }
+
+ if (!section)
+ continue;
+
+ e = strchr(l, '=');
+ if (e == NULL)
+ continue;
+
+ r = strndup_strip(l, e - l, &lvalue);
+ if (r < 0)
+ goto finish;
+
+ r = strdup_strip(e + 1, &rvalue);
+ if (r < 0)
+ goto finish;
+
+ r = config_parse_table(filename,
+ line,
+ table,
+ section,
+ lvalue,
+ rvalue);
+ if (r < 0)
+ goto finish;
+ }
+
+ r = 0;
+
+finish:
+ for (i = 0; i < num_section; i++)
+ if (sections[i])
+ free(sections[i]);
+
+ return r;
+}
+
+int config_parse_dir(const char *dir, ConfigParseFunc fp, void *data) {
+ _cleanup_closedir_ DIR *d = NULL;
+ struct dirent *de;
+
+ d = opendir(dir);
+ if (!d)
+ return errno;
+
+ FOREACH_DIRENT(de, d, return -errno) {
+ _cleanup_free_ char *path = NULL;
+ int r;
+
+ if (de->d_type != DT_REG)
+ continue;
+
+ r = asprintf(&path, "%s/%s", dir, de->d_name);
+ if (r < 0)
+ return -ENOMEM;
+
+ /* Do not just break loop until parse all file of
+ * dir. ignore return */
+ (void) fp(path, data);
+ }
+
+ return 0;
+}
+
+int config_parse_int(
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data) {
+
+ int *i = data;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (!is_number(rvalue, strlen(rvalue)))
+ return -EINVAL;
+
+ *i = atoi(rvalue);
+
+ return 0;
+}
+
+int config_parse_bool(
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data) {
+
+ int k;
+ bool *b = data;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ k = parse_boolean(rvalue);
+ if (k < 0)
+ return 0;
+
+ *b = !!k;
+ return 0;
+}
+
+int config_parse_string(
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data) {
+
+ char **s = data, *n;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue))
+ n = NULL;
+ else {
+ n = strdup(rvalue);
+ if (!n)
+ return -ENOMEM;
+ }
+
+ free(*s);
+ *s = n;
+
+ return 0;
+}
+
+int config_parse_bytes(
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data) {
+
+ size_t *ss = data, s = 0;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue))
+ s = 0;
+ else {
+ r = parse_bytes(rvalue, &s);
+ if (r < 0)
+ return r;
+ }
+
+ *ss = s;
+
+ return 0;
+}
+
+int config_parse_percent(
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data) {
+
+ size_t *percent = data, p = 0;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (!isempty(rvalue)) {
+ r = parse_percent(rvalue, &p);
+ if (r < 0)
+ return r;
+ }
+
+ *percent = p;
+
+ return 0;
+}
diff --git a/src/libsystem/config-parser.h b/src/libsystem/config-parser.h
new file mode 100644
index 0000000..1909fe8
--- /dev/null
+++ b/src/libsystem/config-parser.h
@@ -0,0 +1,192 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * libsystem
+ *
+ * Copyright (c) 2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file config-parser.h
+ *
+ * ini type config file parser
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#pragma once
+
+#include <stdio.h>
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Prototype for a parser for a specific configuration setting
+ */
+typedef int (*ConfigParserCallback)(
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data);
+
+/**
+ * @brief A callback function of #config_parse_dir.
+ *
+ * @param path a parsing config file name
+ * @param data user data to be passed by #config_parse_dir.
+ */
+typedef int (*ConfigParseFunc)(const char *path, void *data);
+
+/**
+ * Wraps information for parsing a specific configuration variable, to
+ * be stored in a simple array
+ */
+typedef struct ConfigTableItem {
+ /**
+ * Section
+ */
+ const char *section;
+
+ /**
+ * Name of the variable
+ */
+ const char *lvalue;
+
+ /**
+ * Function that is called to parse the variable's value
+ */
+ ConfigParserCallback cb;
+
+ /**
+ * Distinguish different variables passed to the same callback
+ */
+ int ltype;
+
+ /**
+ * Where to store the variable's data
+ */
+ void *data;
+} ConfigTableItem;
+
+/**
+ * @brief config parser function
+ *
+ * @param filename full path of config file
+ * @param table a table of #ConfigTableItem to parse
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int config_parse(const char *filename, void *table);
+
+/**
+ * @brief parse all regular config files in directory
+ *
+ * @param dir dir full path
+ * @param fp config parse function.
+ * @param data user data to be passed to config parser function
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int config_parse_dir(const char *dir, ConfigParseFunc fp, void *data);
+
+
+/**
+ * @brief A common int type rvalue parser.
+ *
+ * @param filename a parsing config file name
+ * @param line a parsing config file line
+ * @param section a parsing config file section
+ * @param lvalue a parsing config file left value
+ * @param ltype a parsing config file left value type. (not used.)
+ * @param rvalue a parsing config file rvalue
+ * @param data user data
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int config_parse_int(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data);
+
+/**
+ * @brief A common boolean type rvalue parser.
+ *
+ * @param filename a parsing config file name
+ * @param line a parsing config file line
+ * @param section a parsing config file section
+ * @param lvalue a parsing config file left value
+ * @param ltype a parsing config file left value type. (not used.)
+ * @param rvalue a parsing config file rvalue
+ * @param data user data
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int config_parse_bool(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data);
+
+/**
+ * @brief A common string type rvalue parser.
+ *
+ * @param filename a parsing config file name
+ * @param line a parsing config file line
+ * @param section a parsing config file section
+ * @param lvalue a parsing config file left value
+ * @param ltype a parsing config file left value type. (not used.)
+ * @param rvalue a parsing config file rvalue
+ * @param data user data
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int config_parse_string(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data);
+
+/**
+ * @brief A common byte type rvalue parser.
+ *
+ * @param filename a parsing config file name
+ * @param line a parsing config file line
+ * @param section a parsing config file section
+ * @param lvalue a parsing config file left value
+ * @param ltype a parsing config file left value type. (not used.)
+ * @param rvalue a parsing config file rvalue
+ * @param data user data
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int config_parse_bytes(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data);
+
+/**
+ * @brief A common percent(%) type rvalue parser. The right value has
+ * to be end with '%'.
+ *
+ * @param filename a parsing config file name
+ * @param line a parsing config file line
+ * @param section a parsing config file section
+ * @param lvalue a parsing config file left value
+ * @param ltype a parsing config file left value type. (not used.)
+ * @param rvalue a parsing config file rvalue
+ * @param data user data
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int config_parse_percent(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/libsystem/dbus-util.h b/src/libsystem/dbus-util.h
new file mode 100644
index 0000000..6f2a953
--- /dev/null
+++ b/src/libsystem/dbus-util.h
@@ -0,0 +1,63 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * libsystem
+ *
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file dbus-util.h
+ *
+ * dbus utility library
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#pragma once
+
+#include <dbus/dbus.h>
+#include "libsystem.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline void __dbus_error_free(DBusError *error) {
+ if (error && dbus_error_is_set(error))
+ dbus_error_free(error);
+}
+
+static inline void __dbus_message_unref(DBusMessage **message) {
+ if (*message)
+ dbus_message_unref(*message);
+}
+
+/**
+ * Declare value with cleanup attribute. dbus_error_free() is called
+ * when is going out the scope.
+ */
+#define _cleanup_dbus_error_free_ _cleanup_(__dbus_error_free)
+
+/**
+ * Declare value with cleanup attribute. dbus_message_unref() is
+ * called when is going out the scope.
+ */
+#define _cleanup_dbus_message_unref_ _cleanup_(__dbus_message_unref)
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/libsystem/exec.c b/src/libsystem/exec.c
new file mode 100644
index 0000000..5fb49f4
--- /dev/null
+++ b/src/libsystem/exec.c
@@ -0,0 +1,125 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * libsystem
+ *
+ * Copyright (c) 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+#include "libsystem.h"
+
+static int wait_child(pid_t pid, int64_t timeout_msec, int sig) {
+ struct timeval start, timeout;
+ int status;
+
+ if (timeout_msec < 0)
+ return 0;
+
+ if (timeout_msec > 0) {
+ msec_to_timeval((uint64_t) timeout_msec, &timeout);
+
+ if (gettimeofday(&start, NULL) < 0)
+ return -errno;
+ }
+
+ for (;;) {
+ struct timeval current, delta;
+ pid_t p;
+
+ p = waitpid(pid, &status, WNOHANG);
+ if (p == pid)
+ break;
+
+ if (timeout_msec == 0)
+ continue;
+
+ if (gettimeofday(&current, NULL) < 0)
+ return -errno;
+
+ timersub(&current, &start, &delta);
+
+ if (timercmp(&timeout, &delta, <)) {
+ (void) kill(pid, sig);
+ return -ETIME;
+ }
+
+ usleep(100000);
+ }
+
+ return WEXITSTATUS(status);
+}
+
+int do_fork_exec_kill_redirect(char *const argv[], char * const envp[], int64_t timeout_msec, int sig, int fd, int flags) {
+ pid_t pid;
+
+ assert(argv);
+
+ pid = fork();
+ if (pid < 0)
+ return -errno;
+ else if (pid == 0) {
+
+ if (fd >= 0) {
+ if (flags & EXEC_REDIRECT_OUTPUT)
+ dup2(fd, STDOUT_FILENO);
+
+ if (flags & EXEC_REDIRECT_ERROR)
+ dup2(fd, STDERR_FILENO);
+ }
+
+ if (!envp)
+ execv(*argv, argv);
+ else
+ execvpe(*argv, argv, envp);
+
+ _exit(EXIT_FAILURE);
+ }
+
+ return wait_child(pid, timeout_msec, sig);
+}
+
+int do_fork_exec_redirect(char *const argv[], char * const envp[], int64_t timeout_msec, int fd, int flags) {
+
+ assert(argv);
+
+ return do_fork_exec_kill_redirect(argv, envp, timeout_msec, SIGTERM, fd, flags);
+}
+
+int do_fork_exec_kill(char *const argv[], char * const envp[], int64_t timeout_msec, int sig) {
+
+ assert(argv);
+
+ return do_fork_exec_kill_redirect(argv, envp, timeout_msec, sig, -1, EXEC_REDIRECT_NONE);
+}
+
+int do_fork_exec(char *const argv[], char * const envp[], int64_t timeout_msec) {
+
+ assert(argv);
+
+ return do_fork_exec_kill(argv, envp, timeout_msec, SIGTERM);
+}
diff --git a/src/libsystem/glib-util.c b/src/libsystem/glib-util.c
new file mode 100644
index 0000000..5866b4c
--- /dev/null
+++ b/src/libsystem/glib-util.c
@@ -0,0 +1,56 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * libsystem
+ *
+ * Copyright (c) 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <assert.h>
+#include <glib.h>
+
+static const int gerror_code_table[] = {
+ [G_FILE_ERROR_EXIST] = EEXIST,
+ [G_FILE_ERROR_ISDIR] = EISDIR,
+ [G_FILE_ERROR_ACCES] = EACCES,
+ [G_FILE_ERROR_NAMETOOLONG] = ENAMETOOLONG,
+ [G_FILE_ERROR_NOENT] = ENOENT,
+ [G_FILE_ERROR_NOTDIR] = ENOTDIR,
+ [G_FILE_ERROR_NXIO] = ENXIO,
+ [G_FILE_ERROR_NODEV] = ENODEV,
+ [G_FILE_ERROR_ROFS] = EROFS,
+ [G_FILE_ERROR_TXTBSY] = ETXTBSY,
+ [G_FILE_ERROR_FAULT] = EFAULT,
+ [G_FILE_ERROR_LOOP] = ELOOP,
+ [G_FILE_ERROR_NOSPC] = ENOSPC,
+ [G_FILE_ERROR_NOMEM] = ENOMEM,
+ [G_FILE_ERROR_MFILE] = EMFILE,
+ [G_FILE_ERROR_NFILE] = ENFILE,
+ [G_FILE_ERROR_BADF] = EBADF,
+ [G_FILE_ERROR_INVAL] = EINVAL,
+ [G_FILE_ERROR_PIPE] = EPIPE,
+ [G_FILE_ERROR_AGAIN] = EAGAIN,
+ [G_FILE_ERROR_INTR] = EINTR,
+ [G_FILE_ERROR_IO] = EIO,
+ [G_FILE_ERROR_PERM] = EPERM,
+ [G_FILE_ERROR_NOSYS] = ENOSYS,
+};
+
+int gerror_to_errno(GError *error) {
+ assert(error);
+
+ return gerror_code_table[error->code];
+}
diff --git a/src/libsystem/glib-util.h b/src/libsystem/glib-util.h
new file mode 100644
index 0000000..560acc4
--- /dev/null
+++ b/src/libsystem/glib-util.h
@@ -0,0 +1,94 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * libsystem
+ *
+ * Copyright (c) 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file glib-util.h
+ *
+ * GLib utility library
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#pragma once
+
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Iterate for each list nodes.
+ *
+ * @param c current node
+ * @param l list to iterate
+ */
+#define FOREACH_G_LIST(c, l) \
+ for (c = g_list_first(l); c; c = g_list_next(c))
+
+/**
+ * @brief Reverse iterate for each list nodes.
+ *
+ * @param c current node
+ * @param l list to iterate
+ */
+#define FOREACH_G_LIST_REVERSE(c, l) \
+ for (c = g_list_last(l); c; c = g_list_previous(c))
+
+/**
+ * @brief Iterate for each list nodes. #FOREACH_G_LIST_SAFE is similar
+ * with #FOREACH_G_LIST but safe for list remove. When you are
+ * iterating a list to remove some of list nodes, you have to use
+ * #FOREACH_G_LIST_SAFE for safe iteration.
+ *
+ * @param c current node
+ * @param n next node of current iteration, this is used for safe iteration
+ * @param l list to iterate
+ */
+#define FOREACH_G_LIST_SAFE(c, n, l) \
+ for (c = g_list_first(l), n = g_list_next(c); c; c = n, n = g_list_next(c))
+
+/**
+ * @brief Reverse iterate for each list
+ * nodes. #FOREACH_G_LIST_SAFE_REVERSE is similar with
+ * #FOREACH_G_LIST_REVERSE but safe for list remove. When you are
+ * iterating a list to remove some of list nodes, you have to use
+ * #FOREACH_G_LIST_SAFE_REVERSE for safe iteration.
+ *
+ * @param c current node
+ * @param p previous node of current iteration, this is used for safe iteration
+ * @param l list to iterate
+ */
+#define FOREACH_G_LIST_SAFE_REVERSE(c, p, l) \
+ for (c = g_list_last(l), p = g_list_previous(c); c; c = p, p = g_list_previous(c))
+
+/**
+ * @brief Convert GError to errno.
+ *
+ * @param error GError to convert
+ *
+ * @return converted errno.
+ */
+int gerror_to_errno(GError *error);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/libsystem/libsystem.c b/src/libsystem/libsystem.c
new file mode 100644
index 0000000..c8b7c58
--- /dev/null
+++ b/src/libsystem/libsystem.c
@@ -0,0 +1,1116 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * libsystem
+ *
+ * Copyright (c) 2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stddef.h>
+#include <assert.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#include <ctype.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <mntent.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#include "libsystem.h"
+
+static int _errno_old;
+
+#define STORE_RESET_ERRNO do { \
+ _errno_old = errno; \
+ errno = 0; \
+} while (0)
+
+#define RESTORE_ERRNO do { \
+ errno = _errno_old; \
+ _errno_old = 0; \
+} while (0)
+
+bool streq_ptr(const char *a, const char *b) {
+
+ /* Like streq(), but tries to make sense of NULL pointers */
+
+ if (a && b)
+ return streq(a, b);
+
+ if (!a && !b)
+ return true;
+
+ return false;
+}
+
+char *truncate_nl(char *s) {
+ assert(s);
+
+ s[strcspn(s, NEWLINE)] = 0;
+
+ return s;
+}
+
+char *strnappend(const char *s, const char *suffix, size_t b) {
+ size_t a;
+ char *r;
+
+ if (!s && !suffix)
+ return strdup("");
+
+ if (!s)
+ return strndup(suffix, b);
+
+ if (!suffix)
+ return strdup(s);
+
+ assert(s);
+ assert(suffix);
+
+ a = strlen(s);
+ if (b > ((size_t) - 1) - a)
+ return NULL;
+
+ r = new(char, a + b + 1);
+ if (!r)
+ return NULL;
+
+ memcpy(r, s, a);
+ memcpy(r + a, suffix, b);
+ r[a + b] = 0;
+
+ return r;
+}
+
+char *strappend(const char *s, const char *suffix) {
+ return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
+}
+
+char *strstrip(char *s) {
+ char *e;
+
+ /* Drops trailing whitespace. Modifies the string in
+ * place. Returns pointer to first non-space character */
+
+ s += strspn(s, WHITESPACE);
+
+ for (e = strchr(s, 0); e > s; e--)
+ if (!strchr(WHITESPACE, e[-1]))
+ break;
+
+ *e = 0;
+
+ return s;
+}
+
+int strdup_strip(const char *str, char **ret) {
+ char *r = NULL;
+ size_t s, l;
+
+ assert(str);
+ assert(ret);
+
+ s = strspn(str, WHITESPACE);
+
+ for (l = strlen(str + s); l > 0; l--)
+ if (!strchr(WHITESPACE, str[s + l - 1]))
+ break;
+
+ r = strndup(str + s, l);
+ if (!r)
+ return -ENOMEM;
+
+ *ret = r;
+
+ return 0;
+}
+
+int strndup_strip(const char *str, size_t len, char **ret) {
+ char *r = NULL;
+ size_t s, l;
+
+ assert(str);
+ assert(ret);
+
+ s = strspn(str, WHITESPACE);
+
+ l = strlen(str + s);
+ if (len > s)
+ l = l < len - s ? l : len - s;
+ else
+ return -EFAULT;
+
+ for (; l > 0; l--)
+ if (!strchr(WHITESPACE, str[s + l - 1]))
+ break;
+
+ r = strndup(str + s, l);
+ if (!r)
+ return -ENOMEM;
+
+ *ret = r;
+
+ return 0;
+}
+
+bool nulstr_contains(const char *nulstr, const char *needle) {
+ const char *i;
+
+ if (!nulstr)
+ return false;
+
+ NULSTR_FOREACH(i, nulstr)
+ if (streq(i, needle))
+ return true;
+
+ return false;
+}
+
+bool path_is_absolute(const char *p) {
+
+ assert(p);
+
+ return p[0] == '/';
+}
+
+char *path_kill_slashes(char *path) {
+ char *f, *t;
+ bool slash = false;
+
+ /* Removes redundant inner and trailing slashes. Modifies the
+ * passed string in-place.
+ *
+ * ///foo///bar/ becomes /foo/bar
+ */
+
+ for (f = path, t = path; *f; f++) {
+
+ if (*f == '/') {
+ slash = true;
+ continue;
+ }
+
+ if (slash) {
+ slash = false;
+ *(t++) = '/';
+ }
+
+ *(t++) = *f;
+ }
+
+ /* Special rule, if we are talking of the root directory, a
+ trailing slash is good */
+
+ if (t == path && slash)
+ *(t++) = '/';
+
+ *t = 0;
+ return path;
+}
+
+char *endswith(const char *s, const char *postfix) {
+ size_t sl, pl;
+
+ assert(s);
+ assert(postfix);
+
+ sl = strlen(s);
+ pl = strlen(postfix);
+
+ if (pl == 0)
+ return (char *) s + sl;
+
+ if (sl < pl)
+ return NULL;
+
+ if (memcmp(s + sl - pl, postfix, pl) != 0)
+ return NULL;
+
+ return (char *) s + sl - pl;
+}
+
+int parse_boolean(const char *v) {
+ assert(v);
+
+ if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || strcaseeq(v, "on"))
+ return 1;
+ else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || strcaseeq(v, "off"))
+ return 0;
+
+ return -EINVAL;
+}
+
+int parse_bytes(const char *b, size_t *s) {
+ _cleanup_free_ char *num = NULL;
+ size_t len, num_l, unit_l;
+
+ assert(b);
+
+ len = strlen(b);
+
+ if (!len)
+ return 0;
+
+ num_l = strspn(b, "0123456789");
+ if (num_l < len - 1)
+ return -EINVAL;
+
+ unit_l = strcspn(b, "BKMG");
+ if (num_l != unit_l)
+ return -EINVAL;
+
+ num = strndup(b, num_l);
+ if (!num)
+ return -ENOMEM;
+
+ switch (b[len - 1]) {
+ case 'G':
+ *s = atoi(num) << 30;
+ break;
+ case 'M':
+ *s = atoi(num) << 20;
+ break;
+ case 'K':
+ *s = atoi(num) << 10;
+ break;
+ case 'B':
+ default:
+ *s = atoi(num);
+ break;
+ }
+
+ return 0;
+}
+
+int parse_percent(const char *string, size_t *percent) {
+ _cleanup_free_ char *num = NULL;
+ size_t len, num_len, per;
+
+ assert(string);
+ assert(percent);
+
+ len = strlen(string);
+ if (!len)
+ return 0;
+
+ if (string[len - 1] != '%')
+ return -EINVAL;
+
+ num_len = strspn(string, "0123456789");
+ if (num_len < len - 1)
+ return -EINVAL;
+
+ num = strndup(string, num_len);
+ if (!num)
+ return -ENOMEM;
+
+ per = atoi(num);
+ if (per > 100)
+ return -EINVAL;
+
+ *percent = per;
+
+ return 0;
+}
+
+static bool __quote_complete(char *str, size_t l, char q) {
+ char *s, *s2;
+
+ assert(str);
+
+ if (!l)
+ return true;
+
+ s = strchr(str, q);
+ if (!s || (s - str) > l)
+ return true;
+
+ s = strchr(s + 1, q);
+ if (!s || (s - str) > l)
+ return false;
+
+ s2 = strchr(s + 1, q);
+ if (!s2 || (s2 - str) > l)
+ return true;
+
+ return __quote_complete(s + 1, l - (s + 1 - str), q);
+}
+
+static bool quote_complete(char *str, size_t l) {
+ char quotes[] = QUOTES;
+ int i;
+
+ assert(str);
+
+ if (!l)
+ return true;
+
+ for (i = 0; quotes[i]; i++) {
+ if (!__quote_complete(str, l, quotes[i]))
+ return false;
+ }
+
+ return true;
+}
+
+char *split(const char *c, size_t *l, const char *separator, char **state) {
+ bool separator_include_quotes;
+ char *current;
+ size_t s;
+
+ assert(c);
+ assert(l);
+ assert(separator);
+ assert(state);
+
+ current = *state ? *state : (char *) c;
+ if (!*current || *c == 0)
+ return NULL;
+
+ *l = 0;
+ separator_include_quotes = !!strspn(separator, QUOTES);
+ current += strspn(current, separator);
+
+ while ((s = strcspn(current + *l, separator))) {
+ *l += s;
+ if (separator_include_quotes ||
+ quote_complete(current, *l))
+ break;
+ (*l)++;
+ }
+
+ *state = current + *l;
+
+ return (char *) current;
+}
+
+bool is_number(const char *s, int l) {
+ int i;
+
+ for (i = 0; i < l; i++)
+ if (!isdigit(s[i]))
+ return false;
+
+ return true;
+}
+
+static int do_copy_internal(const char *src, const char *dst, mode_t mode, bool force) {
+ _cleanup_close_ int rfd = -1, wfd = -1;
+ char buf[1024];
+ ssize_t red;
+ int r;
+
+ assert(src);
+ assert(dst);
+
+ if (!force) {
+ r = access(dst, F_OK);
+ if (r == 0)
+ return -EALREADY;
+ else if (errno != ENOENT)
+ return -errno;
+ }
+
+ wfd = open(dst, O_CREAT | O_WRONLY | O_TRUNC, mode);
+ if (wfd < 0)
+ return -errno;
+
+ rfd = open(src, O_RDONLY);
+ if (rfd < 0)
+ return -errno;
+
+ while ((red = read(rfd, buf, 1024)) > 0)
+ if (write(wfd, buf, red) != red)
+ return -errno;
+
+ if (red < 0)
+ return -errno;
+
+ return 0;
+}
+
+int do_copy_mode(const char *src, const char *dst, mode_t mode) {
+
+ assert(src);
+ assert(dst);
+
+ return do_copy_internal(src, dst, mode, false);
+}
+
+int do_copy_mode_force(const char *src, const char *dst, mode_t mode) {
+
+ assert(src);
+ assert(dst);
+
+ return do_copy_internal(src, dst, mode, true);
+}
+
+int do_copy(const char *src, const char *dst) {
+
+ assert(src);
+ assert(dst);
+
+ return do_copy_internal(src, dst, 0644, false);
+}
+
+int do_copy_force(const char *src, const char *dst) {
+
+ assert(src);
+ assert(dst);
+
+ return do_copy_internal(src, dst, 0644, true);
+}
+
+int do_mkdir(const char *path, mode_t mode) {
+ char d[PATH_MAX];
+ size_t s, l;
+ int r, p;
+
+ assert(path);
+
+ l = strlen(path);
+
+ for (p = 0, s = 0; p < l; p += s + 1) {
+ s = strcspn(path + p, "/");
+ if (!s)
+ continue;
+
+ assert(PATH_MAX > p + s + 1);
+
+ r = snprintf(d, p + s + 1, "%s", path);
+ if (r < 0)
+ return r;
+
+ r = mkdir(d, mode);
+ if (r < 0 && errno != EEXIST)
+ return -errno;
+ }
+
+ return 0;
+}
+
+int rmdir_recursive(const char *path) {
+ _cleanup_closedir_ DIR *d = NULL;
+ struct dirent *de;
+ int r;
+
+ assert(path);
+
+ d = opendir(path);
+ if (!d)
+ return -errno;
+
+ FOREACH_DIRENT(de, d, return -errno) {
+ _cleanup_free_ char *p = NULL;
+
+ r = asprintf(&p, "%s/%s", path, de->d_name);
+ if (r < 0)
+ return -ENOMEM;
+
+ if (de->d_type == DT_DIR) {
+ r = rmdir_recursive(p);
+ if (r < 0)
+ return r;
+ } else {
+ r = unlink(p);
+ if (r < 0)
+ return r;
+ }
+ }
+
+ return rmdir(path);
+}
+
+char *strdup_unquote(const char *str, const char *quotes) {
+ size_t l;
+
+ assert(str);
+
+ l = strlen(str);
+ if (l < 2)
+ return strdup(str);
+
+ if (strchr(quotes, str[0]) && str[0] == str[l - 1])
+ return strndup(str + 1, l - 2);
+
+ return strdup(str);
+}
+
+int write_str_to_file(FILE *f, const char *str, enum file_write_flags flags) {
+ int r = 0;
+
+ assert(f);
+ assert(str);
+
+ STORE_RESET_ERRNO;
+
+ (void) fputs(str, f);
+ if ((flags & FILE_WRITE_NEWLINE_IF_NOT) && !endswith(str, "\n"))
+ (void) fputc('\n', f);
+
+ if (flags & FILE_WRITE_WITH_FFLUSH)
+ (void) fflush(f);
+
+ if (ferror(f))
+ r = errno ? -errno : -EIO;
+
+ RESTORE_ERRNO;
+
+ return r;
+}
+
+int write_str_to_path(const char *path, const char *str, enum file_write_flags flags) {
+ _cleanup_fclose_ FILE *f = NULL;
+
+ assert(path);
+ assert(str);
+
+ if (flags & FILE_WRITE_APPEND)
+ f = fopen(path, "ae");
+ else
+ f = fopen(path, "we");
+ if (!f)
+ return -errno;
+
+ return write_str_to_file(f, str, flags);
+}
+
+int read_one_line_from_file(FILE *f, char **line) {
+ char t[LINE_MAX], *c;
+
+ assert(f);
+ assert(line);
+
+ STORE_RESET_ERRNO;
+
+ if (!fgets(t, sizeof(t), f)) {
+
+ if (ferror(f)) {
+ int r;
+
+ r = errno ? -errno : -EIO;
+ RESTORE_ERRNO;
+ return r;
+ }
+
+ t[0] = 0;
+ }
+
+ RESTORE_ERRNO;
+
+ c = strdup(t);
+ if (!c)
+ return -ENOMEM;
+
+ *line = truncate_nl(c);
+
+ return 0;
+}
+
+int read_one_line_from_path(const char *path, char **line) {
+ _cleanup_fclose_ FILE *f = NULL;
+
+ assert(path);
+ assert(line);
+
+ f = fopen(path, "re");
+ if (!f)
+ return -errno;
+
+ return read_one_line_from_file(f, line);
+}
+
+#define DEFINE_WRITE_NUM_TO_FILE(type, format) \
+ int write_##type##_to_file(FILE *f, \
+ type##_t u, \
+ enum file_write_flags flags) { \
+ int r = 0; \
+ \
+ assert(f); \
+ \
+ STORE_RESET_ERRNO; \
+ \
+ (void) fprintf(f, format, u); \
+ if (flags & FILE_WRITE_NEWLINE_IF_NOT) \
+ (void) fputc('\n', f); \
+ \
+ if (flags & FILE_WRITE_WITH_FFLUSH) \
+ (void) fflush(f); \
+ \
+ if (ferror(f)) \
+ r = errno ? -errno : -EIO; \
+ \
+ RESTORE_ERRNO; \
+ \
+ return r; \
+ }
+
+#define DEFINE_WRITE_NUM_TO_PATH(type) \
+ int write_##type##_to_path(const char *path, \
+ type##_t u, \
+ enum file_write_flags flags) { \
+ _cleanup_fclose_ FILE *f = NULL; \
+ \
+ assert(path); \
+ \
+ if (flags & FILE_WRITE_APPEND) \
+ f = fopen(path, "ae"); \
+ else \
+ f = fopen(path, "we"); \
+ if (!f) \
+ return -errno; \
+ \
+ return write_##type##_to_file(f, u, flags); \
+ }
+
+#define DEFINE_WRITE_NUM_DUAL(type, format) \
+ DEFINE_WRITE_NUM_TO_FILE(type, format); \
+ DEFINE_WRITE_NUM_TO_PATH(type)
+
+#define DEFINE_READ_NUM_FROM_FILE(type, format) \
+ int read_##type##_from_file(FILE *f, type##_t *num) { \
+ int r = 0; \
+ \
+ assert(f); \
+ assert(num); \
+ \
+ STORE_RESET_ERRNO; \
+ \
+ r = fscanf(f, format, num); \
+ if (r == EOF && ferror(f)) \
+ r = errno ? -errno : -EOF; \
+ \
+ RESTORE_ERRNO; \
+ \
+ return r; \
+ }
+
+#define DEFINE_READ_NUM_FROM_PATH(type) \
+ int read_##type##_from_path(const char *path, type##_t *num) { \
+ _cleanup_fclose_ FILE *f = NULL; \
+ \
+ assert(path); \
+ assert(num); \
+ \
+ f = fopen(path, "re"); \
+ if (!f) \
+ return -errno; \
+ \
+ return read_##type##_from_file(f, num); \
+ }
+
+#define DEFINE_READ_NUM_DUAL(type, format) \
+ DEFINE_READ_NUM_FROM_FILE(type, format); \
+ DEFINE_READ_NUM_FROM_PATH(type)
+
+#define DEFINE_READ_WRITE_NUM_DUAL(type, r_format, w_format) \
+ DEFINE_READ_NUM_DUAL(type, r_format); \
+ DEFINE_WRITE_NUM_DUAL(type, w_format)
+
+DEFINE_READ_WRITE_NUM_DUAL(int32, "%d", "%d");
+DEFINE_READ_WRITE_NUM_DUAL(uint32, "%u", "%u");
+DEFINE_READ_WRITE_NUM_DUAL(int64, "%" SCNd64, "%" PRId64);
+DEFINE_READ_WRITE_NUM_DUAL(uint64, "%" SCNu64, "%" PRIu64);
+
+int write_int_to_file(FILE *f, int num, enum file_write_flags flags) {
+
+ assert(f);
+ assert(num);
+
+ return write_int32_to_file(f, (int32_t) num, flags);
+}
+
+int write_int_to_path(const char *path, int num, enum file_write_flags flags) {
+
+ assert(path);
+ assert(num);
+
+ return write_int32_to_path(path, (int32_t) num, flags);
+}
+
+int write_unsigned_int_to_file(FILE *f, unsigned int num, enum file_write_flags flags) {
+
+ assert(f);
+ assert(num);
+
+ return write_uint32_to_file(f, (uint32_t) num, flags);
+}
+
+int write_unsigned_int_to_path(const char *path, unsigned int num, enum file_write_flags flags) {
+
+ assert(path);
+ assert(num);
+
+ return write_uint32_to_path(path, (uint32_t) num, flags);
+}
+
+int write_long_int_to_file(FILE *f, long int num, enum file_write_flags flags) {
+
+ assert(f);
+ assert(num);
+
+#if __WORDSIZE == 64
+ return write_int64_to_file(f, (int64_t) num, flags);
+#else
+ return write_int32_to_file(f, (int32_t) num, flags);
+#endif
+}
+
+int write_long_int_to_path(const char *path, long int num, enum file_write_flags flags) {
+
+ assert(path);
+ assert(num);
+
+#if __WORDSIZE == 64
+ return write_int64_to_path(path, (int64_t) num, flags);
+#else
+ return write_int32_to_path(path, (int32_t) num, flags);
+#endif
+}
+
+int write_unsigned_long_int_to_file(FILE *f, unsigned long int num, enum file_write_flags flags) {
+
+ assert(f);
+ assert(num);
+
+#if __WORDSIZE == 64
+ return write_uint64_to_file(f, (uint64_t) num, flags);
+#else
+ return write_uint32_to_file(f, (uint32_t) num, flags);
+#endif
+}
+
+int write_unsigned_long_int_to_path(const char *path, unsigned long int num, enum file_write_flags flags) {
+
+ assert(path);
+ assert(num);
+
+#if __WORDSIZE == 64
+ return write_uint64_to_path(path, (uint64_t) num, flags);
+#else
+ return write_uint32_to_path(path, (uint32_t) num, flags);
+#endif
+}
+
+int write_long_long_int_to_file(FILE *f, long long int num, enum file_write_flags flags) {
+
+ assert(f);
+ assert(num);
+
+ return write_int64_to_file(f, (int64_t) num, flags);
+}
+
+int write_long_long_int_to_path(const char *path, long long int num, enum file_write_flags flags) {
+
+ assert(path);
+ assert(num);
+
+ return write_int64_to_path(path, (int64_t) num, flags);
+}
+
+int write_unsigned_long_long_int_to_file(FILE *f, unsigned long long int num, enum file_write_flags flags) {
+
+ assert(f);
+ assert(num);
+
+ return write_uint64_to_file(f, (uint64_t) num, flags);
+}
+
+int write_unsigned_long_long_int_to_path(const char *path, unsigned long long int num, enum file_write_flags flags) {
+
+ assert(path);
+ assert(num);
+
+ return write_uint64_to_path(path, (uint64_t) num, flags);
+}
+
+int read_int_from_file(FILE *f, int *num) {
+
+ assert(f);
+ assert(num);
+
+ return read_int32_from_file(f, (int32_t *) num);
+}
+
+int read_int_from_path(const char *path, int *num) {
+
+ assert(path);
+ assert(num);
+
+ return read_int32_from_path(path, (int32_t *) num);
+}
+
+int read_unsigned_int_from_file(FILE *f, unsigned int *num) {
+
+ assert(f);
+ assert(num);
+
+ return read_uint32_from_file(f, (uint32_t *) num);
+}
+
+int read_unsigned_int_from_path(const char *path, unsigned int *num) {
+
+ assert(path);
+ assert(num);
+
+ return read_uint32_from_path(path, (uint32_t *) num);
+}
+
+int read_long_int_from_file(FILE *f, long int *num) {
+
+ assert(f);
+ assert(num);
+
+#if __WORDSIZE == 64
+ return read_int64_from_file(f, (int64_t *) num);
+#else
+ return read_int32_from_file(f, (int32_t *) num);
+#endif
+}
+
+int read_long_int_from_path(const char *path, long int *num) {
+
+ assert(path);
+ assert(num);
+
+#if __WORDSIZE == 64
+ return read_int64_from_path(path, (int64_t *) num);
+#else
+ return read_int32_from_path(path, (int32_t *) num);
+#endif
+}
+
+int read_unsigned_long_int_from_file(FILE *f, unsigned long int *num) {
+
+ assert(f);
+ assert(num);
+
+#if __WORDSIZE == 64
+ return read_uint64_from_file(f, (uint64_t *) num);
+#else
+ return read_uint32_from_file(f, (uint32_t *) num);
+#endif
+}
+
+int read_unsigned_long_int_from_path(const char *path, unsigned long int *num) {
+
+ assert(path);
+ assert(num);
+
+#if __WORDSIZE == 64
+ return read_uint64_from_path(path, (uint64_t *) num);
+#else
+ return read_uint32_from_path(path, (uint32_t *) num);
+#endif
+}
+
+int read_long_long_int_from_file(FILE *f, long long *num) {
+
+ assert(f);
+ assert(num);
+
+ return read_int64_from_file(f, (int64_t *) num);
+}
+
+int read_long_long_int_from_path(const char *path, long long *num) {
+
+ assert(path);
+ assert(num);
+
+ return read_int64_from_path(path, (int64_t *) num);
+}
+
+int read_unsigned_long_long_int_from_file(FILE *f, unsigned long long *num) {
+
+ assert(f);
+ assert(num);
+
+ return read_uint64_from_file(f, (uint64_t *) num);
+}
+
+int read_unsigned_long_long_int_from_path(const char *path, unsigned long long *num) {
+
+ assert(path);
+ assert(num);
+
+ return read_uint64_from_path(path, (uint64_t *) num);
+}
+
+int str_to_strv(const char *str, char ***strv, const char *separator) {
+ char *w, *state, *p;
+ char **v = NULL, **new = NULL;
+ size_t l;
+ size_t i = 0;
+
+ FOREACH_WORD_SEPARATOR(w, l, str, separator, state) {
+ p = strndup(w, l);
+ if (!p) {
+ free(v);
+ return -ENOMEM;
+ }
+
+ new = (char **) realloc(v, sizeof(char *) * (i + 2));
+ if (!new) {
+ free(p);
+ free(v);
+ p = NULL;
+ return -ENOMEM;
+ }
+
+ v = new;
+
+ v[i] = p;
+ v[i + 1] = NULL;
+ i++;
+ }
+
+ *strv = v;
+
+ return 0;
+}
+
+size_t sizeof_strv(char **strv) {
+ size_t u = 0;
+
+ if (!strv)
+ return 0;
+
+ while(strv[u++])
+ ;
+
+ return u - 1;
+}
+
+int strv_attach(char **first, char **second, char ***strv, bool free_second) {
+ char **new = NULL;
+ size_t n1 = 0, n2 = 0;
+
+ assert(strv);
+
+ if (first)
+ n1 = sizeof_strv(first);
+
+ if (second) {
+ n2 = sizeof_strv(second);
+
+ new = (char **) realloc(first, sizeof(char *) * (n1 + n2 + 1));
+ if (!new)
+ return -ENOMEM;
+
+ first = new;
+
+ memcpy(first + n1, second, sizeof(char *) * (n2 + 1));
+
+ if (free_second)
+ free(second);
+ }
+
+ *strv = first;
+
+ return 0;
+}
+
+void strv_free_full(char **strv) {
+ char **s;
+
+ if (!strv)
+ return;
+
+ FOREACH_STRV(s, strv) {
+ if (s && *s) {
+ free(*s);
+ *s = NULL;
+ }
+ }
+
+ free(strv);
+ strv = NULL;
+}
+
+bool isdir(const char *path) {
+ struct stat st;
+
+ assert(path);
+
+ if (lstat(path, &st) < 0)
+ return false;
+
+ return S_ISDIR(st.st_mode);
+}
+
+int touch(const char *path) {
+ _cleanup_fclose_ FILE *f = NULL;
+
+ assert(path);
+
+ f = fopen(path, "w");
+ if (!f)
+ return -errno;
+
+ return 0;
+}
+
+bool mnt_is_mounted(const char *fsname, const char *dir, const char *type, const char *opts) {
+ struct mntent *ent;
+ FILE *f = NULL;
+ bool matched = false;
+
+ f = setmntent("/etc/mtab", "r");
+ if (!f)
+ return false;
+
+ while ((ent = getmntent(f))) {
+ if (fsname) {
+ if (streq(fsname, ent->mnt_fsname))
+ matched = true;
+ else
+ goto no_match;
+ }
+
+ if (dir) {
+ if (streq(dir, ent->mnt_dir))
+ matched = true;
+ else
+ goto no_match;
+ }
+
+ if (type) {
+ if (streq(type, ent->mnt_type))
+ matched = true;
+ else
+ goto no_match;
+ }
+
+ if (opts) {
+ if (streq(opts, ent->mnt_opts))
+ matched = true;
+ else
+ goto no_match;
+ }
+
+ if (matched)
+ break;
+
+ no_match:
+ matched = false;
+ }
+
+ endmntent(f);
+
+ return matched;
+}
diff --git a/src/libsystem/libsystem.h b/src/libsystem/libsystem.h
new file mode 100644
index 0000000..4452179
--- /dev/null
+++ b/src/libsystem/libsystem.h
@@ -0,0 +1,1428 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * libsystem
+ *
+ * Copyright (c) 2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file libsystem.h
+ *
+ * system utility library
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#pragma once
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Many functions have no effects except the return value and their
+ * return value depends only on the parameters and/or global
+ * variables. Such a function can be subject to common subexpression
+ * elimination and loop optimization just as an arithmetic operator
+ * would be. These functions should be declared with the attribute
+ * pure.
+ */
+#define _pure_ __attribute__ ((pure))
+
+/**
+ * The cleanup attribute runs a function when the variable goes out of
+ * scope. This attribute can only be applied to auto function scope
+ * variables; it may not be applied to parameters or variables with
+ * static storage duration. The function must take one parameter, a
+ * pointer to a type compatible with the variable. The return value of
+ * the function (if any) is ignored.
+ */
+#define _cleanup_(x) __attribute__((cleanup(x)))
+
+/**
+ * whitespaces such like space, tab or newlines
+ */
+#define WHITESPACE " \t\n\r"
+
+/**
+ * newlines
+ */
+#define NEWLINE "\n\r"
+
+/**
+ * single or double quotes
+ */
+#define QUOTES "\"\'"
+
+/**
+ * comment start specifiers such like sharp(#) or semicolon(;)
+ */
+#define COMMENTS "#;"
+
+/**
+ * @defgroup GCC_CLEANUP_ATT_GROUP gcc cleanup attribute
+ *
+ * @{
+ */
+
+static inline void __cleanup_free_func(void *p) {
+ free(*(void**) p);
+}
+
+static inline void __cleanup_close_func(int *fd) {
+ if (*fd >= 0)
+ close(*fd);
+}
+
+static inline void __cleanup_fclose_func(FILE **f) {
+ if (*f)
+ fclose(*f);
+}
+
+static inline void __cleanup_pclose_func(FILE **f) {
+ if (*f)
+ pclose(*f);
+}
+
+static inline void __cleanup_closedir_func(DIR **d) {
+ if (*d)
+ closedir(*d);
+}
+
+static inline const char *startswith(const char *s, const char *prefix) {
+ if (strncmp(s, prefix, strlen(prefix)) == 0)
+ return s + strlen(prefix);
+ return NULL;
+}
+
+static inline bool isempty(const char *p) {
+ return !p || !p[0];
+}
+
+/**
+ * Declare value with cleanup attribute. free() is called when is
+ * going out the scope.
+ */
+#define _cleanup_free_ _cleanup_(__cleanup_free_func)
+
+/**
+ * Declare value with cleanup attribute. close() is called when is
+ * going out the scope.
+ */
+#define _cleanup_close_ _cleanup_(__cleanup_close_func)
+
+/**
+ * Declare value with cleanup attribute. fclose() is called when is
+ * going out the scope.
+ */
+#define _cleanup_fclose_ _cleanup_(__cleanup_fclose_func)
+
+/**
+ * Declare value with cleanup attribute. pclose() is called when is
+ * going out the scope.
+ */
+#define _cleanup_pclose_ _cleanup_(__cleanup_pclose_func)
+
+/**
+ * Declare value with cleanup attribute. closedir() is called when is
+ * going out the scope.
+ */
+#define _cleanup_closedir_ _cleanup_(__cleanup_closedir_func)
+/**
+ * @}
+ */
+
+/**
+ * Allocate n number of size t memory.
+ */
+#define new(t, n) ((t*) malloc(sizeof(t) * (n)))
+
+/**
+ * Allocate n number of size t memory. And initialize to 0 all.
+ */
+#define new0(t, n) ((t*) calloc((n), sizeof(t)))
+
+/**
+ * Allocate n number memory.
+ */
+#define malloc0(n) (calloc((n), 1))
+
+/**
+ * @brief Parse boolean type string.
+ *
+ * @param v String to parse.
+ *
+ * @return TRUE on "1", 'y', 'Y', 't', 'T' and "on". FALSE on "0",
+ * 'n', 'N', 'f', 'F', "off".
+ */
+int parse_boolean(const char *v) _pure_;
+
+/**
+ * @brief Parse byte type string.
+ *
+ * @param b Byte string. This can be only digit number with byte unit
+ * "BKMG". B is byte, K is kilo byte, M is mega byte and G is gira
+ * byte. Byte is default.
+ * @param s Parsed byte size is filled.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int parse_bytes(const char *b, size_t *s) _pure_;
+
+/**
+ * @brief Parse percentage type string.
+ *
+ * @param string Percentage string to parse. Such like "70%".
+ * @param percent Parsed percentage size is filled.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int parse_percent(const char *string, size_t *percent) _pure_;
+
+/**
+ * @brief check the path string is started with '/'
+ *
+ * @param p a path to check
+ *
+ * @return true if p started with '/', otherwise false.
+ */
+bool path_is_absolute(const char *p);
+
+/**
+ * @brief Removes redundant inner and trailing slashes. Modifies the
+ * passed string in-place. For example, if "///foo//bar/" is given
+ * then the path will be changed as "/foo/bar"
+ *
+ * @param path a path to modify.
+ *
+ * @return modified path pointer. It maybe identical with given path.
+ */
+char *path_kill_slashes(char *path);
+
+/**
+ * Get element number of array.
+ */
+#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0]))
+
+/**
+ * Iterate for each struct reference.
+ */
+#define FOREACH_STRUCT_REF(s, f, i) \
+ for ((i) = 0; s[(i)].f != NULL; (i)++)
+
+/**
+ * @brief Iterate for each directory entries exclude "." and "..".
+ */
+#define FOREACH_DIRENT(de, d, on_error) \
+ for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) \
+ if (!de) { \
+ if (errno > 0) { \
+ on_error; \
+ } \
+ break; \
+ } else if (streq(de->d_name, ".") || \
+ streq(de->d_name, "..")) \
+ continue; \
+ else
+
+/**
+ * @brief Check string is digit.
+ *
+ * @param s String to check.
+ * @param l Length to check.
+ *
+ * @return TRUE on all the characters are digit. FALSE on the others.
+ */
+bool is_number(const char *s, int l);
+
+/**
+ * @brief copy a file with mode, if destination file exists, return
+ * error.
+ *
+ * @param src source file path
+ * @param dst destination file path
+ * @param mode destination file mode
+ *
+ * @return 0 on success, -errno on failure. -EALREADY if destination
+ * file exist.
+ */
+int do_copy_mode(const char *src, const char *dst, mode_t mode);
+
+/**
+ * @brief copy a file with mode, if destination file exists, the file
+ * is overwritten.
+ *
+ * @param src source file path
+ * @param dst destination file path
+ * @param mode destination file mode
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int do_copy_mode_force(const char *src, const char *dst, mode_t mode);
+
+/**
+ * @brief copy a file, destination file mode is 0644, if destination
+ * file exist, return error.
+ *
+ * @param src source file path
+ * @param dst destination file path
+ *
+ * @return 0 on success, -errno on failure. -EALREADY if destination
+ * file exist.
+ */
+int do_copy(const char *src, const char *dst);
+
+/**
+ * @brief copy a file, destination file mode is 0644, if destination
+ * file exist, the file is overwritten.
+ *
+ * @param src source file path
+ * @param dst destination file path
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int do_copy_force(const char *src, const char *dst);
+
+/**
+ * @brief Make a directory. If parent directories are also absent,
+ * make them also. Corresponding with "mkdir -p".
+ *
+ * @param path Path to make directory.
+ * @param mode The directory mode.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int do_mkdir(const char *path, mode_t mode);
+
+/**
+ * @brief Remove all elements in path recursivly.
+ *
+ * @param path Path to make directory.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int rmdir_recursive(const char *path);
+
+/**
+ * @defgroup FILE_READ_WRITE_GROUP File Read/Write utility
+ *
+ * @{
+ */
+
+/**
+ * file write flags
+ */
+enum file_write_flags {
+ /** Append line-end(\\n) at the end of file. In case of string
+ * write, if given string has already line-end characters
+ * then this flag has no effect. */
+ FILE_WRITE_NEWLINE_IF_NOT = 1 << 0,
+ /** Run fflush(3) after file write. */
+ FILE_WRITE_WITH_FFLUSH = 1 << 1,
+ /** Open file as append mode. */
+ FILE_WRITE_APPEND = 1 << 2,
+};
+
+/**
+ * @brief Write strings to FILE
+ *
+ * @param f File pointer.
+ * @param str Strings to write.
+ * @param flags Optional flags to write file. For
+ * ::FILE_WRITE_NEWLINE_IF_NOT, if str has already line-end,
+ * ::FILE_WRITE_NEWLINE_IF_NOT will has no effect. For detail, see
+ * ::file_write_flags.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int write_str_to_file(FILE *f, const char *str, enum file_write_flags flags);
+
+/**
+ * @brief Write strings to path.
+ *
+ * @param path File path.
+ * @param str Strings to write.
+ * @param flags Optional flags to write file. For
+ * ::FILE_WRITE_NEWLINE_IF_NOT, if str has already line-end,
+ * ::FILE_WRITE_NEWLINE_IF_NOT will has no effect. For detail, see
+ * ::file_write_flags.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int write_str_to_path(const char *path, const char *str, enum file_write_flags flags);
+
+/**
+ * @brief Write signed decimal integer to FILE.
+ *
+ * @param f File pointer.
+ * @param i Signed integer to write.
+ * @param flags Optional flags to write file. if
+ * ::FILE_WRITE_NEWLINE_IF_NOT is set, line-end added. For detail, see
+ * ::file_write_flags.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int write_int32_to_file(FILE *f, int32_t i, enum file_write_flags flags);
+
+/**
+ * @brief Write signed decimal integer to path.
+ *
+ * @param path File path.
+ * @param i Signed integer to write.
+ * @param flags Optional flags to write file. if
+ * ::FILE_WRITE_NEWLINE_IF_NOT is set, line-end added. For detail, see
+ * ::file_write_flags.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int write_int32_to_path(const char *path, int32_t i, enum file_write_flags flags);
+
+/**
+ * @brief Write unsigned decimal integer to FILE.
+ *
+ * @param f File pointer
+ * @param u Unsigned integer to write.
+ * @param flags Optional flags to write file. if
+ * ::FILE_WRITE_NEWLINE_IF_NOT is set, line-end added. For detail, see
+ * ::file_write_flags.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int write_uint32_to_file(FILE *f, uint32_t u, enum file_write_flags flags);
+
+/**
+ * @brief Write unsigned decimal integer to path.
+ *
+ * @param path File path.
+ * @param u Unsigned integer to write.
+ * @param flags Optional flags to write file. if
+ * ::FILE_WRITE_NEWLINE_IF_NOT is set, line-end added. For detail, see
+ * ::file_write_flags.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int write_uint32_to_path(const char *path, uint32_t u, enum file_write_flags flags);
+
+/**
+ * @brief Write 64 bit signed decimal integer to FILE.
+ *
+ * @param f File pointer.
+ * @param i 64 bit signed integer to write.
+ * @param flags Optional flags to write file. if
+ * ::FILE_WRITE_NEWLINE_IF_NOT is set, line-end added. For detail, see
+ * ::file_write_flags.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int write_int64_to_file(FILE *f, int64_t i, enum file_write_flags flags);
+
+/**
+ * @brief Write 64 bit signed decimal integer to path.
+ *
+ * @param path File path.
+ * @param i 64 bit signed integer to write.
+ * @param flags Optional flags to write file. if
+ * ::FILE_WRITE_NEWLINE_IF_NOT is set, line-end added. For detail, see
+ * ::file_write_flags.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int write_int64_to_path(const char *path, int64_t i, enum file_write_flags flags);
+
+/**
+ * @brief Write 64 bit unsigned decimal integer to FILE.
+ *
+ * @param f File pointer
+ * @param u 64 bit Unsigned integer to write.
+ * @param flags Optional flags to write file. if
+ * ::FILE_WRITE_NEWLINE_IF_NOT is set, line-end added. For detail, see
+ * ::file_write_flags.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int write_uint64_to_file(FILE *f, uint64_t u, enum file_write_flags flags);
+
+/**
+ * @brief Write 64 bit unsigned decimal integer to path.
+ *
+ * @param path File path.
+ * @param u 64 bit Unsigned integer to write.
+ * @param flags Optional flags to write file. if
+ * ::FILE_WRITE_NEWLINE_IF_NOT is set, line-end added. For detail, see
+ * ::file_write_flags.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int write_uint64_to_path(const char *path, uint64_t u, enum file_write_flags flags);
+
+/**
+ * @brief Write int to FILE.
+ *
+ * @param f File pointer
+ * @param num int to write.
+ * @param flags Optional flags to write file. if
+ * ::FILE_WRITE_NEWLINE_IF_NOT is set, line-end added. For detail, see
+ * ::file_write_flags.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int write_int_to_file(FILE *f, int num, enum file_write_flags flags);
+
+/**
+ * @brief Write int to path.
+ *
+ * @param path File path.
+ * @param num int to write.
+ * @param flags Optional flags to write file. if
+ * ::FILE_WRITE_NEWLINE_IF_NOT is set, line-end added. For detail, see
+ * ::file_write_flags.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int write_int_to_path(const char *path, int num, enum file_write_flags flags);
+
+/**
+ * @brief Write type unsigned int to FILE.
+ *
+ * @param f File pointer
+ * @param num unsigned int to write.
+ * @param flags Optional flags to write file. if
+ * ::FILE_WRITE_NEWLINE_IF_NOT is set, line-end added. For detail, see
+ * ::file_write_flags.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int write_unsigned_int_to_file(FILE *f, unsigned int num, enum file_write_flags flags);
+
+/**
+ * @brief Write int to path.
+ *
+ * @param path File path.
+ * @param num int to write.
+ * @param flags Optional flags to write file. if
+ * ::FILE_WRITE_NEWLINE_IF_NOT is set, line-end added. For detail, see
+ * ::file_write_flags.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int write_unsigned_int_to_path(const char *path, unsigned int num, enum file_write_flags flags);
+
+/**
+ * @brief Write long int to FILE.
+ *
+ * @param f File pointer
+ * @param num long int to write.
+ * @param flags Optional flags to write file. if
+ * ::FILE_WRITE_NEWLINE_IF_NOT is set, line-end added. For detail, see
+ * ::file_write_flags.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int write_long_int_to_file(FILE *f, long int num, enum file_write_flags flags);
+
+/**
+ * @brief Write int to path.
+ *
+ * @param path File path.
+ * @param num int to write.
+ * @param flags Optional flags to write file. if
+ * ::FILE_WRITE_NEWLINE_IF_NOT is set, line-end added. For detail, see
+ * ::file_write_flags.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int write_long_int_to_path(const char *path, long int num, enum file_write_flags flags);
+
+/**
+ * @brief Write unsigned long int to FILE.
+ *
+ * @param f File pointer
+ * @param num unsigned long int to write.
+ * @param flags Optional flags to write file. if
+ * ::FILE_WRITE_NEWLINE_IF_NOT is set, line-end added. For detail, see
+ * ::file_write_flags.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int write_unsigned_long_int_to_file(FILE *f, unsigned long int num, enum file_write_flags flags);
+
+/**
+ * @brief Write int to path.
+ *
+ * @param path File path.
+ * @param num int to write.
+ * @param flags Optional flags to write file. if
+ * ::FILE_WRITE_NEWLINE_IF_NOT is set, line-end added. For detail, see
+ * ::file_write_flags.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int write_unsigned_long_int_to_path(const char *path, unsigned long int num, enum file_write_flags flags);
+
+/**
+ * @brief Write long long int to FILE.
+ *
+ * @param f File pointer
+ * @param num long long int to write.
+ * @param flags Optional flags to write file. if
+ * ::FILE_WRITE_NEWLINE_IF_NOT is set, line-end added. For detail, see
+ * ::file_write_flags.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int write_long_long_int_to_file(FILE *f, long long int num, enum file_write_flags flags);
+
+/**
+ * @brief Write int to path.
+ *
+ * @param path File path.
+ * @param num int to write.
+ * @param flags Optional flags to write file. if
+ * ::FILE_WRITE_NEWLINE_IF_NOT is set, line-end added. For detail, see
+ * ::file_write_flags.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int write_long_long_int_to_path(const char *path, long long int num, enum file_write_flags flags);
+
+/**
+ * @brief Write unsigned long long int to FILE.
+ *
+ * @param f File pointer
+ * @param num unsigned long long int to write.
+ * @param flags Optional flags to write file. if
+ * ::FILE_WRITE_NEWLINE_IF_NOT is set, line-end added. For detail, see
+ * ::file_write_flags.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int write_unsigned_long_long_int_to_file(FILE *f, unsigned long long int num, enum file_write_flags flags);
+
+/**
+ * @brief Write int to path.
+ *
+ * @param path File path.
+ * @param num int to write.
+ * @param flags Optional flags to write file. if
+ * ::FILE_WRITE_NEWLINE_IF_NOT is set, line-end added. For detail, see
+ * ::file_write_flags.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int write_unsigned_long_long_int_to_path(const char *path, unsigned long long int num, enum file_write_flags flags);
+
+/**
+ * @brief Read the first line from FILE
+ *
+ * @param f File pointer.
+ * @param line Duplicated string line is filled. This value has to
+ * be free-ed by caller.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int read_one_line_from_file(FILE *f, char **line);
+
+/**
+ * @brief Read the first line from path
+ *
+ * @param path File path.
+ * @param line Duplicated string line is filled. This value has to
+ * be free-ed by caller.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int read_one_line_from_path(const char *path, char **line);
+
+/**
+ * @brief Read signed decimal integer from FILE.
+ *
+ * @param f File pointer.
+ * @param i signed int value pointer.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int read_int32_from_file(FILE *f, int32_t *i);
+
+/**
+ * @brief Read signed decimalinteger from path.
+ *
+ * @param path File path.
+ * @param i signed int value pointer.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int read_int32_from_path(const char *path, int32_t *i);
+
+/**
+ * @brief Read unsigned decimalinteger from FILE.
+ *
+ * @param f File pointer.
+ * @param u unsigned int value pointer.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int read_uint32_from_file(FILE *f, uint32_t *u);
+
+/**
+ * @brief Read unsigned decimal integer from path
+ *
+ * @param path File path.
+ * @param u unsigned int value pointer.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int read_uint32_from_path(const char *path, uint32_t *u);
+
+/**
+ * @brief Read 64 bit signed decimal integer from FILE.
+ *
+ * @param f File pointer.
+ * @param i 64 bit signed int value pointer.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int read_int64_from_file(FILE *f, int64_t *i);
+
+/**
+ * @brief Read 64 bit signed decimal integer from path.
+ *
+ * @param path File path.
+ * @param i 64 bit signed int value pointer.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int read_int64_from_path(const char *path, int64_t *i);
+
+/**
+ * @brief Read 64 bit unsigned decimal integer from FILE.
+ *
+ * @param f File pointer.
+ * @param u 64 bit unsigned int value pointer.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int read_uint64_from_file(FILE *f, uint64_t *u);
+
+/**
+ * @brief Read 64 bit unsigned decimal integer from path
+ *
+ * @param path File path.
+ * @param u 64 bit unsigned int value pointer.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int read_uint64_from_path(const char *path, uint64_t *u);
+
+/**
+ * @brief Read type int from FILE
+ *
+ * @param f File pointer.
+ * @param num type int pointer
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int read_int_from_file(FILE *f, int *num);
+
+/**
+ * @brief Read type int from path
+ *
+ * @param path File path.
+ * @param num type int pointer
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int read_int_from_path(const char *path, int *num);
+
+/**
+ * @brief Read type unsigned int from FILE
+ *
+ * @param f File pointer.
+ * @param num type unsigned int pointer
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int read_unsigned_int_from_file(FILE *f, unsigned int *num);
+
+/**
+ * @brief Read type unsigned int from path
+ *
+ * @param path File path.
+ * @param num type unsigned int pointer
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int read_unsigned_int_from_path(const char *path, unsigned int *num);
+
+/**
+ * @brief Read type long int from FILE
+ *
+ * @param f File pointer.
+ * @param num type long int pointer
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int read_long_int_from_file(FILE *f, long int *num);
+
+/**
+ * @brief Read type long int from path
+ *
+ * @param path File path.
+ * @param num type long int pointer
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int read_long_int_from_path(const char *path, long int *num);
+
+/**
+ * @brief Read type unsigned long int from FILE
+ *
+ * @param f File pointer.
+ * @param num type unsigned long int pointer
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int read_unsigned_long_int_from_file(FILE *f, unsigned long int *num);
+
+/**
+ * @brief Read type unsigned long int from path
+ *
+ * @param path File path.
+ * @param num type unsigned long int pointer
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int read_unsigned_long_int_from_path(const char *path, unsigned long int *num);
+
+/**
+ * @brief Read type long long int from FILE
+ *
+ * @param f File pointer.
+ * @param num type long long int pointer
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int read_long_long_int_from_file(FILE *f, long long *num);
+
+/**
+ * @brief Read type long long int from path
+ *
+ * @param path File path.
+ * @param num type long long int pointer
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int read_long_long_int_from_path(const char *path, long long *num);
+
+/**
+ * @brief Read type unsigned long long int from FILE
+ *
+ * @param f File pointer.
+ * @param num type unsigned long long int pointer
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int read_unsigned_long_long_int_from_file(FILE *f, unsigned long long *num);
+
+/**
+ * @brief Read type unsigned long long int from path
+ *
+ * @param path File path.
+ * @param num type unsigned long long int pointer
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int read_unsigned_long_long_int_from_path(const char *path, unsigned long long *num);
+/**
+ * @}
+ */
+
+/**
+ * @defgroup STRING_GROUP String helper
+ *
+ * @{
+ */
+
+/**
+ * Compare two strings. TRUE on same, FALSE on others.
+ * Same with (strcmp((a),(b)) == 0)
+ */
+#define streq(a,b) (strcmp((a),(b)) == 0)
+/**
+ * Compare two strings for n length. TRUE on same, FALSE on others.
+ * Same with (strncmp((a), (b), (n)) == 0)
+ */
+#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
+
+/**
+ * Compare two strings. Similar to streq() but ignore case. TRUE on
+ * same, FALSE on others.
+ * Same with (strcasecmp((a),(b)) == 0)
+ */
+#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0)
+
+/**
+ * Compare two strings for n length. Similar to strneq() but ignore
+ * case. TRUE on same, FALSE on others.
+ * Same with (strcasecmp((a),(b)) == 0)
+ */
+#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0)
+
+/**
+ * Iterate string in strings which include null characters.
+ * For example,
+ *\code{.c}
+const char str[] = {
+ "foo\0"
+ "bar\0";
+};
+
+const char *s;
+
+NULSTR_FOREACH(s, str) {
+ // do something here
+}
+ *\endcode
+ */
+#define NULSTR_FOREACH(i, l) \
+ for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)
+
+/**
+ * @brief Like streq(), but tries to make sense of NULL pointers.
+ *
+ * @param a String.
+ * @param b String.
+ *
+ * @return TRUE on same, FALSE on the others.
+ */
+bool streq_ptr(const char *a, const char *b) _pure_;
+
+/**
+ * @brief Truncate line end characters.
+ *
+ * @param s String to truncate.
+ *
+ * @return Result string.
+ */
+char *truncate_nl(char *s);
+
+/**
+ * @brief Append suffix string to sting s with size b.
+ *
+ * @param s Ahead string.
+ * @param suffix The second string.
+ * @param b suffix size to append.
+ *
+ * @return Result string. This string has to be free-ed by caller.
+ */
+char *strnappend(const char *s, const char *suffix, size_t b);
+
+/**
+ * @brief Append suffix string to sting s.
+ *
+ * @param s Ahead string.
+ * @param suffix The second string.
+ *
+ * @return Result string. This string has to be free-ed by caller.
+ */
+char *strappend(const char *s, const char *suffix);
+
+/**
+ * @brief Drops trailing whitespaces.
+ *
+ * @param s String.
+ *
+ * @return The pointer to the first non-space character.
+ */
+char *strstrip(char *s);
+
+/**
+ * @brief duplicate string without leading and trailing whitespaces
+ *
+ * @param str a target string to duplicate
+ * @param ret newly allocated string is filled
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int strdup_strip(const char *str, char **ret);
+
+/**
+ * @brief duplicate string without leading and trailing whitespaces,
+ * duplicated string is not over given length len
+ *
+ * @param str a target string to duplicate
+ * @param len maxium length of duplicate
+ * @param ret newly allocated string is filled
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int strndup_strip(const char *str, size_t len, char **ret);
+
+/**
+ * @brief nulstr is similar to string list but each strings ends with
+ * null and the strings are put at one memory buffer. For example,
+ * "foo" and "bar" string can be represented "foo\0bar". This function
+ * check nulstr is containing the needle string.
+ *
+ * @param nulstr a nulstr
+ * @param needle a needle string to find
+ *
+ * @return true if the needle found, otherwise false.
+ */
+bool nulstr_contains(const char*nulstr, const char *needle);
+
+/**
+ * @brief check a string ends with postfix pattern
+ *
+ * @param s a string to check
+ * @param postfix postfix string
+ *
+ * @return if s is ended with postfix string the pointer of the
+ * string, matched pointer of s is returned. Otherwise NULL.
+ */
+char* endswith(const char *s, const char *postfix);
+
+/**
+ * @brief split a string into words. This api generally is not called
+ * directly, #FOREACH_WORD_SEPARATOR or #FOREACH_WORD are using
+ * this. If separator does not include quotes then quoted words are
+ * assumed as single word.
+ *
+ * @param c string to split
+ * @param l splitted word length
+ * @param separator separator strings such like #WHITESPACE
+ * @param state a state internally used
+ *
+ * @return a splitted current word pointer
+ */
+char *split(const char *c, size_t *l, const char *separator, char **state);
+
+/**
+ * @brief Iterate for each words. If separator does not include quotes
+ * then quoted words are assumed as single word.
+ *
+ * @param word Each word
+ * @param length Length of word
+ * @param s Target string
+ * @param separator Seperator string
+ * @param state Used only internal split().
+ */
+#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \
+ for ((state) = NULL, (word) = split((s), &(length), (separator), &(state)); (word); (word) = split((s), &(length), (separator), &(state)))
+
+/**
+ * @brief Iterate for each words. (Seperators are WHITESPACES.) Quoted
+ * words are assumed as single word.
+ *
+ * @param word Each word
+ * @param length Length of word
+ * @param s Target string
+ * @param state Used only internal split().
+ */
+#define FOREACH_WORD(word, length, s, state) \
+ FOREACH_WORD_SEPARATOR(word, length, s, WHITESPACE, state)
+
+/**
+ * @brief Duplicate string and strip quotes from the string.
+ *
+ * @param str String to duplicate.
+ * @param quotes Quote characters to strip. Predefined #QUOTES can be
+ * used to specify quote and double quote.
+ *
+ * @return Result string. This value has to be free-ed by caller.
+ */
+char *strdup_unquote(const char *str, const char *quotes);
+/**
+ * @}
+ */
+
+/**
+ * @defgroup STRV_GROUP String List
+ *
+ * @{
+ */
+
+/**
+ * iterate for each elements of string list.
+ */
+#define FOREACH_STRV(s, l) \
+ for ((s) = (l); (s) && *(s); (s)++)
+
+/**
+ * @brief Split given string to string list with separator.
+ *
+ * @param str string to split as string list.
+ * @param strv Splitted string list is filled. This string list has to
+ * be free-ed.
+ * @param separator sperators to split the string.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int str_to_strv(const char *str, char ***strv, const char *separator);
+
+/**
+ * @brief Get elements of string list. #sizeof_strv() does not count
+ * end of list NULL. For example, for {"foo", "bar", NULL} string
+ * list, #sizeof_strv() returns 2.
+ *
+ * @param strv string list.
+ *
+ * @return number of string list.
+ */
+size_t sizeof_strv(char **strv);
+
+/**
+ * @brief Merge two string lists. If {"foo", "bar"} and {"baz", "qux"}
+ * are given, the result is {"foo", "bar", "baz", "quz"}.
+ *
+ * @param first The first string list.
+ * @param second The second string list.
+ * @param strv Merged string list.
+ * @param free_second If TRUE is given, the second string list will be
+ * free-ed. If FALSE, no action.
+ *
+ * @return number of string list.
+ */
+int strv_attach(char **first, char **second, char ***strv, bool free_second);
+
+/**
+ * @brief Free all given string list
+ *
+ * @param strv string list to free.
+ */
+void strv_free_full(char **strv);
+/**
+ * @}
+ */
+
+/**
+ * @brief Check given path is directory or not
+ *
+ * @param path path to check
+ *
+ * @return TRUE if path is directory, FALSE on others.
+ */
+bool isdir(const char *path);
+
+/**
+ * @brief Simple file create api similar to touch(1)
+ *
+ * @param path file path
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int touch(const char *path);
+
+/**
+ * @brief Check mount entry. Multiple matches of conditoin are able to
+ * be set with mnt_fsname, mnt_dir, mnt_type or mnt_opts. If multiple
+ * matches are given, return true if a entry satisfied all matches.
+ *
+ * \code{.c}
+// check cgroup is mounted
+if (is_mounted("cgroup", NULL, NULL, NULL))
+ printf("cgroup is mounted\n");
+
+// check /tmp is mounted
+if (is_mounted("tmpfs", "/tmp", NULL, NULL))
+ printf("/tmp is mounted\n");
+
+// check cgroup is mounted as cgroup2
+if (is_mounted("cgroup", "/sys/fs/cgroup", "cgroup2", NULL))
+ printf("cgroup is mounted as cgroup2\n");
+ * \endcode
+ *
+ * @param fsname find matched mount filesystem name
+ * @param dir find matched mount dir(path) name
+ * @param type find matched mount type name
+ * @param opts find matched mount option name
+ *
+ * @return true if matched mount entry found, otherwise false.
+ */
+bool mnt_is_mounted(const char *fsname, const char *dir, const char *type, const char *opts);
+
+/**
+ * @defgroup EXEC_GROUP exec group
+ *
+ * @brief fork() and exec() utility
+ * @{
+ */
+
+/**
+ * standard output/error redirect flags
+ */
+enum {
+ /**
+ * Do not redirect standard output/error
+ */
+ EXEC_REDIRECT_NONE = 0x01 << 0,
+ /**
+ * Redirect standard output only
+ */
+ EXEC_REDIRECT_OUTPUT = 0x01 << 1,
+ /**
+ * Redirect standard error only
+ */
+ EXEC_REDIRECT_ERROR = 0x01 << 2,
+ /**
+ * Redirect standard output and error all
+ */
+ EXEC_REDIRECT_ALL = (EXEC_REDIRECT_OUTPUT | EXEC_REDIRECT_ERROR),
+};
+
+/**
+ * @brief Traditional fork() and exec() helper. If child is not
+ * deactivated within given \p timeout_msec then kill it with given
+ * signal. And additionally redirect child process standard output or
+ * standard error to given fd.
+ *
+ * @param argv array of pointers to null-terminated strings that
+ * represent the argument list available to the new program. The first
+ * argument should point to the filename associated with the file
+ * being executed. The array of pointers must be terminated by a NULL
+ * pointer.
+ * @param envp specify the environment of the executed program via the
+ * argument envp. The envp argument is an array of pointers to
+ * null-terminated strings and must be terminated by a NULL pointer.
+ * @param timeout_msec timeout millisecond to prevent infinite
+ * waiting. If negative is given, the parent will not wait the
+ * child. In other word, the parent will return immediately. If 0 is
+ * given, parent will wait the child infinitly. And if positive value
+ * is given parent will wait given milliseconds and expired return
+ * -1. If the child is exit within the tiemout millisecond return with
+ * child exit code.
+ * @param sig signal to kill the child on timeout.
+ * @param fd file descriptor to redirect child standard output or
+ * error.
+ * @param flags redirect flag. This flags is able to include
+ * EXEC_REDIRECT_OUTPUT or EXEC_REDIRECT_ERROR.
+ *
+ * @return exit code of child. It is fully depend on the child
+ * process. If the child exit with 1 then this function also return 1.
+ * Negative errno on error. -ETIME on timer expired.
+ */
+int do_fork_exec_kill_redirect(char *const argv[], char * const envp[], int64_t timeout_msec, int sig, int fd, int flags);
+
+/**
+ * @brief Traditional fork() and exec() helper. And additionally
+ * redirect child process standard output or standard error to given fd.
+ *
+ * @param argv array of pointers to null-terminated strings that
+ * represent the argument list available to the new program. The first
+ * argument should point to the filename associated with the file
+ * being executed. The array of pointers must be terminated by a NULL pointer.
+ * @param envp specify the environment of the executed program via the
+ * argument envp. The envp argument is an array of pointers to
+ * null-terminated strings and must be terminated by a NULL pointer.
+ * @param timeout_msec timeout millisecond to prevent infinite
+ * waiting. If negative is given, the parent will not wait the
+ * child. In other word, the parent will return immediately. If 0 is
+ * given, parent will wait the child infinitly. And if positive value
+ * is given parent will wait given milliseconds and expired return
+ * -1. If the child is exit within the tiemout millisecond return with
+ * child exit code.
+ * @param fd file descriptor to redirect child standard output or error.
+ * @param flags redirect flag. This flags is able to include
+ * EXEC_REDIRECT_OUTPUT or EXEC_REDIRECT_ERROR.
+ *
+ * @return exit code of child. It is fully depend on the child
+ * process. If the child exit with 1 then this function also return 1.
+ * Negative errno on error. -ETIME on timer expired.
+ */
+int do_fork_exec_redirect(char *const argv[], char * const envp[], int64_t timeout_msec, int fd, int flags);
+
+/**
+ * @brief Traditional fork() and exec() helper. If child is not
+ * deactivated within given \p timeout_msec then kill it with given
+ * signal.
+ *
+ * @param argv array of pointers to null-terminated strings that
+ * represent the argument list available to the new program. The first
+ * argument should point to the filename associated with the file
+ * being executed. The array of pointers must be terminated by a NULL pointer.
+ * @param envp specify the environment of the executed program via the
+ * argument envp. The envp argument is an array of pointers to
+ * null-terminated strings and must be terminated by a NULL pointer.
+ * @param timeout_msec timeout millisecond to prevent infinite
+ * waiting. If negative is given, the parent will not wait the
+ * child. In other word, the parent will return immediately. If 0 is
+ * given, parent will wait the child infinitly. And if positive value
+ * is given parent will wait given milliseconds and expired return
+ * -1. If the child is exit within the tiemout millisecond return with
+ * child exit code.
+ * @param sig signal to kill the child on timeout.
+ *
+ * @return exit code of child. It is fully depend on the child
+ * process. If the child exit with 1 then this function also return 1.
+ * Negative errno on error. -ETIME on timer expired.
+ */
+int do_fork_exec_kill(char *const argv[], char * const envp[], int64_t timeout_msec, int sig);
+
+/**
+ * @brief Traditional fork() and exec() helper.
+ *
+ * @param argv array of pointers to null-terminated strings that
+ * represent the argument list available to the new program. The first
+ * argument should point to the filename associated with the file
+ * being executed. The array of pointers must be terminated by a NULL pointer.
+ * @param envp specify the environment of the executed program via the
+ * argument envp. The envp argument is an array of pointers to
+ * null-terminated strings and must be terminated by a NULL pointer.
+ * @param timeout_msec timeout millisecond to prevent infinite
+ * waiting. If negative is given, the parent will not wait the
+ * child. In other word, the parent will return immediately. If 0 is
+ * given, parent will wait the child infinitly. And if positive value
+ * is given parent will wait given milliseconds and expired return
+ * -1. If the child is exit within the tiemout millisecond return with
+ * child exit code.
+ *
+ * @return exit code of child. It is fully depend on the child
+ * process. If the child exit with 1 then this function also return 1.
+ * Negative errno on error. -ETIME on timer expired.
+ */
+int do_fork_exec(char *const argv[], char * const envp[], int64_t timeout_msec);
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup TIME_UTIL_GROUP time util group
+ *
+ * @brief time utility libraries
+ * @{
+ */
+
+/** millisecond per second */
+#define MSEC_PER_SEC 1000ULL
+/** microsecond per second */
+#define USEC_PER_SEC ((uint64_t) 1000000ULL)
+/** microsecond per millisecond */
+#define USEC_PER_MSEC ((uint64_t) 1000ULL)
+/** nanosecond per second */
+#define NSEC_PER_SEC ((uint64_t) 1000000000ULL)
+/** nanosecond per microsecond */
+#define NSEC_PER_MSEC ((uint64_t) 1000000ULL)
+/** nanosecond per microsecond */
+#define NSEC_PER_USEC ((uint64_t) 1000ULL)
+
+/** microsecond per minute */
+#define USEC_PER_MINUTE ((uint64_t) (60ULL*USEC_PER_SEC))
+/** nanosecond per minute */
+#define NSEC_PER_MINUTE ((uint64_t) (60ULL*NSEC_PER_SEC))
+/** microsecond per hour */
+#define USEC_PER_HOUR ((uint64_t) (60ULL*USEC_PER_MINUTE))
+/** nanosecond per hour */
+#define NSEC_PER_HOUR ((uint64_t) (60ULL*NSEC_PER_MINUTE))
+/** microsecond per day */
+#define USEC_PER_DAY ((uint64_t) (24ULL*USEC_PER_HOUR))
+/** nanosecond per day */
+#define NSEC_PER_DAY ((uint64_t) (24ULL*NSEC_PER_HOUR))
+/** microsecond per week */
+#define USEC_PER_WEEK ((uint64_t) (7ULL*USEC_PER_DAY))
+/** nanosecond per week */
+#define NSEC_PER_WEEK ((uint64_t) (7ULL*NSEC_PER_DAY))
+/** microsecond per month */
+#define USEC_PER_MONTH ((uint64_t) (2629800ULL*USEC_PER_SEC))
+/** nanosecond per month */
+#define NSEC_PER_MONTH ((uint64_t) (2629800ULL*NSEC_PER_SEC))
+/** microsecond per year */
+#define USEC_PER_YEAR ((uint64_t) (31557600ULL*USEC_PER_SEC))
+/** nanosecond per year */
+#define NSEC_PER_YEAR ((uint64_t) (31557600ULL*NSEC_PER_SEC))
+
+/** frequently used time format string: 12:34 */
+#define HH_MM "%H:%M"
+/** frequently used time format string: 12:34:56 */
+#define HH_MM_SS "%H:%M:%S"
+
+/** frequently used time format string: 2015-01-23 */
+#define YYYY_MM_DD "%Y-%m-%d"
+/** frequently used time format string: 2015-01-23 12:34 */
+#define YYYY_MM_DD_HH_MM "%Y-%m-%d %H:%M"
+/** frequently used time format string: 2015-01-23 12:34:56 */
+#define YYYY_MM_DD_HH_MM_SS "%Y-%m-%d %H:%M:%S"
+/** frequently used time format string: 2015-01-23 12:34:56 KST */
+#define YYYY_MM_DD_HH_MM_SS_Z "%Y-%m-%d %H:%M:%S %Z"
+
+/** frequently used time format string: Fri 2015-01-23 */
+#define DOW_YYYY_MM_DD "%a %Y-%m-%d"
+/** frequently used time format string: Fri 2015-01-23 12:34 */
+#define DOW_YYYY_MM_DD_HH_MM "%a %Y-%m-%d %H:%M"
+/** frequently used time format string: Fri 2015-01-23 12:34:56 */
+#define DOW_YYYY_MM_DD_HH_MM_SS "%a %Y-%m-%d %H:%M:%S"
+/** frequently used time format string: Fri 2015-01-23 12:34:56 KST */
+#define DOW_YYYY_MM_DD_HH_MM_SS_Z "%a %Y-%m-%d %H:%M:%S %Z"
+
+/**
+ * @brief Convert time_t to given format time string.
+ *
+ * @param sec time second to convert
+ * @param format format string
+ * @param time string pointer to converted time is filled. On
+ * successful return, this value has to be free-ed by caller.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int sec_to_timestr(time_t sec, const char *format, char **time);
+
+/**
+ * @brief Convert time_t to \%a \%Y-\%m-\%d \%H:\%M:\%S \%Z format time string.
+ *
+ * @param sec time second to convert
+ * @param time string pointer to converted time is filled. On
+ * successful return, this value has to be free-ed by caller.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int sec_to_timestr_full(time_t sec, char **time);
+
+/**
+ * @brief Convert given format time string to time_t.
+ *
+ * @param format format string
+ * @param time time string to convert to time_t
+ * @param sec converted time_t
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int timestr_to_sec(const char *format, const char *time, time_t *sec);
+
+/**
+ * @brief Make struct timeval from millisecond
+ *
+ * @param msec millisecond to Convert
+ * @param tv struct timeval to be filled
+ */
+void msec_to_timeval(uint64_t msec, struct timeval *tv);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/libsystem/libsystem.pc.in b/src/libsystem/libsystem.pc.in
new file mode 100644
index 0000000..e942770
--- /dev/null
+++ b/src/libsystem/libsystem.pc.in
@@ -0,0 +1,17 @@
+# Package Information for pkg-config
+#
+# Copyright (c) 2016 Samsung Electronics Co., Ltd.
+# All rights reserved.
+#
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libsystem
+Description: system utility libraries
+Version: @PACKAGE_VERSION@
+Requires.private: @LIBSYSTEM_PC_REQUIRES@
+Cflags: @LIBSYSTEM_PC_CFLAGS@
+Libs: @LIBSYSTEM_PC_LIBS@
diff --git a/src/libsystem/proc-meminfo-lookup.gperf b/src/libsystem/proc-meminfo-lookup.gperf
new file mode 100644
index 0000000..1ca9fbe
--- /dev/null
+++ b/src/libsystem/proc-meminfo-lookup.gperf
@@ -0,0 +1,67 @@
+%{
+#include <assert.h>
+#include "proc.h"
+
+struct meminfo_mapping {
+ const char *name;
+ enum meminfo_id id;
+};
+typedef struct meminfo_mapping meminfo_mapping;
+%}
+meminfo_mapping;
+%language=ANSI-C
+%define slot-name name
+%define hash-function-name meminfo_mapping_hash
+%define lookup-function-name meminfo_mapping_lookup
+%readonly-tables
+%omit-struct-type
+%struct-type
+%includes
+%%
+MemTotal, MEMINFO_ID_MEM_TOTAL
+MemFree, MEMINFO_ID_MEM_FREE
+MemAvailable, MEMINFO_ID_MEM_AVAILABLE
+Buffers, MEMINFO_ID_BUFFERS
+Cached, MEMINFO_ID_CACHED
+SwapCached, MEMINFO_ID_SWAP_CACHED
+Active, MEMINFO_ID_ACTIVE
+Inactive, MEMINFO_ID_INACTIVE
+Active(anon), MEMINFO_ID_ACTIVE_ANON
+Inactive(anon), MEMINFO_ID_INACTIVE_ANON
+Active(file), MEMINFO_ID_ACTIVE_FILE
+Inactive(file), MEMINFO_ID_INACTIVE_FILE
+Unevictable, MEMINFO_ID_UNEVICTABLE
+Mlocked, MEMINFO_ID_MLOCKED
+HighTotal, MEMINFO_ID_HIGH_TOTAL
+HighFree, MEMINFO_ID_HIGH_FREE
+LowTotal, MEMINFO_ID_LOW_TOTAL
+LowFree, MEMINFO_ID_LOW_FREE
+SwapTotal, MEMINFO_ID_SWAP_TOTAL
+SwapFree, MEMINFO_ID_SWAP_FREE
+Dirty, MEMINFO_ID_DIRTY
+Writeback, MEMINFO_ID_WRITEBACK
+AnonPages, MEMINFO_ID_ANON_PAGES
+Mapped, MEMINFO_ID_MAPPED
+Shmem, MEMINFO_ID_SHMEM
+Slab, MEMINFO_ID_SLAB
+SReclaimable, MEMINFO_ID_SRECLAIMABLE
+SUnreclaim, MEMINFO_ID_SUNRECLAIM
+KernelStack, MEMINFO_ID_KERNEL_STACK
+PageTables, MEMINFO_ID_PAGE_TABLES
+NFS_Unstable, MEMINFO_ID_NFS_UNSTABLE
+Bounce, MEMINFO_ID_BOUNCE
+WritebackTmp, MEMINFO_ID_WRITEBACK_TMP
+CommitLimit, MEMINFO_ID_COMMIT_LIMIT
+Committed_AS, MEMINFO_ID_COMMITTED_AS
+VmallocTotal, MEMINFO_ID_VMALLOC_TOTAL
+VmallocUsed, MEMINFO_ID_VMALLOC_USED
+VmallocChunk, MEMINFO_ID_VMALLOC_CHUNK
+%%
+enum meminfo_id meminfo_string_to_id(const char *str)
+{
+ const struct meminfo_mapping *i;
+
+ assert(str);
+ i = meminfo_mapping_lookup(str, strlen(str));
+ return i ? i->id : MEMINFO_ID_INVALID;
+}
diff --git a/src/libsystem/proc-smaps-lookup.gperf b/src/libsystem/proc-smaps-lookup.gperf
new file mode 100644
index 0000000..7cf82e1
--- /dev/null
+++ b/src/libsystem/proc-smaps-lookup.gperf
@@ -0,0 +1,70 @@
+%{
+#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;
+}
diff --git a/src/libsystem/proc.c b/src/libsystem/proc.c
new file mode 100644
index 0000000..49ddfde
--- /dev/null
+++ b/src/libsystem/proc.c
@@ -0,0 +1,416 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * libsystem
+ *
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#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;
+ char *s, *w, *state;
+ size_t l, ll;
+ int r;
+
+ assert(buf);
+ assert(op);
+
+ r = read_one_line_from_path("/proc/cmdline", &cmdline);
+ if (r < 0)
+ return r;
+
+ ll = strlen(op);
+ FOREACH_WORD(w, l, cmdline, state)
+ if (strneq(op, w, ll)) {
+ s = new0(char, l - ll + 1);
+ if (!s)
+ return -ENOMEM;
+
+ strncpy(s, w + ll, l - ll + 1);
+
+ *buf = s;
+
+ return l - ll + 1;
+ }
+
+ return -ENOENT;
+}
+
+/* In old kernel, this symbol maybe NOT */
+#ifndef TASK_COMM_LEN
+#define TASK_COMM_LEN 16
+#endif
+
+int proc_pid_of(const char *pname) {
+ _cleanup_closedir_ DIR *dir = NULL;
+ struct dirent *de;
+ int r;
+
+ dir = opendir("/proc");
+ if (!dir)
+ return -errno;
+
+ FOREACH_DIRENT(de, dir, return -errno) {
+ _cleanup_free_ char *path = NULL;
+ _cleanup_free_ char *comm = NULL;
+
+ if (de->d_type != DT_DIR)
+ continue;
+
+ if (!is_number(de->d_name, strlen(de->d_name)))
+ continue;
+
+ r = asprintf(&path, "/proc/%s/comm", de->d_name);
+ if (r < 0)
+ return -ENOMEM;
+
+ r = read_one_line_from_path(path, &comm);
+ if (r < 0)
+ continue;
+
+ if (strneq(pname, comm, TASK_COMM_LEN - 1))
+ return atoi(de->d_name);
+ }
+
+ 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;
+}
+
+static const char* const meminfo_string_lookup[MEMINFO_ID_MAX] = {
+ [MEMINFO_ID_MEM_TOTAL] = "MemTotal",
+ [MEMINFO_ID_MEM_FREE] = "MemFree",
+ [MEMINFO_ID_MEM_AVAILABLE] = "MemAvailable",
+ [MEMINFO_ID_BUFFERS] = "Buffers",
+ [MEMINFO_ID_CACHED] = "Cached",
+ [MEMINFO_ID_SWAP_CACHED] = "SwapCached",
+ [MEMINFO_ID_ACTIVE] = "Active",
+ [MEMINFO_ID_INACTIVE] = "Inactive",
+ [MEMINFO_ID_ACTIVE_ANON] = "Active(anon)",
+ [MEMINFO_ID_INACTIVE_ANON] = "Inactive(anon)",
+ [MEMINFO_ID_ACTIVE_FILE] = "Active(file)",
+ [MEMINFO_ID_INACTIVE_FILE] = "Inactive(file)",
+ [MEMINFO_ID_UNEVICTABLE] = "Unevictable",
+ [MEMINFO_ID_MLOCKED] = "Mlocked",
+ [MEMINFO_ID_HIGH_TOTAL] = "HighTotal",
+ [MEMINFO_ID_HIGH_FREE] = "HighFree",
+ [MEMINFO_ID_LOW_TOTAL] = "LowTotal",
+ [MEMINFO_ID_LOW_FREE] = "LowFree",
+ [MEMINFO_ID_SWAP_TOTAL] = "SwapTotal",
+ [MEMINFO_ID_SWAP_FREE] = "SwapFree",
+ [MEMINFO_ID_DIRTY] = "Dirty",
+ [MEMINFO_ID_WRITEBACK] = "Writeback",
+ [MEMINFO_ID_ANON_PAGES] = "AnonPages",
+ [MEMINFO_ID_MAPPED] = "Mapped",
+ [MEMINFO_ID_SHMEM] = "Shmem",
+ [MEMINFO_ID_SLAB] = "Slab",
+ [MEMINFO_ID_SRECLAIMABLE] = "SReclaimable",
+ [MEMINFO_ID_SUNRECLAIM] = "SUnreclaim",
+ [MEMINFO_ID_KERNEL_STACK] = "KernelStack",
+ [MEMINFO_ID_PAGE_TABLES] = "PageTables",
+ [MEMINFO_ID_NFS_UNSTABLE] = "NFS_Unstable",
+ [MEMINFO_ID_BOUNCE] = "Bounce",
+ [MEMINFO_ID_WRITEBACK_TMP] = "WritebackTmp",
+ [MEMINFO_ID_COMMIT_LIMIT] = "CommitLimit",
+ [MEMINFO_ID_COMMITTED_AS] = "Committed_AS",
+ [MEMINFO_ID_VMALLOC_TOTAL] = "VmallocTotal",
+ [MEMINFO_ID_VMALLOC_USED] = "VmallocUsed",
+ [MEMINFO_ID_VMALLOC_CHUNK] = "VmallocChunk",
+};
+
+const char *meminfo_id_to_string(enum meminfo_id id) {
+ assert(id >= 0 && id < MEMINFO_ID_MAX);
+
+ return meminfo_string_lookup[id];
+}
+
+int proc_get_meminfo(struct meminfo *mi, enum meminfo_mask mask) {
+ _cleanup_fclose_ FILE *f = NULL;
+ enum meminfo_mask remain_mask = mask;
+ char buf[LINE_MAX];
+
+ assert(mi);
+
+ memset(mi, 0x0, sizeof(struct meminfo));
+
+ f = fopen("/proc/meminfo", "r");
+ if (!f)
+ return -errno;
+
+ if (remain_mask & MEMINFO_MASK_MEM_AVAILABLE)
+ remain_mask |= (MEMINFO_MASK_MEM_FREE | MEMINFO_MASK_CACHED);
+
+ while (remain_mask) {
+ unsigned int v = 0;
+ enum meminfo_id id;
+ size_t l;
+
+ if (!fgets(buf, sizeof(buf), f)) {
+ if (ferror(f))
+ return -errno;
+ break;
+ }
+
+ l = strcspn(buf, ":");
+ if (!l)
+ break;
+
+ buf[l] = 0;
+
+ id = meminfo_string_to_id(buf);
+ if (id < 0 || id >= MEMINFO_ID_MAX)
+ continue;
+
+ if (!(remain_mask & (1ULL << id)))
+ continue;
+
+ remain_mask &= ~((1ULL << id));
+
+ if (sscanf(buf + l + 1, "%d", &v) != 1)
+ break;
+
+ mi->value[id] = v;
+ }
+
+ if (remain_mask & MEMINFO_MASK_MEM_AVAILABLE) {
+ mi->value[MEMINFO_ID_MEM_AVAILABLE] = mi->value[MEMINFO_ID_MEM_FREE]
+ + mi->value[MEMINFO_ID_CACHED];
+ }
+
+ return 0;
+}
+
+void proc_buddyinfo_free(struct buddyinfo *bi) {
+ if (!bi)
+ return;
+
+ free(bi->zone);
+ free(bi);
+}
+
+int proc_get_buddyinfo(const char *zone, struct buddyinfo **bi) {
+ _cleanup_fclose_ FILE *f = NULL;
+ char buf[LINE_MAX];
+
+ assert(zone);
+ assert(bi);
+
+ f = fopen("/proc/buddyinfo", "re");
+ if (!f)
+ return -errno;
+
+ for (;;) {
+ _cleanup_buddyinfo_free_ struct buddyinfo *b = NULL;
+ int n;
+
+ if (!fgets(buf, sizeof(buf), f)) {
+ if (ferror(f))
+ return -errno;
+
+ break;
+ }
+
+ b = new0(struct buddyinfo, 1);
+ if (!b)
+ return -ENOMEM;
+
+ n = sscanf(buf, "Node %d, zone %m[^ ] %d %d %d %d %d %d %d %d %d %d %d",
+ &b->node,
+ &b->zone,
+ &b->page[PAGE_4K],
+ &b->page[PAGE_8K],
+ &b->page[PAGE_16K],
+ &b->page[PAGE_32K],
+ &b->page[PAGE_64K],
+ &b->page[PAGE_128K],
+ &b->page[PAGE_256K],
+ &b->page[PAGE_512K],
+ &b->page[PAGE_1M],
+ &b->page[PAGE_2M],
+ &b->page[PAGE_4M]);
+ if (n != 13)
+ break;
+
+ if (!streq(zone, b->zone))
+ continue;
+
+ *bi = b;
+ b = NULL;
+
+ return 0;
+ }
+
+ return -ENODATA;
+}
diff --git a/src/libsystem/proc.h b/src/libsystem/proc.h
new file mode 100644
index 0000000..995cd00
--- /dev/null
+++ b/src/libsystem/proc.h
@@ -0,0 +1,437 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * libsystem
+ *
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file proc.h
+ *
+ * procfs utility library
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#pragma once
+
+#include <sys/types.h>
+#include "libsystem.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup PROC_GROUP proc group
+ *
+ * @brief A set utility library for /proc. Some of library functions
+ * are only able to be successful root uid with security permissions.
+ *
+ * @{
+ */
+
+/**
+ * @brief Get string with operator from /proc/cmdline. If foo=bar is
+ * included in /proc/cmdline and want to get the bar, then:
+ * \code{.c}
+ char *buf;
+
+ proc_cmdline_get_str(&buf, "foo=");
+ * \endcode
+ *
+ * @param buf The value string is filled to here. This value has to be
+ * free-ed by caller.
+ * @param op An operator string.
+ *
+ * @return Result string. This value has to be free-ed by caller.
+ */
+ssize_t proc_cmdline_get_str(char **buf, const char *op);
+
+/**
+ * @brief Get PID of process.
+ *
+ * @param pname Process name.
+ *
+ * @return PID on successful find. If not found, 0 is returned. And
+ * -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);
+
+/**
+ * meminfo id
+ */
+enum meminfo_id {
+ MEMINFO_ID_INVALID = -1,
+ MEMINFO_ID_MEM_TOTAL = 0,
+ MEMINFO_ID_MEM_FREE,
+ MEMINFO_ID_MEM_AVAILABLE,
+ MEMINFO_ID_BUFFERS,
+ MEMINFO_ID_CACHED,
+ MEMINFO_ID_SWAP_CACHED,
+ MEMINFO_ID_ACTIVE,
+ MEMINFO_ID_INACTIVE,
+ MEMINFO_ID_ACTIVE_ANON,
+ MEMINFO_ID_INACTIVE_ANON,
+ MEMINFO_ID_ACTIVE_FILE,
+ MEMINFO_ID_INACTIVE_FILE,
+ MEMINFO_ID_UNEVICTABLE,
+ MEMINFO_ID_MLOCKED,
+ MEMINFO_ID_HIGH_TOTAL,
+ MEMINFO_ID_HIGH_FREE,
+ MEMINFO_ID_LOW_TOTAL,
+ MEMINFO_ID_LOW_FREE,
+ MEMINFO_ID_SWAP_TOTAL,
+ MEMINFO_ID_SWAP_FREE,
+ MEMINFO_ID_DIRTY,
+ MEMINFO_ID_WRITEBACK,
+ MEMINFO_ID_ANON_PAGES,
+ MEMINFO_ID_MAPPED,
+ MEMINFO_ID_SHMEM,
+ MEMINFO_ID_SLAB,
+ MEMINFO_ID_SRECLAIMABLE,
+ MEMINFO_ID_SUNRECLAIM,
+ MEMINFO_ID_KERNEL_STACK,
+ MEMINFO_ID_PAGE_TABLES,
+ MEMINFO_ID_NFS_UNSTABLE,
+ MEMINFO_ID_BOUNCE,
+ MEMINFO_ID_WRITEBACK_TMP,
+ MEMINFO_ID_COMMIT_LIMIT,
+ MEMINFO_ID_COMMITTED_AS,
+ MEMINFO_ID_VMALLOC_TOTAL,
+ MEMINFO_ID_VMALLOC_USED,
+ MEMINFO_ID_VMALLOC_CHUNK,
+ MEMINFO_ID_MAX,
+};
+
+/**
+ * meminfo mask
+ */
+enum meminfo_mask {
+ MEMINFO_MASK_MEM_TOTAL = 1ULL << MEMINFO_ID_MEM_TOTAL,
+ MEMINFO_MASK_MEM_FREE = 1ULL << MEMINFO_ID_MEM_FREE,
+ MEMINFO_MASK_MEM_AVAILABLE = 1ULL << MEMINFO_ID_MEM_AVAILABLE,
+ MEMINFO_MASK_BUFFERS = 1ULL << MEMINFO_ID_BUFFERS,
+ MEMINFO_MASK_CACHED = 1ULL << MEMINFO_ID_CACHED,
+ MEMINFO_MASK_SWAP_CACHED = 1ULL << MEMINFO_ID_SWAP_CACHED,
+ MEMINFO_MASK_ACTIVE = 1ULL << MEMINFO_ID_ACTIVE,
+ MEMINFO_MASK_INACTIVE = 1ULL << MEMINFO_ID_INACTIVE,
+ MEMINFO_MASK_ACTIVE_ANON = 1ULL << MEMINFO_ID_ACTIVE_ANON,
+ MEMINFO_MASK_INACTIVE_ANON = 1ULL << MEMINFO_ID_INACTIVE_ANON,
+ MEMINFO_MASK_ACTIVE_FILE = 1ULL << MEMINFO_ID_ACTIVE_FILE,
+ MEMINFO_MASK_INACTIVE_FILE = 1ULL << MEMINFO_ID_INACTIVE_FILE,
+ MEMINFO_MASK_UNEVICTABLE = 1ULL << MEMINFO_ID_UNEVICTABLE,
+ MEMINFO_MASK_MLOCKED = 1ULL << MEMINFO_ID_MLOCKED,
+ MEMINFO_MASK_HIGH_TOTAL = 1ULL << MEMINFO_ID_HIGH_TOTAL,
+ MEMINFO_MASK_HIGH_FREE = 1ULL << MEMINFO_ID_HIGH_FREE,
+ MEMINFO_MASK_LOW_TOTAL = 1ULL << MEMINFO_ID_LOW_TOTAL,
+ MEMINFO_MASK_LOW_FREE = 1ULL << MEMINFO_ID_LOW_FREE,
+ MEMINFO_MASK_SWAP_TOTAL = 1ULL << MEMINFO_ID_SWAP_TOTAL,
+ MEMINFO_MASK_SWAP_FREE = 1ULL << MEMINFO_ID_SWAP_FREE,
+ MEMINFO_MASK_DIRTY = 1ULL << MEMINFO_ID_DIRTY,
+ MEMINFO_MASK_WRITEBACK = 1ULL << MEMINFO_ID_WRITEBACK,
+ MEMINFO_MASK_ANON_PAGES = 1ULL << MEMINFO_ID_ANON_PAGES,
+ MEMINFO_MASK_MAPPED = 1ULL << MEMINFO_ID_MAPPED,
+ MEMINFO_MASK_SHMEM = 1ULL << MEMINFO_ID_SHMEM,
+ MEMINFO_MASK_SLAB = 1ULL << MEMINFO_ID_SLAB,
+ MEMINFO_MASK_SRECLAIMABLE = 1ULL << MEMINFO_ID_SRECLAIMABLE,
+ MEMINFO_MASK_SUNRECLAIM = 1ULL << MEMINFO_ID_SUNRECLAIM,
+ MEMINFO_MASK_KERNEL_STACK = 1ULL << MEMINFO_ID_KERNEL_STACK,
+ MEMINFO_MASK_PAGE_TABLES = 1ULL << MEMINFO_ID_PAGE_TABLES,
+ MEMINFO_MASK_NFS_UNSTABLE = 1ULL << MEMINFO_ID_NFS_UNSTABLE,
+ MEMINFO_MASK_BOUNCE = 1ULL << MEMINFO_ID_BOUNCE,
+ MEMINFO_MASK_WRITEBACK_TMP = 1ULL << MEMINFO_ID_WRITEBACK_TMP,
+ MEMINFO_MASK_COMMIT_LIMIT = 1ULL << MEMINFO_ID_COMMIT_LIMIT,
+ MEMINFO_MASK_COMMITTED_AS = 1ULL << MEMINFO_ID_COMMITTED_AS,
+ MEMINFO_MASK_VMALLOC_TOTAL = 1ULL << MEMINFO_ID_VMALLOC_TOTAL,
+ MEMINFO_MASK_VMALLOC_USED = 1ULL << MEMINFO_ID_VMALLOC_USED,
+ MEMINFO_MASK_VMALLOC_CHUNK = 1ULL << MEMINFO_ID_VMALLOC_CHUNK,
+ MEMINFO_MASK_ALL = (1ULL << MEMINFO_ID_MAX) - 1,
+};
+
+/**
+ * meminfo
+ */
+struct meminfo {
+ unsigned int value[MEMINFO_ID_MAX];
+};
+
+/**
+ * @brief Convert meminfo id to string
+ *
+ * @param id meminfo id
+ *
+ * @return converted string
+ */
+const char *meminfo_id_to_string(enum meminfo_id id);
+
+/**
+ * @brief Convert meminfo string to id
+ *
+ * @param str meminfo string
+ *
+ * @return converted id
+ */
+enum meminfo_id meminfo_string_to_id(const char *str);
+
+/**
+ * @brief Get system memory info(/proc/meminfo)
+ * @code{.c}
+ unsigned int get_mem_available(void)
+ {
+ struct meminfo mi;
+
+ proc_get_meminfo(&mi, MEMINFO_MASK_MEM_AVAILABLE);
+ }
+ * @endcode
+ *
+ * @param mi parsed meminfo struct.
+ * @param mask mask to get meminfo.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int proc_get_meminfo(struct meminfo *mi, enum meminfo_mask mask);
+
+/**
+ * /proc/buddyinfo page index
+ */
+enum {
+ PAGE_4K = 0,
+ PAGE_8K,
+ PAGE_16K,
+ PAGE_32K,
+ PAGE_64K,
+ PAGE_128K,
+ PAGE_256K,
+ PAGE_512K,
+ PAGE_1M,
+ PAGE_2M,
+ PAGE_4M,
+ PAGE_MAX,
+};
+
+/**
+ * A zone buddy info
+ */
+struct buddyinfo {
+ /**
+ * Zone name
+ */
+ char *zone;
+ /**
+ * Node number
+ */
+ int node;
+ /**
+ * Each pages size
+ */
+ int page[PAGE_MAX];
+};
+
+/**
+ * @brief free struct buddyinfo
+ *
+ * @param bi a buddyinfo
+ */
+void proc_buddyinfo_free(struct buddyinfo *bi);
+
+static inline void buddyinfo_freep(struct buddyinfo **bi)
+{
+ proc_buddyinfo_free(*bi);
+}
+
+/**
+ * Declare struct buddyinfo with cleanup attribute. Allocated struct
+ * buddyinfo is destroyed on going out the scope.
+ */
+#define _cleanup_buddyinfo_free_ _cleanup_(buddyinfo_freep)
+
+/**
+ * @brief Parse a zone in /proc/buddyinfo
+ *
+ * @param zone A zone to parse such like "Normal"
+ *
+ * @param bi Allocated and parsed buddyinfo for given zone. This value
+ * has to be destroyed by caller. #_cleanup_buddyinfo_free_ is useful
+ * to make autofree this value.
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int proc_get_buddyinfo(const char *zone, struct buddyinfo **bi);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/libsystem/time-util.c b/src/libsystem/time-util.c
new file mode 100644
index 0000000..28ac86f
--- /dev/null
+++ b/src/libsystem/time-util.c
@@ -0,0 +1,87 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * time-util.c
+ *
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "libsystem.h"
+
+#define TIME_BUF_LEN 30
+
+int sec_to_timestr(time_t sec, const char *format, char **time) {
+ struct tm tm;
+ char *buf;
+ size_t l;
+
+ assert(format);
+ assert(time);
+
+ localtime_r(&sec, &tm);
+
+ buf = new0(char, TIME_BUF_LEN);
+ if (!buf)
+ return -ENOMEM;
+
+ l = strftime(buf, TIME_BUF_LEN, format, &tm);
+ if (l <= 0) {
+ free(buf);
+ return -EINVAL;
+ }
+
+ *time = buf;
+
+ return 0;
+}
+
+int sec_to_timestr_full(time_t sec, char **time) {
+ assert(time);
+
+ return sec_to_timestr(sec, DOW_YYYY_MM_DD_HH_MM_SS_Z, time);
+}
+
+int timestr_to_sec(const char *format, const char *time, time_t *sec) {
+ struct tm tm;
+ char *ret;
+
+ assert(format);
+ assert(time);
+ assert(sec);
+
+ memset(&tm, 0, sizeof(struct tm));
+ ret = strptime(time, format, &tm);
+ if ((ret - time) < strlen(time))
+ return -EINVAL;
+
+ *sec = mktime(&tm);
+
+ return 0;
+}
+
+void msec_to_timeval(uint64_t msec, struct timeval *tv) {
+ assert(tv);
+
+ tv->tv_sec = msec / MSEC_PER_SEC;
+ tv->tv_usec = (msec % MSEC_PER_SEC) * USEC_PER_MSEC;
+}