Add support of reading 'smaps' files 01/143101/5
authorVyacheslav Cherkashin <v.cherkashin@samsung.com>
Tue, 8 Aug 2017 06:45:27 +0000 (09:45 +0300)
committerVyacheslav Cherkashin <v.cherkashin@samsung.com>
Mon, 21 Aug 2017 16:23:38 +0000 (19:23 +0300)
To read smaps (/proc/*/smaps) it uses swap_memd service, because
swap_manager dont't have needed permissions.

Change-Id: I0d01fda860c5d2167739e18c6cde60fd4cc862f0
Signed-off-by: Vyacheslav Cherkashin <v.cherkashin@samsung.com>
20 files changed:
daemon/Makefile
daemon/cpp/memd/memd_client.cpp [new file with mode: 0644]
daemon/cpp/memd/memd_client.h [new file with mode: 0644]
daemon/cpp/memd/memd_client_c.cpp [new file with mode: 0644]
daemon/cpp/memd/memd_client_c.h [new file with mode: 0644]
daemon/daemon.h
daemon/extern_service.c
daemon/extern_service.h
daemon/main.c
daemon/sys_stat.c
packaging/swap-manager.manifest
packaging/swap-manager.spec
src/CMakeLists.txt
src/memd/CMakeLists.txt [new file with mode: 0644]
src/memd/protocol/memd.h [new file with mode: 0644]
src/memd/protocol/memd_metadata.proto [new file with mode: 0644]
src/memd/src/main.cpp [new file with mode: 0644]
systemd/swap_memd.path [new file with mode: 0644]
systemd/swap_memd.service [new file with mode: 0644]
systemd/swap_memd.socket [new file with mode: 0644]

index d73ec97..bf3285c 100644 (file)
@@ -120,7 +120,10 @@ SRC_CPP := \
        cpp/elf/Elf.cpp \
 \
        cpp/auxd/auxd_client.cpp \
-       cpp/auxd/auxd_client_c.cpp
+       cpp/auxd/auxd_client_c.cpp \
+\
+       cpp/memd/memd_client.cpp \
+       cpp/memd/memd_client_c.cpp
 
 
 TARGET = swap_manager
@@ -234,10 +237,20 @@ $(GENERATED_DIR):
 
 # AUXC
 AUX_PROTOBUF_DIR = ../src/auxd/protocol
-protobuf_generated:
+protobuf_generated_auxd:
        protoc --cpp_out=$(GENERATED_DIR) --proto_path=$(AUX_PROTOBUF_DIR) $(AUX_PROTOBUF_DIR)/auxd_metadata.proto
 
 SRC_CPP += $(GENERATED_DIR)/auxd_metadata.pb.cc
+
+# MEMD
+MEMD_PROTOBUF_DIR = ../src/memd/protocol
+protobuf_generated_memd:
+       protoc --cpp_out=$(GENERATED_DIR) --proto_path=$(MEMD_PROTOBUF_DIR) $(MEMD_PROTOBUF_DIR)/memd_metadata.proto
+
+SRC_CPP += $(GENERATED_DIR)/memd_metadata.pb.cc
+
+
+protobuf_generated: protobuf_generated_auxd protobuf_generated_memd
 LDFLAGS += -lprotobuf-lite -lswaputils -L../build/lib
 
 
diff --git a/daemon/cpp/memd/memd_client.cpp b/daemon/cpp/memd/memd_client.cpp
new file mode 100644 (file)
index 0000000..d4cd8d8
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *      Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * 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.
+ *
+ * Contributors:
+ * - Samsung RnD Institute Russia
+ *
+ */
+
+
+#include "memd_client.h"
+#include <memory>
+#include <stdexcept>
+#include <utils/unix/unix_client.h>
+#include <utils/socket.h>
+
+#include <memd/protocol/memd.h>
+#include <memd_metadata.pb.h>
+
+
+template <class In, class Out>
+void do_request(IPC::Client &client, unsigned int id, const In &in_type, Out &out_type)
+{
+    std::string in;
+
+    if (!in_type.SerializeToString(&in))
+        throw std::runtime_error("Cannot serialize");
+
+    std::string out;
+    client.request(id, in, out);
+    if (!out_type.ParseFromString(out))
+        throw std::runtime_error("Cannot deserialize");
+}
+
+static int do_read_file(IPC::Client &client, const std::string &path,
+                        std::string &out, std::string &err)
+{
+    MEMD::ReadFileRequest request;
+    request.set_path(path);
+
+    MEMD::ReadFileAnswer answer;
+    do_request(client, MEMD_READ_FILE, request, answer);
+
+    out = answer.data();
+    err = answer.error();
+    return answer.success();
+}
+
+
+MemdClient::MemdClient(const std::string &socket_path) :
+    socket_path_(socket_path)
+{
+    std::unique_ptr<Unix::Client> unix_client(new Unix::Client());
+    Socket *socket = unix_client->connect(socket_path);
+    std::unique_ptr<IPC::Client> ipc_client(new IPC::Client(socket));
+
+    unix_client_ = std::move(unix_client);
+    ipc_client_ = std::move(ipc_client);
+}
+
+bool MemdClient::read_file(const std::string &path, std::string &out)
+{
+    std::string err;
+    int ret = do_read_file(*ipc_client_.get(), path, out, err);
+    if (!ret)
+        throw std::runtime_error(err);
+
+    return ret;
+}
diff --git a/daemon/cpp/memd/memd_client.h b/daemon/cpp/memd/memd_client.h
new file mode 100644 (file)
index 0000000..3287589
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *      Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * 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.
+ *
+ * Contributors:
+ * - Samsung RnD Institute Russia
+ *
+ */
+
+
+#ifndef MEMD_CLIENT_H
+#define MEMD_CLIENT_H
+
+
+#include <string>
+#include <memory>
+#include <utils/socket.h>
+#include <utils/unix/unix_client.h>
+#include <utils/ipc/ipc_client.h>
+
+
+class MemdClient
+{
+public:
+    MemdClient(const std::string &socket_path);
+
+    bool read_file(const std::string &path, std::string &out);
+
+private:
+    std::string socket_path_;
+
+    std::unique_ptr<IPC::Client> ipc_client_;
+    std::unique_ptr<Unix::Client> unix_client_;
+};
+
+
+#endif // MEMD_CLIENT_H
diff --git a/daemon/cpp/memd/memd_client_c.cpp b/daemon/cpp/memd/memd_client_c.cpp
new file mode 100644 (file)
index 0000000..400680c
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *      Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * 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.
+ *
+ * Contributors:
+ * - Samsung RnD Institute Russia
+ *
+ */
+
+
+#include "memd_client_c.h"
+#include "memd_client.h"
+#include <swap_debug.h>
+#include <string>
+
+
+struct memd_client {
+    MemdClient *client;
+    std::string err;
+};
+
+
+struct memd_buffer {
+    std::string data;
+};
+
+
+struct memd_client *memd_client_create(void)
+{
+    struct memd_client *c = nullptr;
+
+    try {
+        c = new memd_client();
+        c->client = nullptr;
+    } catch (...) {
+        LOGE("Unknown error\n");
+    }
+
+    return c;
+}
+
+void memd_client_destroy(struct memd_client *c)
+{
+    delete c->client;
+    delete c;
+}
+
+int memd_client_init(struct memd_client *c, const char *socket_path)
+{
+    c->err.clear();
+
+    if (c->client) {
+        c->err = "Already init";
+        return -EBUSY;
+    }
+
+    try {
+        c->client = new MemdClient(socket_path);
+        return 0;
+    } catch (const std::runtime_error &err) {
+        c->err = err.what();
+    } catch (...) {
+        c->err = "Unknown error";
+    }
+
+    return -EINVAL;
+}
+
+void memd_client_uninit(struct memd_client *c)
+{
+    delete c->client;
+    c->client = nullptr;
+}
+
+bool memd_client_read_file(struct memd_client *c, const char *path,
+                           struct memd_buffer *b /* out */)
+{
+    c->err.clear();
+
+    try {
+        return c->client->read_file(path, b->data);
+    } catch (const std::runtime_error &err) {
+        c->err = err.what();
+    } catch (...) {
+        c->err = "Unknown error";
+    }
+
+    return false;
+}
+
+
+
+struct memd_buffer *memd_buffer_create(void)
+{
+    struct memd_buffer *b = nullptr;
+
+    try {
+        b = new memd_buffer();
+    } catch (...) {
+        LOGE("Unknown error\n");
+    }
+
+    return b;
+}
+
+void memd_buffer_destroy(struct memd_buffer *b)
+{
+    delete b;
+}
+
+size_t memd_buffer_size(struct memd_buffer *b)
+{
+    return b->data.size();
+}
+
+const char *memd_buffer_data(struct memd_buffer *b)
+{
+    return b->data.data();
+}
+
diff --git a/daemon/cpp/memd/memd_client_c.h b/daemon/cpp/memd/memd_client_c.h
new file mode 100644 (file)
index 0000000..9ec62af
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *      Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * 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.
+ *
+ * Contributors:
+ * - Samsung RnD Institute Russia
+ *
+ */
+
+
+#ifndef MEMD_CLIENT_C_H
+#define MEMD_CLIENT_C_H
+
+
+#include <stddef.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+struct memd_client;
+struct memd_buffer;
+
+struct memd_client *memd_client_create(void);
+void memd_client_destroy(struct memd_client *c);
+
+int memd_client_init(struct memd_client *c, const char *socket_path);
+void memd_client_uninit(struct memd_client *c);
+
+bool memd_client_read_file(struct memd_client *c, const char *path,
+                           struct memd_buffer *b /* out */);
+
+
+struct memd_buffer *memd_buffer_create(void);
+void memd_buffer_destroy(struct memd_buffer *b);
+
+size_t memd_buffer_size(struct memd_buffer *b);
+const char *memd_buffer_data(struct memd_buffer *b);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // MEMD_CLIENT_C_H
index 4b482c0..872c749 100644 (file)
@@ -120,6 +120,7 @@ typedef struct
 
 
 struct auxd_client;
+struct memd_client;
 
 typedef struct
 {
@@ -142,6 +143,7 @@ typedef struct
        char appPath[128]; // application executable path
 
        struct auxd_client *auxd_client;
+       struct memd_client *memd_client;
 } __da_manager;
 
 extern __da_manager manager;
index f71f136..07586d6 100644 (file)
@@ -5,6 +5,7 @@
 
 static const int ES_TIMEOUT = 30;
 static const char CMD_AUXD_PATH[] = "/tmp/swap/auxd";
+static const char CMD_MEMD_PATH[] = "/tmp/swap/memd";
 static const char CMD_MODULE_PATH[] = "/tmp/swap/module";
 
 
@@ -33,6 +34,11 @@ int es_auxd_run(void)
        return run_service(CMD_AUXD_PATH, "", ES_TIMEOUT);
 }
 
+int es_memd_run(void)
+{
+       return run_service(CMD_MEMD_PATH, "", ES_TIMEOUT);
+}
+
 int es_modules_load(void)
 {
        return run_service(CMD_MODULE_PATH, "load", ES_TIMEOUT);
index a23962c..d5eafe5 100644 (file)
@@ -29,6 +29,9 @@
 /* auxd */
 int es_auxd_run(void);
 
+/* memd */
+int es_memd_run(void);
+
 /* modules */
 int es_modules_load(void);
 int es_modules_unload(void);
index 325177e..716e1b7 100644 (file)
@@ -52,6 +52,7 @@
 #include "smack.h"
 #include "extern_service.h"
 #include "cpp/auxd/auxd_client_c.h"
+#include "cpp/memd/memd_client_c.h"
 #include "cpp/features/feature_manager_c.h"
 
 #define SINGLETON_LOCKFILE                     "/tmp/da_manager.lock"
@@ -134,6 +135,37 @@ static void manager_auxd_client_uninit(__da_manager *m)
 }
 
 
+static int manager_memd_client_init(__da_manager *m)
+{
+       const char MEMD_SOCKET_PATH[] = "/tmp/swap_memd.socket";
+
+       int ret;
+       struct memd_client *c;
+
+       c = memd_client_create();
+       if (!c)
+               return -ENOMEM;
+
+       ret = memd_client_init(c, MEMD_SOCKET_PATH);
+       if (ret) {
+               memd_client_destroy(c);
+               return ret;
+       }
+
+       m->memd_client = c;
+       LOGI("Connect to socket '%s'\n", MEMD_SOCKET_PATH);
+
+       return ret;
+}
+
+static void manager_memd_client_uninit(__da_manager *m)
+{
+       memd_client_uninit(m->memd_client);
+       memd_client_destroy(m->memd_client);
+
+       m->memd_client = NULL;
+}
+
 // =============================================================================
 // util functions
 // =============================================================================
@@ -389,12 +421,24 @@ static int initializeManager(FILE *portfile)
                return -1;
        }
 
+       ret = es_memd_run();
+       if (ret) {
+               LOGE("Cannot run memd, ret=%d\n", ret);
+               return -1;
+       }
+
        ret = manager_auxd_client_init(&manager);
        if (ret) {
                LOGE("Cannot init aux client, ret=%d\n", ret);
                return -1;
        }
 
+       ret = manager_memd_client_init(&manager);
+       if (ret) {
+               LOGE("Cannot init memd client, ret=%d\n", ret);
+               return -1;
+       }
+
        if (ks_init()) {
                LOGE("Cannot init kernel space");
                return -1;
@@ -464,6 +508,7 @@ static int finalizeManager()
                close(manager.host.data_socket);
        }
 
+       manager_memd_client_uninit(&manager);
        manager_auxd_client_uninit(&manager);
 
        LOGI("return\n");
index 0747c72..71cf4a3 100644 (file)
@@ -56,6 +56,7 @@
 #include "device_vconf.h"
 #include "device_camera.h"
 #include "swap_debug.h"
+#include <cpp/memd/memd_client_c.h>
 
 // defines for runtime environment
 #define FOR_EACH_CPU
@@ -745,47 +746,35 @@ static int smaps_lcnt = 0;
 
 #define BUF_INC_SIZE    (512 * 1024)        /* maximal SMAPS I saw 2 MB     */
 /* reads file contents into memory */
-static char* cread(const char* path)
+static char *cread(const char *path, size_t *size)
 {
-       /* once allocated area for reads */
-       static char*    text = NULL;
-       static size_t   size = 0;
+       char *buf = NULL;
 
-       ssize_t ret;
-       char*   ptr = text;
-       size_t  cap = size;
-       int     fd  = open(path, O_RDONLY);
-
-       if (fd < 0) {
+       struct memd_buffer *b = memd_buffer_create();
+       if (!b)
                return NULL;
-       }
 
-       do {
-               /* ensure we have enough space */
-               if (cap == 0) {
-                       ptr = (char*)realloc(text, size + BUF_INC_SIZE);
-                       if (ptr == NULL) {
-                               ret = -1;
-                               break;
-                       }
+       if (!memd_client_read_file(manager.memd_client, path, b))
+               goto free_all;
 
-                       text  = ptr;
-                       ptr   = text + size;
-                       cap   = BUF_INC_SIZE;
-                       size += BUF_INC_SIZE;
-               }
-               ret = read(fd, ptr, cap);
-               if (ret == 0) {
-                       *ptr = 0;
-               } else if (ret > 0) {
-                       cap -= ret;
-                       ptr += ret;
-               }
-       } while (ret > 0);
-       close(fd);
+       size_t sz = memd_buffer_size(b);
+       if (!sz)
+               goto free_all;
+
+       buf = malloc(sz + 1);
+       if (!buf)
+               goto free_all;
 
-       return (ret < 0 ? NULL : text);
-} /* cread */
+       memcpy(buf, memd_buffer_data(b), sz);
+       buf[sz] = '\0';
+       if (size)
+               *size = sz;
+
+free_all:
+       memd_buffer_destroy(b);
+
+       return buf;
+}
 
 /* like fgets/gets but adjusting contents pointer */
 static inline char* cgets(char** contents)
@@ -877,7 +866,7 @@ int get_smaps_lcnt(void)
        int major, minor;
        char flags[4];
 
-       buf_start = cread(cmd);
+       buf_start = cread(cmd, NULL);
        if (buf_start == NULL)
                goto error;
 
@@ -957,13 +946,45 @@ int read_mapinfo_section(FILE* fp, proc_t *proc)
 }
 
 
+static bool save_to_tmpfile(char *path, int suffixlen,
+                           const char *data, size_t len)
+{
+       int fd = mkstemps(path, suffixlen);
+       if (fd == -1) {
+               LOGE("Cannot make temp file, errno=%d\n", errno);
+               return false;
+       }
+
+       /* TODO: check return value */
+       write(fd, data, len);
+       close(fd);
+
+       return true;
+}
+
+static bool save_request_to_tmpfile(const char *in_path,
+                                   char *out_path, int out_suffixlen)
+{
+       size_t size;
+       char *buf = cread(in_path, &size);
+       if (!buf) {
+               LOGE("Cannot 'cread' '%s' file\n", in_path);
+               return false;
+       }
+
+       bool ret = save_to_tmpfile(out_path, out_suffixlen, buf, size);
+       free(buf);
+
+       return ret;
+}
+
 // return 0 for normal case
 // return negative value for error case
 static int parse_proc_smaps_file_bypid(char *path, proc_t *P)
 {
 #define MIN_SMAP_BLOCKLINE     50
 
-       char filename[PROCPATH_MAX];
+       char path_smaps[PROCPATH_MAX];
        proc_t proc_tmp;
        FILE* fp;
 
@@ -975,10 +996,21 @@ static int parse_proc_smaps_file_bypid(char *path, proc_t *P)
        P->gem_pss = 0;
 
        // read from smaps file
-       snprintf(filename, sizeof(filename), "%s/smaps", path);
-       fp = fopen(filename, "r");
+       snprintf(path_smaps, sizeof(path_smaps), "%s/smaps", path);
+
+       /* FIXME: rework this code (save to file, read file, remove file) */
+       const int tmp_suffixlen = 6;
+       char tmp_path[] = "/tmp/swap_smaps_XXXXXX.smaps";
+       bool ret = save_request_to_tmpfile(path_smaps, tmp_path, tmp_suffixlen);
+       if (!ret) {
+               LOGE("Cannot save smaps to tmpfile\n");
+               return -1;
+       }
 
+       fp = fopen(tmp_path, "r");
        if(fp == NULL){
+               LOGE("Open '%s'\n", tmp_path);
+               remove(tmp_path);
                return -1;
        }
 
@@ -1006,6 +1038,7 @@ static int parse_proc_smaps_file_bypid(char *path, proc_t *P)
        P->sh_mem_dirty *= 1024;
 
        fclose(fp);
+       remove(tmp_path);
 
        return 0;
 }
index 9ac1043..4771d21 100644 (file)
@@ -10,6 +10,9 @@
     <!-- swap_auxd -->
     <filesystem path="/usr/bin/swap_auxd" label="System" exec_label="User"/>
 
+    <!-- swap_memd -->
+    <filesystem path="/usr/bin/swap_memd" label="System" exec_label="User"/>
+
     <!-- libswaputils.so -->
     <filesystem path="/usr/lib/libswaputils.so" label="_"/>
 
index 9d9383d..fb74f18 100644 (file)
@@ -172,6 +172,12 @@ install -m 0644 systemd/swap_auxd.socket %{buildroot}%{_unitdir}/
 install -m 0644 systemd/swap_auxd.path %{buildroot}%{_unitdir}/
 ln -s ../swap_auxd.path %{buildroot}%{_unitdir}/multi-user.target.wants/
 
+#   swap_memd
+install -m 0644 systemd/swap_memd.service %{buildroot}%{_unitdir}/
+install -m 0644 systemd/swap_memd.socket %{buildroot}%{_unitdir}/
+install -m 0644 systemd/swap_memd.path %{buildroot}%{_unitdir}/
+ln -s ../swap_memd.path %{buildroot}%{_unitdir}/multi-user.target.wants/
+
 # tmpfiles.d
 mkdir -p %{buildroot}%{_tmpfilesdir}
 install -m 0666 systemd/swap.conf %{buildroot}%{_tmpfilesdir}/swap.conf
@@ -231,6 +237,12 @@ systemctl daemon-reload
 %{_unitdir}/swap_auxd.path
 %{_unitdir}/multi-user.target.wants/swap_auxd.path
 
+# swap_memd
+%{_unitdir}/swap_memd.socket
+%{_unitdir}/swap_memd.service
+%{_unitdir}/swap_memd.path
+%{_unitdir}/multi-user.target.wants/swap_memd.path
+
 %{_tmpfilesdir}/swap.conf
 %{_udevrulesdir}/99-swap_dev.rules
 
@@ -259,4 +271,7 @@ systemctl daemon-reload
 # auxd
 %{_bindir}/swap_auxd
 
+# swap_memd
+%{_bindir}/swap_memd
+
 %changelog
index 16ac84e..e43b3e1 100644 (file)
@@ -9,3 +9,4 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
 
 add_subdirectory(utils)
 add_subdirectory(auxd)
+add_subdirectory(memd)
diff --git a/src/memd/CMakeLists.txt b/src/memd/CMakeLists.txt
new file mode 100644 (file)
index 0000000..d9dcb07
--- /dev/null
@@ -0,0 +1,48 @@
+cmake_minimum_required(VERSION 2.8)
+
+project(memd)
+set(PROJECT_NAME swap_memd)
+
+find_package(Protobuf REQUIRED)
+
+
+# setup protobuf
+set(PROTO_DIR ${CMAKE_CURRENT_SOURCE_DIR}/protocol)
+
+protobuf_generate_cpp(
+  PROTO_SRCS
+  PROTO_HDRS
+  ${PROTO_DIR}/memd_metadata.proto
+)
+
+
+# headers setup
+include_directories(
+  ${PROTO_DIR}                          # protocol headers
+  ${CMAKE_CURRENT_BINARY_DIR}           # generated protobuf headers
+  ${CMAKE_CURRENT_SOURCE_DIR}/../utils/ # utils headers
+)
+
+
+# setup sorces
+set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
+set(SRC
+  ${PROTO_SRCS}
+  ${SRC_DIR}/main.cpp
+)
+
+
+# setup linker
+link_directories(${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
+
+add_executable(${PROJECT_NAME} ${SRC})
+target_link_libraries(
+  ${PROJECT_NAME}
+  ${PROTOBUF_LITE_LIBRARIES}
+  libswaputils.so
+  libsystemd.so
+)
+
+
+# install
+install(TARGETS ${PROJECT_NAME} DESTINATION ${BINDIR})
diff --git a/src/memd/protocol/memd.h b/src/memd/protocol/memd.h
new file mode 100644 (file)
index 0000000..70f6756
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *      Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * 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.
+ *
+ * Contributors:
+ * - Samsung RnD Institute Russia
+ *
+ */
+
+#ifndef MEMD_H
+#define MEMD_H
+
+
+enum MemdIPC {
+    MEMD_READ_FILE,
+    MEMD_EXIT,
+    MEMD_CNT
+};
+
+
+#endif // MEMD_H
diff --git a/src/memd/protocol/memd_metadata.proto b/src/memd/protocol/memd_metadata.proto
new file mode 100644 (file)
index 0000000..9f29c99
--- /dev/null
@@ -0,0 +1,16 @@
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+
+package MEMD;
+
+message ReadFileRequest {
+  required string path = 1;
+}
+
+message ReadFileAnswer {
+  required bool success = 1;
+  required string error = 2;
+  required bytes data = 3;
+}
diff --git a/src/memd/src/main.cpp b/src/memd/src/main.cpp
new file mode 100644 (file)
index 0000000..ae1849a
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *      Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ * 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.
+ *
+ * Contributors:
+ * - Samsung RnD Institute Russia
+ *
+ */
+
+#include <errno.h>
+#include <signal.h>
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <systemd/sd-daemon.h>
+#include <event_loop.h>
+#include <memd.h>
+#include <memd_metadata.pb.h>
+
+
+static const int CONNECT_TIMEOUT = 10 * 1000;
+static const char SOCKET_PATH[] = "/tmp/swap_memd.socket";
+
+
+static bool read_file(const char *filename, std::string &out)
+{
+    std::ifstream in(filename, std::ios::in | std::ios::binary);
+    if (in) {
+        out = std::string(std::istreambuf_iterator<char>(in),
+                          std::istreambuf_iterator<char>());
+        return true;
+    }
+
+    return false;
+}
+
+static void do_memd_read_file(const MEMD::ReadFileRequest &request,
+                              MEMD::ReadFileAnswer &answer)
+{
+    bool ret = false;
+    std::string out;
+    std::string err;
+
+    try {
+        ret = read_file(request.path().c_str(), out);
+    } catch (...) {
+        err = "Cannot read file: " + request.path();
+    }
+
+    answer.set_success(ret);
+    answer.set_error(err);
+    answer.set_data(out);
+}
+
+static void try_memd_read_file(void *user_data, const std::string &in, std::string &out)
+{
+    MEMD::ReadFileRequest request;
+    MEMD::ReadFileAnswer answer;
+
+    if (!request.ParseFromString(in))
+        throw std::runtime_error("Cannot parse: in -> ReadFileRequest");
+
+    do_memd_read_file(request, answer);
+
+    if (!answer.SerializeToString(&out))
+        throw std::runtime_error("Cannot serialize: ReadFileAnswer -> out");
+}
+
+static EventLoop::HandlerCode memd_read_file(void *user_data,
+                                             const std::string &in, std::string &out)
+{
+    try {
+        try_memd_read_file(user_data, in, out);
+        return EventLoop::HC_SUCCESS;
+    } catch (const google::protobuf::FatalException &e) {
+        throw std::runtime_error(e.what());
+    } catch (...) {
+        throw std::runtime_error(std::string("Unknown exeption in: ") + __func__);
+    }
+
+    return EventLoop::HC_ERROR;
+}
+
+static EventLoop::HandlerCode memd_exit(void *user_data,
+                                        const std::string &in, std::string &out)
+{
+    return EventLoop::HC_STOP;
+}
+
+static EventLoop::Handler recv_handler[MEMD_CNT] = {
+    [MEMD_READ_FILE] = memd_read_file,
+    [MEMD_EXIT] = memd_exit,
+};
+
+
+
+static EventLoop *g_loop;
+
+static void signal_handler(int sig)
+{
+    if (sig == SIGTERM) {
+        // shut down
+        g_loop->stop();
+
+        // reaset signal
+        signal(SIGTERM, SIG_DFL);
+    } else if (sig == SIGHUP) {
+        // reload config
+    }
+}
+
+static void signal_setup()
+{
+    signal(SIGTERM, signal_handler);
+    signal(SIGHUP, signal_handler);
+}
+
+static void do_main()
+{
+    signal_setup();
+
+    EventLoop::RecvData recv_data(nullptr, recv_handler, MEMD_CNT);
+
+    EventLoop event_loop;
+    g_loop = &event_loop;
+    g_loop->init(SOCKET_PATH);
+
+    sd_notify(0, "READY=1");
+    g_loop->run(recv_data, CONNECT_TIMEOUT);
+    sd_notify(0, "STOPPING=1");
+
+    g_loop->uninit();
+}
+
+
+int main(int argc, char *argv[])
+{
+    int ret = 0;
+
+    try {
+        do_main();
+    } catch (const std::runtime_error &err) {
+        std::cerr << err.what() << std::endl;
+        ret = -1;
+    } catch (...) {
+        std::cerr << "main: Unknown exception" << std::endl;
+        ret = -1;
+    }
+
+    return ret;
+}
diff --git a/systemd/swap_memd.path b/systemd/swap_memd.path
new file mode 100644 (file)
index 0000000..d27491a
--- /dev/null
@@ -0,0 +1,8 @@
+[Unit]
+Description=swap_memd trigger
+
+[Path]
+PathExists=/tmp/swap/memd
+
+[Install]
+WantedBy=multi-user.target
diff --git a/systemd/swap_memd.service b/systemd/swap_memd.service
new file mode 100644 (file)
index 0000000..e74b3a0
--- /dev/null
@@ -0,0 +1,18 @@
+[Unit]
+Description=swap_memd service
+
+[Service]
+Type=notify
+NotifyAccess=main
+
+User=owner
+Group=users
+SmackProcessLabel=System
+Sockets=swap_memd.socket
+
+PermissionsStartOnly=true
+ExecStart=/usr/bin/swap_memd
+ExecStartPost=/bin/rm -f /tmp/swap/memd
+
+StandardOutput=journal+console
+StandardError=journal+console
diff --git a/systemd/swap_memd.socket b/systemd/swap_memd.socket
new file mode 100644 (file)
index 0000000..d922bd5
--- /dev/null
@@ -0,0 +1,10 @@
+[Unit]
+Description=swap_memd socket
+
+[Socket]
+ListenStream=/tmp/swap_memd.socket
+SmackLabelIPIn=*
+SmackLabelIPOut=@
+
+[Install]
+WantedBy=sockets.target