init_reboot.c 6.6 KB
Newer Older
Z
zhong_ning 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
 * Copyright (c) 2020 Huawei Device Co., Ltd.
 * 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.
 */

#include "init_reboot.h"

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/prctl.h>
#include <sys/reboot.h>
S
sun_fan 已提交
25 26
#include <unistd.h>
#include "init_log.h"
Z
zhong_ning 已提交
27 28
#include "init_service.h"
#include "init_service_manager.h"
S
sun_fan 已提交
29 30
#include "init_utils.h"
#include "securec.h"
Z
zhong_ning 已提交
31 32 33 34 35 36 37 38 39 40

#define MAX_VALUE_LENGTH 500
#define MAX_COMMAND_SIZE 20
#define MAX_UPDATE_SIZE 100

struct RBMiscUpdateMessage {
    char command[MAX_COMMAND_SIZE];
    char update[MAX_UPDATE_SIZE];
};

S
sun_fan 已提交
41
static bool RBMiscWriteUpdaterMessage(const char *path, const struct RBMiscUpdateMessage *boot)
Z
zhong_ning 已提交
42
{
S
sun_fan 已提交
43 44 45 46
    if (path == NULL || boot == NULL) {
        INIT_LOGE("path or boot is NULL.");
        return false;
    }
S
sun_fan 已提交
47 48 49 50 51
    char *realPath = realpath(path, NULL);
    if (realPath == NULL) {
        return false;
    }
    FILE* fp = fopen(realPath, "rb+");
Z
zhong_ning 已提交
52 53
    if (fp == NULL) {
        INIT_LOGE("open %s failed", path);
S
sun_fan 已提交
54 55
        free(realPath);
        realPath = NULL;
Z
zhong_ning 已提交
56 57 58 59 60
        return false;
    }

    size_t ret = fwrite(boot, sizeof(struct RBMiscUpdateMessage), 1, fp);
    if (ret < 0) {
Z
zhong_ning 已提交
61
        INIT_LOGE("write to misc failed");
S
sun_fan 已提交
62 63
        free(realPath);
        realPath = NULL;
Z
zhong_ning 已提交
64 65 66
        fclose(fp);
        return false;
    }
S
sun_fan 已提交
67 68
    free(realPath);
    realPath = NULL;
Z
zhong_ning 已提交
69 70 71 72 73 74
    fclose(fp);
    return true;
}

static bool RBMiscReadUpdaterMessage(const char *path, struct RBMiscUpdateMessage *boot)
{
S
sun_fan 已提交
75 76 77 78
    if (path == NULL || boot == NULL) {
        INIT_LOGE("path or boot is NULL.");
        return false;
    }
S
sun_fan 已提交
79 80 81 82 83
    char *realPath = realpath(path, NULL);
    if (realPath == NULL) {
        return false;
    }
    FILE* fp = fopen(realPath, "rb");
Z
zhong_ning 已提交
84 85
    if (fp == NULL) {
        INIT_LOGE("open %s failed", path);
S
sun_fan 已提交
86 87
        free(realPath);
        realPath = NULL;
Z
zhong_ning 已提交
88 89 90 91 92 93
        return false;
    }

    size_t ret = fread(boot, 1, sizeof(struct RBMiscUpdateMessage), fp);
    if (ret <= 0) {
        INIT_LOGE("read to misc failed");
S
sun_fan 已提交
94 95
        free(realPath);
        realPath = NULL;
Z
zhong_ning 已提交
96 97 98
        fclose(fp);
        return false;
    }
S
sun_fan 已提交
99 100
    free(realPath);
    realPath = NULL;
Z
zhong_ning 已提交
101 102 103 104 105 106
    fclose(fp);
    return true;
}

static int GetMountStatusForMountPoint(const char *mountPoint)
{
S
sun_fan 已提交
107 108
    const int bufferMaxSize = 512;
    char buffer[bufferMaxSize];
Z
zhong_ning 已提交
109 110 111 112
    size_t n;
    const char *mountFile = "/proc/mounts";
    FILE *fp = fopen(mountFile, "r");
    if (fp == NULL) {
Z
zhong_ning 已提交
113
        INIT_LOGE("DoReboot %s can't open.", mountPoint);
Z
zhong_ning 已提交
114 115 116
        return 1;
    }

S
sun_fan 已提交
117
    while (fgets(buffer, sizeof(buffer) - 1, fp) != NULL) {
Z
zhong_ning 已提交
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
        n = strlen(buffer);
        if (buffer[n - 1] == '\n') {
            buffer[n - 1] = '\0';
        }
        if (strstr(buffer, mountPoint) != NULL) {
            fclose(fp);
            return 1;
        }
    }

    // Cannot find it from system.
    fclose(fp);
    return 0;
}

S
sun_fan 已提交
133
static int CheckAndRebootToUpdater(const char *valueData, const char *cmd, const char *cmdExt, const char *boot)
134
{
S
sun_fan 已提交
135
    // "updater" or "updater:"
136 137
    const char *miscFile = "/dev/block/platform/soc/10100000.himci.eMMC/by-name/misc";
    struct RBMiscUpdateMessage msg;
S
sun_fan 已提交
138 139 140 141 142 143 144 145 146 147 148 149
    bool bRet = RBMiscReadUpdaterMessage(miscFile, &msg);
    INIT_ERROR_CHECK(bRet, return -1, "Failed to get misc info for %s.", cmd);

    int ret = snprintf_s(msg.command, MAX_COMMAND_SIZE, MAX_COMMAND_SIZE - 1, "%s", boot);
    INIT_ERROR_CHECK(ret > 0, return -1, "Failed to format cmd for %s.", cmd);
    msg.command[MAX_COMMAND_SIZE - 1] = 0;

    if (strncmp(valueData, cmdExt, strlen(cmdExt)) == 0) {
        const char *p = valueData + strlen(cmdExt);
        ret = snprintf_s(msg.update, MAX_UPDATE_SIZE, MAX_UPDATE_SIZE - 1, "%s", p);
        INIT_ERROR_CHECK(ret > 0, return -1, "Failed to format param for %s.", cmd);
        msg.update[MAX_UPDATE_SIZE - 1] = 0;
150 151
    }

S
sun_fan 已提交
152 153
    if (RBMiscWriteUpdaterMessage(miscFile, &msg)) {
        return reboot(RB_AUTOBOOT);
154
    }
S
sun_fan 已提交
155
    return -1;
156 157
}

Z
zhong_ning 已提交
158 159
void DoReboot(const char *value)
{
S
sun_fan 已提交
160 161 162 163
    static const char *g_cmdParams[] = {
        "shutdown", "updater", "updater:", "flashing", "flashing:", "NoArgument", "bootloader"
    };
    if (value == NULL || strlen(value) > MAX_VALUE_LENGTH) {
Z
zhong_ning 已提交
164
        INIT_LOGE("DoReboot value = NULL");
Z
zhong_ning 已提交
165 166
        return;
    }
S
sun_fan 已提交
167
    const char *valueData = NULL;
S
sun_fan 已提交
168
    if (strcmp(value, "reboot") == 0) {
169
        valueData = NULL;
S
sun_fan 已提交
170
    } else if (strncmp(value, "reboot,", strlen("reboot,")) != 0) {
Z
zhong_ning 已提交
171
        INIT_LOGE("DoReboot reboot value = %s, must started with reboot ,error.", value);
S
sun_fan 已提交
172
        return;
S
sun_fan 已提交
173 174
    } else {
        valueData = value + strlen("reboot,");
S
sun_fan 已提交
175
    }
S
sun_fan 已提交
176 177 178 179 180 181 182 183 184 185 186
    if (valueData != NULL) {
        size_t i = 0;
        for (; i < ARRAY_LENGTH(g_cmdParams); i++) {
            if (strncmp(valueData, g_cmdParams[i], strlen(g_cmdParams[i])) == 0) {
                break;
            }
        }
        if (i >= ARRAY_LENGTH(g_cmdParams)) {
            INIT_LOGE("DoReboot value = %s, parameters error.", value);
            return;
        }
Z
fix bug  
zhong_ning 已提交
187 188
    }
    StopAllServicesBeforeReboot();
189
    sync();
S
sun_fan 已提交
190 191
    if (GetMountStatusForMountPoint("/vendor") != 0 && umount("/vendor") != 0) {
        INIT_LOGE("DoReboot umount vendor failed! errno = %d.", errno);
Z
zhong_ning 已提交
192
    }
S
sun_fan 已提交
193 194
    if (GetMountStatusForMountPoint("/data") != 0 && umount("/data") != 0) {
        INIT_LOGE("DoReboot umount data failed! errno = %d.", errno);
Z
zhong_ning 已提交
195
    }
S
sun_fan 已提交
196 197 198 199 200 201 202 203 204 205 206
    int ret = 0;
    if (valueData == NULL) {
        ret = reboot(RB_AUTOBOOT);
    } else if (strcmp(valueData, "shutdown") == 0) {
        ret = reboot(RB_POWER_OFF);
    } else if (strcmp(valueData, "bootloader") == 0) {
        ret = reboot(RB_POWER_OFF);
    } else if (strncmp(valueData, "updater", strlen("updater")) == 0) {
        ret = CheckAndRebootToUpdater(valueData, "updater", "updater:", "boot_updater");
    } else if (strncmp(valueData, "flashing", strlen("flashing")) == 0) {
        ret = CheckAndRebootToUpdater(valueData, "flashing", "flashing:", "boot_flashing");
Z
zhong_ning 已提交
207
    }
S
sun_fan 已提交
208
    INIT_LOGI("DoReboot value = %s %s.", value, (ret == 0) ? "success" : "fail");
Z
zhong_ning 已提交
209 210
    return;
}