Fix ResultParcelable to handle null char pointer
[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 "pkgmgrinfo_debug.h"
22
23 #undef LOG_TAG
24 #define LOG_TAG "PKGMGR_INFO"
25
26 namespace pkgmgr_common {
27
28 gboolean ReadyChecker::OnReceiveEvent(GIOChannel* channel, GIOCondition cond,
29     gpointer user_data) {
30   char buf[4096] __attribute__((aligned(__alignof__(struct inotify_event))));
31   char* ptr;
32   ssize_t len;
33   struct inotify_event* event;
34   auto ready_checker = reinterpret_cast<ReadyChecker*>(user_data);
35   int fd = g_io_channel_unix_get_fd(channel);
36   while ((len = read(fd, buf, sizeof(buf))) > 0) {
37     for (ptr = buf; ptr < buf + len;
38          ptr += sizeof(struct inotify_event) + event->len) {
39       event = reinterpret_cast<struct inotify_event*>(ptr);
40       char* nptr = ptr + sizeof(struct inotify_event) + event->len;
41       if (nptr > buf + len)
42         break;
43
44       if (event->len) {
45         if (event->mask & IN_CREATE &&
46             ready_checker->ready_file_ == event->name) {
47           _LOGI("server is ready (%s)", ready_checker->ready_file_.c_str());
48           ready_checker->ready_ = true;
49           ready_checker->Dispose();
50           return G_SOURCE_CONTINUE;
51         }
52       }
53     }
54   }
55
56   return G_SOURCE_CONTINUE;
57 }
58
59 ReadyChecker::ReadyChecker(const std::string& ready_path) {
60   if (access(ready_path.c_str(), F_OK) == 0) {
61     ready_ = true;
62     disposed_ = true;
63     return;
64   }
65   auto it = ready_path.find_last_of("/");
66   if (it == ready_path.npos) {
67     _LOGE("Invalid path %s", ready_path.c_str());
68     disposed_ = true;
69     return;
70   }
71
72   fd_ = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
73   if (fd_ == -1) {
74     _LOGE("Failed to inotify_init. errno(%d)", errno);
75     disposed_ = true;
76     return;
77   }
78   ready_path_ = ready_path.substr(0, it);
79   ready_file_ = ready_path.substr(it + 1);
80   wd_ = inotify_add_watch(fd_, ready_path_.c_str(), IN_CREATE);
81   if (wd_ == -1) {
82     _LOGE("Failed to inotify_add_watch. errno(%d)", errno);
83     Dispose();
84     return;
85   }
86
87   channel_ = g_io_channel_unix_new(fd_);
88   if (channel_ == nullptr) {
89     _LOGE("Failed to create GIO channel");
90     Dispose();
91     return;
92   }
93   tag_ = g_io_add_watch(channel_, G_IO_IN, OnReceiveEvent, this);
94   if (tag_ == 0) {
95     _LOGE("Failed to add watch");
96     Dispose();
97     return;
98   }
99
100   disposed_ = false;
101 }
102
103 ReadyChecker::~ReadyChecker() {
104   Dispose();
105 }
106
107 bool ReadyChecker::IsReady() const {
108   return ready_;
109 }
110
111 void ReadyChecker::Dispose() {
112   if (disposed_)
113     return;
114
115   if (tag_) {
116     g_source_remove(tag_);
117     tag_ = 0;
118   }
119
120   if (channel_ != nullptr) {
121     g_io_channel_unref(channel_);
122     channel_ = nullptr;
123   }
124
125   if (wd_ > 0) {
126     inotify_rm_watch(fd_, wd_);
127     wd_ = 0;
128   }
129
130   if (fd_ > 0) {
131     close(fd_);
132     fd_ = 0;
133   }
134
135   disposed_ = true;
136 }
137
138 }  // namespace pkgmgr_common