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