init_common_service.c 13.0 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_service.h"
X
xionglei6 已提交
36
#include "init_service_manager.h"
Z
zhong_ning 已提交
37
#include "init_service_socket.h"
Z
zhong_ning 已提交
38
#include "init_utils.h"
Z
zhong_ning 已提交
39
#include "securec.h"
W
wenjun 已提交
40

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

Z
zhong_ning 已提交
46 47 48
#ifndef TIOCSCTTY
#define TIOCSCTTY 0x540E
#endif
Z
zhong_ning 已提交
49

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

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

    // 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 已提交
85
    struct __user_cap_data_struct capData[CAP_NUM] = {};
W
wenjun 已提交
86 87
    for (unsigned int i = 0; i < service->servPerm.capsCnt; ++i) {
        if (service->servPerm.caps[i] == FULL_CAP) {
88 89 90 91
            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 已提交
92 93 94 95 96 97 98 99 100
            }
            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 已提交
101
        INIT_LOGE("capset faild for service: %s, error: %d", service->name, errno);
W
wenjun 已提交
102 103
        return SERVICE_FAILURE;
    }
M
mamingshuai 已提交
104 105 106 107 108
    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 已提交
109
            INIT_LOGE("SetAmbientCapability faild for service: %s", service->name);
M
mamingshuai 已提交
110 111 112
            return SERVICE_FAILURE;
        }
    }
W
wenjun 已提交
113 114 115
    return SERVICE_SUCCESS;
}

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

134
static int WritePid(const Service *service)
S
sun_fan 已提交
135
{
136 137 138 139
    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 已提交
140
    INIT_ERROR_CHECK(len > 0, return SERVICE_FAILURE, "Failed to format pid for service %s", service->name);
141 142
    for (int i = 0; i < service->writePidArgs.count; i++) {
        if (service->writePidArgs.argv[i] == NULL) {
S
sun_fan 已提交
143
            continue;
S
sun_fan 已提交
144
        }
145 146 147 148 149 150 151 152
        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 已提交
153 154
            INIT_CHECK_ONLY_ELOG((int)fwrite(pidString, 1, len, fd) == len,
                "Failed to write %s pid:%s", service->writePidArgs.argv[i], pidString);
155 156 157 158 159 160 161 162
            (void)fclose(fd);
        } else {
            INIT_LOGE("Failed to open %s.", service->writePidArgs.argv[i]);
        }
        if (realPath != NULL) {
            free(realPath);
        }
        INIT_LOGD("ServiceStart writepid filename=%s, childPid=%s, ok", service->writePidArgs.argv[i], pidString);
S
sun_fan 已提交
163
    }
164
    return SERVICE_SUCCESS;
S
sun_fan 已提交
165 166
}

X
xionglei6 已提交
167
void SetSecon(Service *service)
Q
Qin Fandong 已提交
168 169 170 171 172 173 174 175 176 177 178 179
{
#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
}

W
wenjun 已提交
180 181
int ServiceStart(Service *service)
{
S
sun_fan 已提交
182
    INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "start service failed! null ptr.");
183 184 185
    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);
W
wenjun 已提交
186
    if (service->attribute & SERVICE_ATTR_INVALID) {
Z
zhong_ning 已提交
187
        INIT_LOGE("start service %s invalid.", service->name);
W
wenjun 已提交
188 189
        return SERVICE_FAILURE;
    }
190
    struct stat pathStat = { 0 };
W
wenjun 已提交
191
    service->attribute &= (~(SERVICE_ATTR_NEED_RESTART | SERVICE_ATTR_NEED_STOP));
192 193 194 195 196 197
    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 已提交
198
    if (pid == 0) {
X
xionglei6 已提交
199 200 201 202 203
        if (!IsOnDemandService(service)) {
            int ret = CreateServiceSocket(service->socketCfg);
            INIT_ERROR_CHECK(ret >= 0, _exit(PROCESS_EXIT_CODE),
                "service %s exit! create socket failed!", service->name);
        }
X
xionglei6 已提交
204
        CreateServiceFile(service->fileCfg);
Z
zhong_ning 已提交
205 206 207
        if (service->attribute & SERVICE_ATTR_CONSOLE) {
            OpenConsole();
        }
208
        // permissions
X
add ut  
xionglei6 已提交
209 210
        INIT_ERROR_CHECK(SetPerms(service) == SERVICE_SUCCESS, _exit(PROCESS_EXIT_CODE),
            "service %s exit! set perms failed! err %d.", service->name, errno);
211
        // write pid
X
add ut  
xionglei6 已提交
212 213
        INIT_ERROR_CHECK(WritePid(service) == SERVICE_SUCCESS, _exit(PROCESS_EXIT_CODE),
            "service %s exit! write pid failed!", service->name);
Q
Qin Fandong 已提交
214
        SetSecon(service);
215 216
        ServiceExec(service);
        _exit(PROCESS_EXIT_CODE);
W
wenjun 已提交
217
    } else if (pid < 0) {
Z
zhong_ning 已提交
218
        INIT_LOGE("start service %s fork failed!", service->name);
W
wenjun 已提交
219 220
        return SERVICE_FAILURE;
    }
221
    INIT_LOGI("service %s starting pid %d", service->name, pid);
W
wenjun 已提交
222
    service->pid = pid;
223
    NotifyServiceChange(service->name, "running");
W
wenjun 已提交
224 225 226 227 228
    return SERVICE_SUCCESS;
}

int ServiceStop(Service *service)
{
229
    INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "stop service failed! null ptr.");
W
wenjun 已提交
230 231 232 233 234
    service->attribute &= ~SERVICE_ATTR_NEED_RESTART;
    service->attribute |= SERVICE_ATTR_NEED_STOP;
    if (service->pid <= 0) {
        return SERVICE_SUCCESS;
    }
235
    CloseServiceSocket(service->socketCfg);
X
xionglei6 已提交
236
    CloseServiceFile(service->fileCfg);
X
add ut  
xionglei6 已提交
237 238
    INIT_ERROR_CHECK(kill(service->pid, SIGKILL) == 0, return SERVICE_FAILURE,
        "stop service %s pid %d failed! err %d.", service->name, service->pid, errno);
239
    NotifyServiceChange(service->name, "stopping");
Z
zhong_ning 已提交
240
    INIT_LOGI("stop service %s, pid %d.", service->name, service->pid);
W
wenjun 已提交
241 242 243
    return SERVICE_SUCCESS;
}

S
sun_fan 已提交
244
static bool CalculateCrashTime(Service *service, int crashTimeLimit, int crashCountLimit)
Z
zhong_ning 已提交
245
{
S
sun_fan 已提交
246 247 248 249 250 251
    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 已提交
252 253 254
        if (service->crashCnt == crashCountLimit) {
            return false;
        }
S
sun_fan 已提交
255 256 257 258 259
    } else if (difftime(curTime, service->firstCrashTime) > crashTimeLimit) {
        service->firstCrashTime = curTime;
        service->crashCnt = 1;
    } else {
        ++service->crashCnt;
X
xionglei6 已提交
260
        if (service->crashCnt >= crashCountLimit) {
S
sun_fan 已提交
261
            return false;
Z
zhong_ning 已提交
262 263
        }
    }
S
sun_fan 已提交
264
    return true;
Z
zhong_ning 已提交
265 266 267 268
}

static int ExecRestartCmd(const Service *service)
{
269 270
    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 已提交
271

272 273 274
    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 已提交
275
    }
276
    free(service->restartArg);
Z
zhong_ning 已提交
277 278 279
    return SERVICE_SUCCESS;
}

X
xionglei6 已提交
280
static void PollSocketAfresh(Service *service)
X
xionglei6 已提交
281 282 283 284 285 286 287 288 289 290 291 292 293
{
    if (service->socketCfg == NULL) {
        INIT_LOGE("service %s socket config is NULL!", service->name);
        return;
    }
    ServiceSocket *tmpSock = service->socketCfg;
    while (tmpSock != NULL) {
        SocketPollInit(tmpSock->sockFd, service->name);
        tmpSock = tmpSock->next;
    }
    return;
}

W
wenjun 已提交
294 295
void ServiceReap(Service *service)
{
296 297
    INIT_CHECK(service != NULL, return);
    INIT_LOGI("Reap service %s, pid %d.", service->name, service->pid);
Z
zhong_ning 已提交
298
    service->pid = -1;
299 300
    NotifyServiceChange(service->name, "stopped");

Z
zhong_ning 已提交
301
    if (service->attribute & SERVICE_ATTR_INVALID) {
302
        INIT_LOGE("Reap service %s invalid.", service->name);
M
mamingshuai 已提交
303 304
        return;
    }
305

X
xionglei6 已提交
306 307 308
    if (!IsOnDemandService(service)) {
        CloseServiceSocket(service->socketCfg);
    }
X
xionglei6 已提交
309
    CloseServiceFile(service->fileCfg);
W
wenjun 已提交
310 311 312 313 314 315
    // 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;
    }
316

W
wenjun 已提交
317 318 319 320 321 322 323
    // 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;
        }
324
        // the service could be restart even if it is one-shot service
W
wenjun 已提交
325
    }
326 327

    if (service->attribute & SERVICE_ATTR_CRITICAL) { // critical
X
xionglei6 已提交
328
        if (CalculateCrashTime(service, service->crashTime, service->crashCount) == false) {
S
sun_fan 已提交
329
            INIT_LOGE("Critical service \" %s \" crashed %d times, rebooting system",
X
xionglei6 已提交
330
                service->name, service->crashCount);
331
            ExecReboot("reboot");
S
sun_fan 已提交
332 333
        }
    } else if (!(service->attribute & SERVICE_ATTR_NEED_RESTART)) {
X
xionglei6 已提交
334 335
        if (CalculateCrashTime(service, service->crashTime, service->crashCount) == false) {
            INIT_LOGE("Service name=%s, crash %d times, no more start.", service->name, service->crashCount);
S
sun_fan 已提交
336
            return;
W
wenjun 已提交
337 338
        }
    }
X
xionglei6 已提交
339 340 341 342 343
    // service no need to restart which socket managed by init until socket message detected
    if (IsOnDemandService(service)) {
        PollSocketAfresh(service);
        return;
    }
344

X
xionglei6 已提交
345
    int ret;
346 347
    if (service->restartArg != NULL) {
        ret = ExecRestartCmd(service);
X
add ut  
xionglei6 已提交
348
        INIT_CHECK_ONLY_ELOG(ret == SERVICE_SUCCESS, "Failed to exec restartArg for %s", service->name);
349 350 351 352
    }
    ret = ServiceStart(service);
    if (ret != SERVICE_SUCCESS) {
        INIT_LOGE("reap service %s start failed!", service->name);
Z
zhong_ning 已提交
353
    }
W
wenjun 已提交
354 355
    service->attribute &= (~SERVICE_ATTR_NEED_RESTART);
}