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