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