3dae431d9148dd2e93129e74632b12e02de02460
[platform/core/appfw/pkgmgr-info.git] / src / common / ready_checker.cc
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "ready_checker.hh"
18
19 #include <utility>
20
21 #include "utils/logging.hh"
22
23 #include "pkgmgrinfo_debug.h"
24
25 #undef LOG_TAG
26 #define LOG_TAG "PKGMGR_INFO"
27
28 namespace pkgmgr_common {
29
30 gboolean ReadyChecker::OnReceiveEvent(GIOChannel* channel, GIOCondition cond,
31     gpointer user_data) {
32   char buf[4096] __attribute__((aligned(__alignof__(struct inotify_event))));
33   char* ptr;
34   ssize_t len;
35   struct inotify_event* event;
36   auto ready_checker = reinterpret_cast<ReadyChecker*>(user_data);
37   int fd = g_io_channel_unix_get_fd(channel);
38
39   while ((len = read(fd, buf, sizeof(buf))) > 0) {
40     for (ptr = buf; ptr < buf + len;
41          ptr += sizeof(struct inotify_event) + event->len) {
42       event = reinterpret_cast<struct inotify_event*>(ptr);
43       char* nptr = ptr + sizeof(struct inotify_event) + event->len;
44       if (nptr > buf + len)
45         break;
46
47       if (!event->len)
48         continue;
49
50       if (!(event->mask & IN_CREATE) ||
51           ready_checker->ready_file_ != event->name)
52         continue;
53
54       LOG(INFO) << "server is ready : " <<  ready_checker->ready_file_;
55       ready_checker->ready_ = true;
56       ready_checker->Dispose();
57       return G_SOURCE_CONTINUE;
58     }
59   }
60
61   return G_SOURCE_CONTINUE;
62 }
63
64 ReadyChecker::ReadyChecker(const std::string& ready_path) {
65   if (access(ready_path.c_str(), F_OK) == 0) {
66     ready_ = true;
67     disposed_ = true;
68     return;
69   }
70
71   auto it = ready_path.find_last_of("/");
72   if (it == ready_path.npos) {
73     LOG(ERROR) << "Invalid path: " << ready_path;
74     disposed_ = true;
75     return;
76   }
77
78   fd_ = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
79   if (fd_ == -1) {
80     LOG(ERROR) << "Failed to inotify_init. errno: " << errno;
81     disposed_ = true;
82     return;
83   }
84
85   ready_path_ = ready_path.substr(0, it);
86   ready_file_ = ready_path.substr(it + 1);
87   wd_ = inotify_add_watch(fd_, ready_path_.c_str(), IN_CREATE);
88   if (wd_ == -1) {
89     LOG(ERROR) << "Failed to inotify_add_watch. errno: " << errno;
90     Dispose();
91     return;
92   }
93
94   channel_ = g_io_channel_unix_new(fd_);
95   if (channel_ == nullptr) {
96     LOG(ERROR) << "Failed to create GIO channel";
97     Dispose();
98     return;
99   }
100
101   tag_ = g_io_add_watch(channel_, G_IO_IN, OnReceiveEvent, this);
102   if (tag_ == 0) {
103     LOG(ERROR) << "Failed to add watch";
104     Dispose();
105     return;
106   }
107
108   disposed_ = false;
109 }
110
111 ReadyChecker::~ReadyChecker() {
112   Dispose();
113 }
114
115 bool ReadyChecker::IsReady() const {
116   return ready_;
117 }
118
119 void ReadyChecker::Dispose() {
120   if (disposed_)
121     return;
122
123   if (tag_) {
124     g_source_remove(tag_);
125     tag_ = 0;
126   }
127
128   if (channel_ != nullptr) {
129     g_io_channel_unref(channel_);
130     channel_ = nullptr;
131   }
132
133   if (wd_ > 0) {
134     inotify_rm_watch(fd_, wd_);
135     wd_ = 0;
136   }
137
138   if (fd_ > 0) {
139     close(fd_);
140     fd_ = 0;
141   }
142
143   disposed_ = true;
144 }
145
146 }  // namespace pkgmgr_common