• 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 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