init_common_service.c 17.6 KB
Newer Older
W
wenjun 已提交
1
/*
Z
zhong_ning 已提交
2
 * Copyright (c) 2021 Huawei Device Co., Ltd.
W
wenjun 已提交
3 4 5 6 7 8 9 10 11 12 13 14
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
15

W
wenjun 已提交
16
#include <errno.h>
Z
zhong_ning 已提交
17
#include <fcntl.h>
W
wenjun 已提交
18
#include <signal.h>
Z
zhong_ning 已提交
19
#include <stdlib.h>
M
mamingshuai 已提交
20
#include <string.h>
Z
zhong_ning 已提交
21 22 23
#ifdef __MUSL__
#include <stropts.h>
#endif
24
#include <sys/capability.h>
X
xionglei6 已提交
25
#include <sys/ioctl.h>
Z
zhong_ning 已提交
26
#include <sys/param.h>
W
wenjun 已提交
27 28 29
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
30

31
#include "init.h"
W
wenjun 已提交
32
#include "init_adapter.h"
Z
zhong_ning 已提交
33 34
#include "init_cmds.h"
#include "init_log.h"
X
xionglei6 已提交
35
#include "init_jobs_internal.h"
X
xionglei6 已提交
36
#include "init_service.h"
X
xionglei6 已提交
37
#include "init_service_manager.h"
Z
zhong_ning 已提交
38
#include "init_service_socket.h"
Z
zhong_ning 已提交
39
#include "init_utils.h"
X
xionglei6 已提交
40
#include "fd_holder_internal.h"
Z
zhong_ning 已提交
41
#include "securec.h"
W
wenjun 已提交
42

Q
Qin Fandong 已提交
43
#ifdef WITH_SELINUX
X
xionglei6 已提交
44 45
#include "init_selinux_param.h"
#include <selinux/selinux.h>
Q
Qin Fandong 已提交
46 47
#endif // WITH_SELINUX

Z
zhong_ning 已提交
48 49 50
#ifndef TIOCSCTTY
#define TIOCSCTTY 0x540E
#endif
Z
zhong_ning 已提交
51

S
sun_fan 已提交
52
static int SetAllAmbientCapability(void)
M
mamingshuai 已提交
53 54 55 56 57 58 59 60 61
{
    for (int i = 0; i <= CAP_LAST_CAP; ++i) {
        if (SetAmbientCapability(i) != 0) {
            return SERVICE_FAILURE;
        }
    }
    return SERVICE_SUCCESS;
}

W
wenjun 已提交
62 63
static int SetPerms(const Service *service)
{
Z
zhong_ning 已提交
64
    INIT_CHECK_RETURN_VALUE(KeepCapability() == 0, SERVICE_FAILURE);
Z
zhong_ning 已提交
65
    if (service->servPerm.gIDCnt > 0) {
Z
zhong_ning 已提交
66 67
        INIT_ERROR_CHECK(setgid(service->servPerm.gIDArray[0]) == 0, return SERVICE_FAILURE,
            "SetPerms, setgid for %s failed. %d", service->name, errno);
Z
zhong_ning 已提交
68 69
    }
    if (service->servPerm.gIDCnt > 1) {
X
xionglei6 已提交
70 71
        INIT_ERROR_CHECK(setgroups(service->servPerm.gIDCnt - 1, (const gid_t *)&service->servPerm.gIDArray[1]) == 0,
            return SERVICE_FAILURE,
Z
zhong_ning 已提交
72
            "SetPerms, setgroups failed. errno = %d, gIDCnt=%d", errno, service->servPerm.gIDCnt);
W
wenjun 已提交
73
    }
Z
zhong_ning 已提交
74 75
    if (service->servPerm.uID != 0) {
        if (setuid(service->servPerm.uID) != 0) {
Z
zhong_ning 已提交
76
            INIT_LOGE("setuid of service: %s failed, uid = %d", service->name, service->servPerm.uID);
Z
zhong_ning 已提交
77 78
            return SERVICE_FAILURE;
        }
W
wenjun 已提交
79 80 81 82 83 84 85 86
    }

    // umask call always succeeds and return the previous mask value which is not needed here
    (void)umask(DEFAULT_UMASK_INIT);

    struct __user_cap_header_struct capHeader;
    capHeader.version = _LINUX_CAPABILITY_VERSION_3;
    capHeader.pid = 0;
Z
zhong_ning 已提交
87
    struct __user_cap_data_struct capData[CAP_NUM] = {};
W
wenjun 已提交
88 89
    for (unsigned int i = 0; i < service->servPerm.capsCnt; ++i) {
        if (service->servPerm.caps[i] == FULL_CAP) {
90 91 92 93
            for (int j = 0; j < CAP_NUM; ++j) {
                capData[j].effective = FULL_CAP;
                capData[j].permitted = FULL_CAP;
                capData[j].inheritable = FULL_CAP;
W
wenjun 已提交
94 95 96 97 98 99 100 101 102
            }
            break;
        }
        capData[CAP_TO_INDEX(service->servPerm.caps[i])].effective |= CAP_TO_MASK(service->servPerm.caps[i]);
        capData[CAP_TO_INDEX(service->servPerm.caps[i])].permitted |= CAP_TO_MASK(service->servPerm.caps[i]);
        capData[CAP_TO_INDEX(service->servPerm.caps[i])].inheritable |= CAP_TO_MASK(service->servPerm.caps[i]);
    }

    if (capset(&capHeader, capData) != 0) {
Z
zhong_ning 已提交
103
        INIT_LOGE("capset faild for service: %s, error: %d", service->name, errno);
W
wenjun 已提交
104 105
        return SERVICE_FAILURE;
    }
M
mamingshuai 已提交
106 107 108 109 110
    for (unsigned int i = 0; i < service->servPerm.capsCnt; ++i) {
        if (service->servPerm.caps[i] == FULL_CAP) {
            return SetAllAmbientCapability();
        }
        if (SetAmbientCapability(service->servPerm.caps[i]) != 0) {
Z
zhong_ning 已提交
111
            INIT_LOGE("SetAmbientCapability faild for service: %s", service->name);
M
mamingshuai 已提交
112 113 114
            return SERVICE_FAILURE;
        }
    }
W
wenjun 已提交
115 116 117
    return SERVICE_SUCCESS;
}

S
sun_fan 已提交
118
static void OpenConsole(void)
Z
zhong_ning 已提交
119
{
120
    const int stdError = 2;
Z
zhong_ning 已提交
121
    setsid();
H
huangshan 已提交
122
    WaitForFile("/dev/console", WAIT_MAX_SECOND);
Z
zhong_ning 已提交
123 124 125 126 127
    int fd = open("/dev/console", O_RDWR);
    if (fd >= 0) {
        ioctl(fd, TIOCSCTTY, 0);
        dup2(fd, 0);
        dup2(fd, 1);
128
        dup2(fd, stdError); // Redirect fd to 0, 1, 2
Z
zhong_ning 已提交
129 130
        close(fd);
    } else {
Z
zhong_ning 已提交
131
        INIT_LOGE("Open /dev/console failed. err = %d", errno);
Z
zhong_ning 已提交
132 133 134 135
    }
    return;
}

136
static int WritePid(const Service *service)
S
sun_fan 已提交
137
{
138 139 140 141
    const int maxPidStrLen = 50;
    char pidString[maxPidStrLen];
    pid_t childPid = getpid();
    int len = snprintf_s(pidString, maxPidStrLen, maxPidStrLen - 1, "%d", childPid);
X
add ut  
xionglei6 已提交
142
    INIT_ERROR_CHECK(len > 0, return SERVICE_FAILURE, "Failed to format pid for service %s", service->name);
143 144
    for (int i = 0; i < service->writePidArgs.count; i++) {
        if (service->writePidArgs.argv[i] == NULL) {
S
sun_fan 已提交
145
            continue;
S
sun_fan 已提交
146
        }
147 148 149 150 151 152 153 154
        FILE *fd = NULL;
        char *realPath = GetRealPath(service->writePidArgs.argv[i]);
        if (realPath != NULL) {
            fd = fopen(realPath, "wb");
        } else {
            fd = fopen(service->writePidArgs.argv[i], "wb");
        }
        if (fd != NULL) {
X
add ut  
xionglei6 已提交
155 156
            INIT_CHECK_ONLY_ELOG((int)fwrite(pidString, 1, len, fd) == len,
                "Failed to write %s pid:%s", service->writePidArgs.argv[i], pidString);
157 158 159 160 161 162 163
            (void)fclose(fd);
        } else {
            INIT_LOGE("Failed to open %s.", service->writePidArgs.argv[i]);
        }
        if (realPath != NULL) {
            free(realPath);
        }
X
xionglei6 已提交
164
        INIT_LOGV("ServiceStart writepid filename=%s, childPid=%s, ok", service->writePidArgs.argv[i], pidString);
S
sun_fan 已提交
165
    }
166
    return SERVICE_SUCCESS;
S
sun_fan 已提交
167 168
}

X
xionglei6 已提交
169
void SetSecon(Service *service)
Q
Qin Fandong 已提交
170 171 172 173 174 175 176 177 178 179 180 181
{
#ifdef WITH_SELINUX
    if (*(service->secon)) {
        if (setexeccon(service->secon) < 0) {
            INIT_LOGE("failed to set service %s's secon (%s).", service->name, service->secon);
        } else {
            INIT_LOGI("service %s secon set to %s.", service->name, service->secon);
        }
    }
#endif // WITH_SELINUX
}

X
xionglei6 已提交
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
void CloseServiceFds(Service *service, bool needFree)
{
    if (service == NULL) {
        return;
    }

    INIT_LOGI("Closing service \' %s \' fds", service->name);
    // fdCount > 0, There is no reason fds is NULL
    if (service->fdCount != 0) {
        size_t fdCount = service->fdCount;
        int *fds = service->fds;
        for (size_t i = 0; i < fdCount; i++) {
            INIT_LOGV("Closing fd: %d", fds[i]);
            close(fds[i]);
            fds[i] = -1;
        }
    }
    service->fdCount = 0;
    if (needFree && service->fds != NULL) {
        free(service->fds);
        service->fds = NULL;
    }
}

static void PublishHoldFds(Service *service)
{
    INIT_ERROR_CHECK(service != NULL, return, "Publish hold fds with invalid service");
    char fdBuffer[MAX_FD_HOLDER_BUFFER] = {};
    if (service->fdCount > 0 && service->fds != NULL) {
        size_t pos = 0;
        for (size_t i = 0; i < service->fdCount; i++) {
            (void)snprintf_s((char *)fdBuffer + pos, sizeof(fdBuffer) - pos, sizeof(fdBuffer) - 1,
                "%d ", service->fds[i]);
            pos = strlen(fdBuffer);
        }
        fdBuffer[pos - 1] = '\0'; // Remove last ' '
        INIT_LOGI("fd buffer: [%s]", fdBuffer);
        char envName[MAX_BUFFER_LEN] = {};
        (void)snprintf_s(envName, MAX_BUFFER_LEN, MAX_BUFFER_LEN - 1, ENV_FD_HOLD_PREFIX"%s", service->name);
        if (setenv(envName, fdBuffer, 1) < 0) {
            INIT_LOGE("Failed to set env %s", envName);
        }
        INIT_LOGI("File descriptors of Service \' %s \' published", service->name);
    }
226 227
}

W
wenjun 已提交
228 229
int ServiceStart(Service *service)
{
S
sun_fan 已提交
230
    INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "start service failed! null ptr.");
231 232 233
    INIT_ERROR_CHECK(service->pid <= 0, return SERVICE_SUCCESS, "service : %s had started already.", service->name);
    INIT_ERROR_CHECK(service->pathArgs.count > 0,
        return SERVICE_FAILURE, "start service %s pathArgs is NULL.", service->name);
X
xionglei6 已提交
234

W
wenjun 已提交
235
    if (service->attribute & SERVICE_ATTR_INVALID) {
Z
zhong_ning 已提交
236
        INIT_LOGE("start service %s invalid.", service->name);
W
wenjun 已提交
237 238
        return SERVICE_FAILURE;
    }
239
    struct stat pathStat = { 0 };
W
wenjun 已提交
240
    service->attribute &= (~(SERVICE_ATTR_NEED_RESTART | SERVICE_ATTR_NEED_STOP));
241 242 243 244 245 246
    if (stat(service->pathArgs.argv[0], &pathStat) != 0) {
        service->attribute |= SERVICE_ATTR_INVALID;
        INIT_LOGE("start service %s invalid, please check %s.", service->name, service->pathArgs.argv[0]);
        return SERVICE_FAILURE;
    }
    int pid = fork();
W
wenjun 已提交
247
    if (pid == 0) {
248 249
	INIT_CHECK_ONLY_ELOG(SetAccessToken(service) == SERVICE_SUCCESS,
	    "set access token failed for service %s", service->name);
X
xionglei6 已提交
250 251 252 253 254
        // deal start job
        if (service->serviceJobs.jobsName[JOB_ON_START] != NULL) {
            DoJobNow(service->serviceJobs.jobsName[JOB_ON_START]);
        }

X
xionglei6 已提交
255
        if (!IsOnDemandService(service)) {
X
xionglei6 已提交
256 257
            int ret = CreateServiceSocket(service);
            INIT_ERROR_CHECK(ret >= 0, return SERVICE_FAILURE,
X
xionglei6 已提交
258 259
                "service %s exit! create socket failed!", service->name);
        }
X
xionglei6 已提交
260

X
xionglei6 已提交
261
        CreateServiceFile(service->fileCfg);
Z
zhong_ning 已提交
262 263 264
        if (service->attribute & SERVICE_ATTR_CONSOLE) {
            OpenConsole();
        }
X
xionglei6 已提交
265
        PublishHoldFds(service);
266
        // permissions
X
add ut  
xionglei6 已提交
267 268
        INIT_ERROR_CHECK(SetPerms(service) == SERVICE_SUCCESS, _exit(PROCESS_EXIT_CODE),
            "service %s exit! set perms failed! err %d.", service->name, errno);
269
        // write pid
X
add ut  
xionglei6 已提交
270 271
        INIT_ERROR_CHECK(WritePid(service) == SERVICE_SUCCESS, _exit(PROCESS_EXIT_CODE),
            "service %s exit! write pid failed!", service->name);
Q
Qin Fandong 已提交
272
        SetSecon(service);
273 274
        ServiceExec(service);
        _exit(PROCESS_EXIT_CODE);
W
wenjun 已提交
275
    } else if (pid < 0) {
Z
zhong_ning 已提交
276
        INIT_LOGE("start service %s fork failed!", service->name);
W
wenjun 已提交
277 278
        return SERVICE_FAILURE;
    }
279
    INIT_LOGI("service %s starting pid %d", service->name, pid);
W
wenjun 已提交
280
    service->pid = pid;
281
    NotifyServiceChange(service->name, "running");
W
wenjun 已提交
282 283 284 285 286
    return SERVICE_SUCCESS;
}

int ServiceStop(Service *service)
{
287
    INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "stop service failed! null ptr.");
X
xionglei6 已提交
288 289 290
    if (service->serviceJobs.jobsName[JOB_ON_STOP] != NULL) {
        DoJobNow(service->serviceJobs.jobsName[JOB_ON_STOP]);
    }
W
wenjun 已提交
291 292 293 294 295
    service->attribute &= ~SERVICE_ATTR_NEED_RESTART;
    service->attribute |= SERVICE_ATTR_NEED_STOP;
    if (service->pid <= 0) {
        return SERVICE_SUCCESS;
    }
X
xionglei6 已提交
296
    CloseServiceSocket(service);
X
xionglei6 已提交
297
    CloseServiceFile(service->fileCfg);
X
xionglei6 已提交
298 299 300 301 302
    // Service stop means service is killed by init or command(i.e stop_service) or system is rebooting
    // There is no reason still to hold fds
    if (service->fdCount != 0) {
        CloseServiceFds(service, true);
    }
X
add ut  
xionglei6 已提交
303 304
    INIT_ERROR_CHECK(kill(service->pid, SIGKILL) == 0, return SERVICE_FAILURE,
        "stop service %s pid %d failed! err %d.", service->name, service->pid, errno);
305
    NotifyServiceChange(service->name, "stopping");
Z
zhong_ning 已提交
306
    INIT_LOGI("stop service %s, pid %d.", service->name, service->pid);
W
wenjun 已提交
307 308 309
    return SERVICE_SUCCESS;
}

S
sun_fan 已提交
310
static bool CalculateCrashTime(Service *service, int crashTimeLimit, int crashCountLimit)
Z
zhong_ning 已提交
311
{
S
sun_fan 已提交
312 313 314 315 316 317
    INIT_ERROR_CHECK(service != NULL && crashTimeLimit > 0 && crashCountLimit > 0, return 0,
        "Service name=%s, input params error.", service->name);
    time_t curTime = time(NULL);
    if (service->crashCnt == 0) {
        service->firstCrashTime = curTime;
        ++service->crashCnt;
X
xionglei6 已提交
318 319 320
        if (service->crashCnt == crashCountLimit) {
            return false;
        }
S
sun_fan 已提交
321 322 323 324 325
    } else if (difftime(curTime, service->firstCrashTime) > crashTimeLimit) {
        service->firstCrashTime = curTime;
        service->crashCnt = 1;
    } else {
        ++service->crashCnt;
X
xionglei6 已提交
326
        if (service->crashCnt >= crashCountLimit) {
S
sun_fan 已提交
327
            return false;
Z
zhong_ning 已提交
328 329
        }
    }
S
sun_fan 已提交
330
    return true;
Z
zhong_ning 已提交
331 332 333 334
}

static int ExecRestartCmd(const Service *service)
{
335 336
    INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "Exec service failed! null ptr.");
    INIT_ERROR_CHECK(service->restartArg != NULL, return SERVICE_FAILURE, "restartArg is null");
Z
zhong_ning 已提交
337

338 339 340
    for (int i = 0; i < service->restartArg->cmdNum; i++) {
        INIT_LOGI("ExecRestartCmd cmdLine->cmdContent %s ", service->restartArg->cmds[i].cmdContent);
        DoCmdByIndex(service->restartArg->cmds[i].cmdIndex, service->restartArg->cmds[i].cmdContent);
Z
zhong_ning 已提交
341
    }
342
    free(service->restartArg);
Z
zhong_ning 已提交
343 344 345
    return SERVICE_SUCCESS;
}

X
xionglei6 已提交
346
static void PollSocketAfresh(Service *service)
X
xionglei6 已提交
347 348 349 350 351 352 353
{
    if (service->socketCfg == NULL) {
        INIT_LOGE("service %s socket config is NULL!", service->name);
        return;
    }
    ServiceSocket *tmpSock = service->socketCfg;
    while (tmpSock != NULL) {
X
xionglei6 已提交
354 355 356 357
        if (tmpSock->sockFd <= 0) {
            INIT_LOGE("Invaid socket %s for service", service->name);
            tmpSock = tmpSock->next;
        }
358
        SocketAddWatcher(&tmpSock->watcher, service, tmpSock->sockFd);
X
xionglei6 已提交
359 360 361 362 363
        tmpSock = tmpSock->next;
    }
    return;
}

W
wenjun 已提交
364 365
void ServiceReap(Service *service)
{
366 367
    INIT_CHECK(service != NULL, return);
    INIT_LOGI("Reap service %s, pid %d.", service->name, service->pid);
Z
zhong_ning 已提交
368
    service->pid = -1;
369 370
    NotifyServiceChange(service->name, "stopped");

Z
zhong_ning 已提交
371
    if (service->attribute & SERVICE_ATTR_INVALID) {
372
        INIT_LOGE("Reap service %s invalid.", service->name);
M
mamingshuai 已提交
373 374
        return;
    }
375

X
xionglei6 已提交
376
    if (!IsOnDemandService(service)) {
X
xionglei6 已提交
377
        CloseServiceSocket(service);
X
xionglei6 已提交
378
    }
X
xionglei6 已提交
379
    CloseServiceFile(service->fileCfg);
W
wenjun 已提交
380 381 382 383 384 385
    // stopped by system-init itself, no need to restart even if it is not one-shot service
    if (service->attribute & SERVICE_ATTR_NEED_STOP) {
        service->attribute &= (~SERVICE_ATTR_NEED_STOP);
        service->crashCnt = 0;
        return;
    }
386

W
wenjun 已提交
387 388 389 390 391 392 393
    // for one-shot service
    if (service->attribute & SERVICE_ATTR_ONCE) {
        // no need to restart
        if (!(service->attribute & SERVICE_ATTR_NEED_RESTART)) {
            service->attribute &= (~SERVICE_ATTR_NEED_STOP);
            return;
        }
394
        // the service could be restart even if it is one-shot service
W
wenjun 已提交
395
    }
396 397

    if (service->attribute & SERVICE_ATTR_CRITICAL) { // critical
X
xionglei6 已提交
398
        if (CalculateCrashTime(service, service->crashTime, service->crashCount) == false) {
S
sun_fan 已提交
399
            INIT_LOGE("Critical service \" %s \" crashed %d times, rebooting system",
X
xionglei6 已提交
400
                service->name, service->crashCount);
401
            ExecReboot("reboot");
S
sun_fan 已提交
402 403
        }
    } else if (!(service->attribute & SERVICE_ATTR_NEED_RESTART)) {
404 405
        if (CalculateCrashTime(service, service->crashTime, service->crashCount) == false) {
            INIT_LOGE("Service name=%s, crash %d times, no more start.", service->name, service->crashCount);
406
            return;
W
wenjun 已提交
407 408
        }
    }
X
xionglei6 已提交
409 410 411 412 413
    // service no need to restart which socket managed by init until socket message detected
    if (IsOnDemandService(service)) {
        PollSocketAfresh(service);
        return;
    }
414

X
xionglei6 已提交
415
    int ret;
416 417
    if (service->restartArg != NULL) {
        ret = ExecRestartCmd(service);
X
add ut  
xionglei6 已提交
418
        INIT_CHECK_ONLY_ELOG(ret == SERVICE_SUCCESS, "Failed to exec restartArg for %s", service->name);
419 420 421 422
    }
    ret = ServiceStart(service);
    if (ret != SERVICE_SUCCESS) {
        INIT_LOGE("reap service %s start failed!", service->name);
Z
zhong_ning 已提交
423
    }
W
wenjun 已提交
424 425
    service->attribute &= (~SERVICE_ATTR_NEED_RESTART);
}
X
xionglei6 已提交
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486

int UpdaterServiceFds(Service *service, int *fds, size_t fdCount)
{
    if (service == NULL) {
        INIT_LOGE("Invalid service info");
        return -1;
    }

    if (fdCount == 0) {
        INIT_LOGE("Update service fds with fdCount is 0, ignore.");
        return 0;
    }

    // if service->fds is NULL, allocate new memory to hold the fds
    // else if service->fds is not NULL, we will try to override it.
    // There are two cases:
    // 1) service->fdCount != fdCount:
    //  It is not easy to re-use the memory of service->fds, so we have to free the memory first
    //  then re-allocate memory to store new fds
    // 2) service->fdCount == fdCount
    //  A situation we happy to meet, just override it.

    int ret = 0;
    if (service->fdCount == fdCount) {
        // case 2
        CloseServiceFds(service, false);
        if (memcpy_s(service->fds, sizeof(int) * (fdCount + 1), fds, sizeof(int) * fdCount) != 0) {
            INIT_LOGE("Failed to copy fds to service");
            // Something wrong happened, maybe service->fds is broken, clear it.
            free(service->fds);
            service->fds = NULL;
            service->fdCount = 0;
            ret = -1;
        } else {
            service->fdCount = fdCount;
        }
    } else {
        if (service->fdCount > 0) {
            // case 1
            CloseServiceFds(service, true);
        }
        service->fds = calloc(fdCount + 1, sizeof(int));
        if (service->fds == NULL) {
            INIT_LOGE("Service \' %s \' failed to allocate memory for fds", service->name);
            ret = -1;
        } else {
            if (memcpy_s(service->fds, sizeof(int) * (fdCount + 1), fds, sizeof(int) * fdCount) != 0) {
                INIT_LOGE("Failed to copy fds to service");
                // Something wrong happened, maybe service->fds is broken, clear it.
                free(service->fds);
                service->fds = NULL;
                service->fdCount = 0;
                return -1;
            } else {
                service->fdCount = fdCount;
            }
        }
    }
    INIT_LOGI("Hold fd for service \' %s \' done", service->name);
    return ret;
}