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