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