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