1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <grp.h>
17 #include <pwd.h>
18 #include <unistd.h>
19 #include <sys/types.h>
20 #include "daemon_common.h"
21 #if defined(SURPPORT_SELINUX)
22 #include "selinux/selinux.h"
23 #endif
24 using namespace Hdc;
25
26 static bool g_enableUsb = false;
27 #ifdef HDC_SUPPORT_UART
28 static bool g_enableUart = false;
29 #endif
30 static bool g_enableTcp = false;
31 static bool g_backgroundRun = false;
32 namespace Hdc {
RestartDaemon(bool forkchild)33 bool RestartDaemon(bool forkchild)
34 {
35 char path[256] = "";
36 size_t nPathSize = 256;
37 uv_exepath(path, &nPathSize);
38 execl(path, "hdcd", forkchild ? "-forkchild" : nullptr, nullptr);
39 return true;
40 }
41
ForkChildCheck(int argc,const char * argv[])42 bool ForkChildCheck(int argc, const char *argv[])
43 {
44 // hdcd #service start foreground
45 // hdcd -b #service start backgroundRun
46 // hdcd -fork #fork
47 Base::PrintMessage("Background mode, persist.hdc.mode");
48 string workMode;
49 SystemDepend::GetDevItem("persist.hdc.mode", workMode);
50 workMode = Base::Trim(workMode);
51 if (workMode == CMDSTR_TMODE_TCP) {
52 WRITE_LOG(LOG_DEBUG, "Property enable TCP");
53 g_enableTcp = true;
54 } else if (workMode == CMDSTR_TMODE_USB) {
55 WRITE_LOG(LOG_DEBUG, "Property enable USB");
56 g_enableUsb = true;
57 #ifdef HDC_SUPPORT_UART
58 } else if (workMode == CMDSTR_TMODE_UART) {
59 WRITE_LOG(LOG_DEBUG, "Property enable UART");
60 g_enableUart = true;
61 } else if (workMode == "all") {
62 #else
63 } else if (workMode == "all") {
64 #endif
65 WRITE_LOG(LOG_DEBUG, "Property enable USB and TCP");
66 g_enableUsb = true;
67 g_enableTcp = true;
68 #ifdef HDC_SUPPORT_UART
69 g_enableUart = true;
70 #endif
71 } else {
72 WRITE_LOG(LOG_DEBUG, "Default USB mode");
73 g_enableUsb = true;
74 #ifdef HDC_SUPPORT_UART
75 WRITE_LOG(LOG_DEBUG, "Default UART mode");
76 g_enableUart = true;
77 #endif
78 }
79 if (argc == CMD_ARG1_COUNT) {
80 if (!strcmp(argv[1], "-forkchild")) {
81 g_backgroundRun = false; // forkchild,Forced foreground
82 } else if (!strcmp(argv[1], "-b")) {
83 g_backgroundRun = true;
84 }
85 }
86 return true;
87 }
88
CheckUvThreadConfig()89 size_t CheckUvThreadConfig()
90 {
91 string nThreadsString;
92 bool ret = SystemDepend::GetDevItem("persist.hdc.uv.threads", nThreadsString);
93 if (!ret) {
94 return SIZE_THREAD_POOL;
95 }
96 size_t nThreads = atoi(nThreadsString.c_str());
97 if (nThreads <= 0) {
98 nThreads = SIZE_THREAD_POOL;
99 }
100 return nThreads;
101 }
102
BackgroundRun()103 int BackgroundRun()
104 {
105 pid_t pc = fork(); // create process as daemon process
106 if (pc < 0) {
107 return -1;
108 } else if (!pc) {
109 int i;
110 const int MAX_NUM = 64;
111 for (i = 0; i < MAX_NUM; ++i) {
112 int fd = i;
113 Base::CloseFd(fd);
114 }
115 RestartDaemon(true);
116 } else { // >0 orig process
117 }
118 return 0;
119 }
120
DaemonUsage()121 string DaemonUsage()
122 {
123 string ret;
124 ret = "\n Harmony device connector daemon(HDCD) Usage: hdcd [options]...\n\n"
125 "\n"
126 "general options:\n"
127 " -h - Print help\n"
128 " -l 0-5 - Print runtime log\n"
129 "\n"
130 "daemon mode options:\n"
131 " -b - Daemon run in background/fork mode\n"
132 #ifdef HDC_SUPPORT_UART
133 " -i - Enable UART mode\n"
134 #endif
135 " -u - Enable USB mode\n"
136 " -t - Enable TCP mode\n";
137 return ret;
138 }
139
GetDaemonCommandlineOptions(int argc,const char * argv[])140 bool GetDaemonCommandlineOptions(int argc, const char *argv[])
141 {
142 int ch;
143 // hdcd -l4 ...
144 WRITE_LOG(LOG_DEBUG, "Foreground cli-mode");
145 // Both settings are running with parameters
146 while ((ch = getopt(argc, const_cast<char *const *>(argv), "utl:")) != -1) {
147 switch (ch) {
148 case 'l': {
149 int logLevel = atoi(optarg);
150 if (logLevel < 0 || logLevel > LOG_LAST) {
151 WRITE_LOG(LOG_DEBUG, "Loglevel error!\n");
152 return -1;
153 }
154 Base::SetLogLevel(logLevel);
155 break;
156 }
157 case 'u': {
158 Base::PrintMessage("Option USB enabled");
159 g_enableUsb = true;
160 break;
161 }
162 case 't': {
163 Base::PrintMessage("Option TCP enabled");
164 g_enableTcp = true;
165 break;
166 }
167 #ifdef HDC_SUPPORT_UART
168 case 'i': { // enable uart
169 Base::PrintMessage("Parament Enable UART");
170 g_enableUart = true;
171 break;
172 }
173 #endif
174 default:
175 Base::PrintMessage("Option:%c non-supported!", ch);
176 exit(0);
177 break;
178 }
179 }
180 return true;
181 }
182
DropRootPrivileges()183 bool DropRootPrivileges()
184 {
185 int ret;
186 const char *userName = "shell";
187 vector<const char *> groupsNames = { "shell", "log", "readproc" };
188 struct passwd *user;
189 gid_t *gids = nullptr;
190
191 user = getpwnam(userName);
192 if (user == nullptr) {
193 WRITE_LOG(LOG_FATAL, "getpwuid %s fail, %s", userName, strerror(errno));
194 return false;
195 }
196
197 gids = static_cast<gid_t *>(calloc(groupsNames.size(), sizeof(gid_t)));
198 if (gids == nullptr) {
199 WRITE_LOG(LOG_FATAL, "calloc fail");
200 return false;
201 }
202
203 for (size_t i = 0; i < groupsNames.size(); i++) {
204 struct group *group = getgrnam(groupsNames[i]);
205 if (group == nullptr) {
206 WRITE_LOG(LOG_FATAL, "calloc fail");
207 }
208 gids[i] = group->gr_gid;
209 }
210
211 ret = setuid(user->pw_uid);
212 if (ret) {
213 WRITE_LOG(LOG_FATAL, "setuid %s fail, %s", userName, strerror(errno));
214 free(gids);
215 return false;
216 }
217
218 ret = setgid(user->pw_gid);
219 if (ret) {
220 WRITE_LOG(LOG_FATAL, "setgid %s fail, %s", userName, strerror(errno));
221 free(gids);
222 return false;
223 }
224
225 ret = setgroups(groupsNames.size(), gids);
226 if (ret) {
227 WRITE_LOG(LOG_FATAL, "setgroups %s fail, %s", userName, strerror(errno));
228 free(gids);
229 return false;
230 }
231
232 free(gids);
233 #if defined(SURPPORT_SELINUX)
234 if (setcon("u:r:hdcd:s0") != 0) {
235 WRITE_LOG(LOG_FATAL, "setcon fail, errno %s", userName, strerror(errno));
236 }
237 #endif
238 return true;
239 }
240
NeedDropRootPrivileges()241 bool NeedDropRootPrivileges()
242 {
243 string rootMode;
244 string debugMode;
245 SystemDepend::GetDevItem("const.debuggable", debugMode);
246 SystemDepend::GetDevItem("persist.hdc.root", rootMode);
247 if (debugMode == "1") {
248 if (rootMode == "1") {
249 int rc = setuid(0);
250 if (rc != 0) {
251 char buffer[BUF_SIZE_DEFAULT] = { 0 };
252 strerror_r(errno, buffer, BUF_SIZE_DEFAULT);
253 WRITE_LOG(LOG_FATAL, "setuid(0) fail %s", buffer);
254 }
255 WRITE_LOG(LOG_DEBUG, "Root run rc:%d", rc);
256 } else if (rootMode == "0") {
257 if (getuid() == 0) {
258 return DropRootPrivileges();
259 }
260 }
261 // default keep root
262 } else {
263 return DropRootPrivileges();
264 }
265 return true;
266 }
267 } // namespace Hdc
268
269 #ifndef UNIT_TEST
270 // daemon running with default behavior. options also can be given to custom its behavior including b/t/u/l etc.
main(int argc,const char * argv[])271 int main(int argc, const char *argv[])
272 {
273 #ifdef CONFIG_USE_JEMALLOC_DFX_INIF
274 mallopt(M_DELAYED_FREE, M_DELAYED_FREE_DISABLE);
275 mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_DISABLE);
276 #endif
277 // check property
278 if (argc == 2 && !strcmp(argv[1], "-h")) {
279 string usage = DaemonUsage();
280 fprintf(stderr, "%s", usage.c_str());
281 return 0;
282 }
283 if (argc == CMD_ARG1_COUNT && !strcmp(argv[1], "-v")) {
284 string ver = Hdc::Base::GetVersion();
285 fprintf(stderr, "%s\n", ver.c_str());
286 return 0;
287 }
288 if (argc == 1 || (argc == CMD_ARG1_COUNT && (!strcmp(argv[1], "-forkchild") || !strcmp(argv[1], "-b")))) {
289 ForkChildCheck(argc, argv);
290 } else {
291 GetDaemonCommandlineOptions(argc, argv);
292 }
293 if (!g_enableTcp && !g_enableUsb) {
294 #ifdef HDC_SUPPORT_UART
295 if (!g_enableUart) {
296 Base::PrintMessage("TCP, USB and Uart are disable, cannot run continue\n");
297 return -1;
298 }
299 #else
300 Base::PrintMessage("Both TCP and USB are disable, cannot run continue\n");
301 return -1;
302 #endif
303 }
304 if (g_backgroundRun) {
305 return BackgroundRun();
306 }
307
308 #ifndef HDC_BUILD_VARIANT_USER
309 if (!NeedDropRootPrivileges()) {
310 Base::PrintMessage("DropRootPrivileges fail, EXITING...\n");
311 return -1;
312 }
313 #endif
314
315 Base::InitProcess();
316 WRITE_LOG(LOG_DEBUG, "HdcDaemon main run");
317 HdcDaemon daemon(false, CheckUvThreadConfig());
318
319 #ifdef HDC_SUPPORT_UART
320 daemon.InitMod(g_enableTcp, g_enableUsb, g_enableUart);
321 #else
322 daemon.InitMod(g_enableTcp, g_enableUsb);
323 #endif
324 daemon.WorkerPendding();
325 bool wantRestart = daemon.WantRestart();
326 WRITE_LOG(LOG_DEBUG, "Daemon finish wantRestart %d", wantRestart);
327 // There is no daemon, we can only restart myself.
328 if (wantRestart) {
329 // just root can self restart, low privilege will be exit and start by service(root)
330 WRITE_LOG(LOG_INFO, "Daemon restart");
331 RestartDaemon(false);
332 }
333 #ifdef HDC_SUPPORT_UART
334 // when no usb insert , device will hung here , we don't know why.
335 // Test the command "smode -r" in uart mode, then execute shell
336 // hdcd will not really exit until usb plug in
337 // so we use abort here
338 _exit(0);
339 #endif
340 return 0;
341 }
342 #endif
343