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