Move function definition to aul header
[platform/core/appfw/aul-1.git] / src / aul_proc.cc
1 /*
2  * Copyright (c) 2000 - 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 <bundle_internal.h>
18 #include <fcntl.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25
26 #include <bundle_cpp.h>
27
28 #include <string>
29 #include <memory>
30 #include <mutex>
31
32 #include "app_request.h"
33 #include "aul_api.h"
34 #include "aul_util.h"
35 #include "include/aul_proc.h"
36 #include "include/aul_sock.h"
37
38 #include "aul/common/file_descriptor.hh"
39
40 using namespace aul;
41 using namespace aul::internal;
42
43 namespace {
44
45 class ProcContext {
46  public:
47   ProcContext() {}
48   ~ProcContext() {}
49
50   void SetName(std::string name) {
51     std::lock_guard<std::mutex> lock(mutex_);
52     name_ = std::move(name);
53   }
54
55   const std::string& GetName() {
56     std::lock_guard<std::mutex> lock(mutex_);
57     return name_;
58   }
59
60   void SetExtra(tizen_base::Bundle extra) {
61     std::lock_guard<std::mutex> lock(mutex_);
62     extra_ = std::move(extra);
63   }
64
65   tizen_base::Bundle& GetExtra() {
66     std::lock_guard<std::mutex> lock(mutex_);
67     return extra_;
68   }
69
70   void SetFd(int fd) {
71     std::lock_guard<std::mutex> lock(mutex_);
72     fd_.Set(fd);
73   }
74
75   void Close() {
76     std::lock_guard<std::mutex> lock(mutex_);
77     fd_.Close();
78   }
79
80   bool IsClosed() {
81     std::lock_guard<std::mutex> lock(mutex_);
82     return fd_.IsClosed();
83   }
84
85  private:
86   FileDescriptor fd_;
87   std::string name_;
88   tizen_base::Bundle extra_;
89   mutable std::mutex mutex_;
90 };
91
92 int ReadFromPath(const std::string& path, char* buf, size_t buf_size) {
93   int fd = open(path.c_str(), O_RDONLY);
94   if (fd < 0) {
95     _E("open() is failed. path(%s), errno(%d)", path.c_str(), errno);
96     return AUL_R_ERROR;
97   }
98
99   FileDescriptor fd_closer(fd);
100   ssize_t bytes = read(fd, buf, buf_size - 1);
101   if (bytes <= 0) {
102     _E("read() is failed. errno(%d)", errno);
103     return AUL_R_ERROR;
104   }
105
106   buf[bytes] = '\0';
107   return AUL_R_OK;
108 }
109
110 int SendAndReceive(int cmd, pid_t pid, uid_t uid, bundle** response) {
111   int fd = AppRequest(cmd, uid)
112       .SetPid(pid)
113       .SendSimply(AUL_SOCK_ASYNC);
114   if (fd < 0 || fd >= sysconf(_SC_OPEN_MAX)) {
115     _E("Failed to send request. error(%d)", fd);
116     return fd;
117   }
118
119   FileDescriptor fd_closer(fd);
120   app_pkt_t* pkt = nullptr;
121   int ret = aul_sock_recv_reply_pkt(fd, &pkt);
122   if (ret < 0) {
123     _E("Failed to receive reply packet. error(%d)", ret);
124     return AUL_R_ECOMM;
125   }
126
127   std::unique_ptr<app_pkt_t, decltype(std::free)*> pkt_auto(pkt, std::free);
128   if (!(pkt->opt & AUL_SOCK_BUNDLE)) {
129     _E("Invalid protocol");
130     return AUL_R_ECOMM;
131   }
132
133   if (pkt->cmd != APP_GET_INFO_OK) {
134     _E("Failed to get name by pid(%d)", pid);
135     return AUL_R_ERROR;
136   }
137
138   *response = bundle_decode(pkt->data, pkt->len);
139   if (*response == nullptr) {
140     _E("bundle_decode() is failed");
141     return AUL_R_ERROR;
142   }
143
144   return AUL_R_OK;
145 }
146
147 ProcContext context;
148
149 }  // namespace
150
151 extern "C" API int aul_proc_get_uid(pid_t pid, uid_t* uid) {
152   if (pid < 1 || uid == nullptr) {
153     _E("Invalid parameter");
154     return AUL_R_EINVAL;
155   }
156
157   std::string path = "/proc/" + std::to_string(pid);
158   struct stat stat_buf;
159   int ret = stat(path.c_str(), &stat_buf);
160   if (ret < 0) {
161     _E("stat() is failed. path(%s), errno(%d)", path.c_str(), errno);
162     return AUL_R_ERROR;
163   }
164
165   *uid = stat_buf.st_uid;
166   return AUL_R_OK;
167 }
168
169 extern "C" API int aul_proc_get_attr(pid_t pid, char* buf, size_t buf_size) {
170   if (pid < 1 || buf == nullptr || buf_size <= 0) {
171     _E("Invalid parameter");
172     return AUL_R_EINVAL;
173   }
174
175   std::string path = "/proc/" + std::to_string(pid) + "/attr/current";
176   return ReadFromPath(path, buf, buf_size);
177 }
178
179 extern "C" API int aul_proc_get_cmdline(pid_t pid, char* buf, size_t buf_size) {
180   if (pid < 1 || buf == nullptr || buf_size <= 0) {
181     _E("Invalid parameter");
182     return AUL_R_EINVAL;
183   }
184
185   std::string path = "/proc/" + std::to_string(pid) + "/cmdline";
186   return ReadFromPath(path, buf, buf_size);
187 }
188
189 extern "C" API int aul_proc_register(const char* name, bundle* extra) {
190   if (name == nullptr || name[0] == '\0') {
191     _E("Invalid parameter");
192     return AUL_R_EINVAL;
193   }
194
195   if (!context.IsClosed()) {
196     _E("Already registered. Please call aul_proc_deregister() first");
197     return AUL_R_ERROR;
198   }
199
200   tizen_base::Bundle b {{AUL_K_PROC_NAME, name}};
201   if (extra) {
202     tizen_base::Bundle extra_data(extra, false, false);
203     auto raw = extra_data.ToRaw();
204     b.Add(AUL_K_PROC_EXTRA, reinterpret_cast<const char*>(raw.first.get()));
205   }
206
207   int ret = AppRequest(PROC_REGISTER, getuid())
208       .With(b)
209       .SendSimply(AUL_SOCK_ASYNC);
210   if (ret < 0) {
211     _E("Failed to send request. name(%s), error(%d)", name, ret);
212     return ret;
213   }
214
215   int res = aul_sock_recv_result_with_fd(ret);
216   if (res != 0) {
217     _E("Failed to receive the result. fd(%d)", res);
218     close(ret);
219     return AUL_R_ERROR;
220   }
221
222   context.SetFd(ret);
223   context.SetName(name);
224   if (extra)
225     context.SetExtra(tizen_base::Bundle(extra, true, true));
226
227   return AUL_R_OK;
228 }
229
230 extern "C" API int aul_proc_deregister(void) {
231   if (context.IsClosed()) {
232     _E("Invalid context");
233     return AUL_R_ERROR;
234   }
235
236   int ret = AppRequest(PROC_DEREGISTER, getuid())
237       .SendSimply(AUL_SOCK_NOREPLY);
238   if (ret < 0) {
239     _E("Failed to send request. error(%d)", ret);
240     return ret;
241   }
242
243   context.Close();
244   return AUL_R_OK;
245 }
246
247 extern "C" API int aul_proc_get_name(pid_t pid, char** name) {
248   if (pid < 1 || name == nullptr) {
249     _E("Invalid parameter");
250     return AUL_R_EINVAL;
251   }
252
253   if (pid == getpid() && !context.IsClosed() && !context.GetName().empty()) {
254     *name = strdup(context.GetName().c_str());
255     if (*name == nullptr) {
256       _E("strdup() is failed");
257       return AUL_R_ENOMEM;
258     }
259
260     return AUL_R_OK;
261   }
262
263   bundle* response;
264   int ret = SendAndReceive(PROC_GET_NAME, pid, getuid(), &response);
265   if (ret != AUL_R_OK)
266     return ret;
267
268   tizen_base::Bundle b(response, false, true);
269   std::string val = b.GetString(AUL_K_PROC_NAME);
270   if (val.empty()) {
271     _E("Failed to get name");
272     return AUL_R_ERROR;
273   }
274
275   *name = strdup(val.c_str());
276   if (*name == nullptr) {
277     _E("strdup() is failed");
278     return AUL_R_ENOMEM;
279   }
280
281   return AUL_R_OK;
282 }
283
284 extern "C" API int aul_proc_get_extra(pid_t pid, bundle** extra) {
285   if (pid < 1 || extra == nullptr) {
286     _E("Invalid parameter");
287     return AUL_R_EINVAL;
288   }
289
290   if (pid == getpid() && !context.IsClosed()) {
291     auto& extra_data = context.GetExtra();
292     *extra = bundle_dup(extra_data.GetHandle());
293     if (*extra == nullptr) {
294       _E("bundle_dup() is failed");
295       return AUL_R_ENOMEM;
296     }
297
298     return AUL_R_OK;
299   }
300
301   bundle* response;
302   int ret = SendAndReceive(PROC_GET_EXTRA, pid, getuid(), &response);
303   if (ret != AUL_R_OK)
304     return ret;
305
306   tizen_base::Bundle b(response, false, true);
307   std::string raw = b.GetString(AUL_K_PROC_EXTRA);
308   if (raw.empty()) {
309     _E("Failed to get extra");
310     return AUL_R_ERROR;
311   }
312
313   tizen_base::Bundle extra_data(raw);
314   *extra = extra_data.Detach();
315   return AUL_R_OK;
316 }