1/* 2 * Copyright (c) 2022 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 <unistd.h> 17#include <linux/reboot.h> 18#include <sys/reboot.h> 19#include <sys/syscall.h> 20 21#include "reboot_adp.h" 22#include "init_cmdexecutor.h" 23#include "init_module_engine.h" 24#include "init_utils.h" 25#include "plugin_adapter.h" 26#include "securec.h" 27 28#define BUFF_SIZE 256 29#define POWEROFF_REASON_DEV_PATH "/proc/poweroff_reason" 30 31static int WritePowerOffReason(const char* reason) 32{ 33 PLUGIN_CHECK(reason != NULL, return -1, "WritePowerOffReason: reason is NULL\n"); 34 PLUGIN_CHECK(access(POWEROFF_REASON_DEV_PATH, F_OK) == 0, return -1, 35 "WritePowerOffReason: access %s failed, errno = %d, %s\n", 36 POWEROFF_REASON_DEV_PATH, errno, strerror(errno)); 37 int fd = open(POWEROFF_REASON_DEV_PATH, O_RDWR); 38 PLUGIN_CHECK(fd > 0, return -1, "WritePowerOffReason: errno = %d, %s\n", errno, strerror(errno)); 39 int writeBytes = strlen(reason); 40 int ret = write(fd, reason, writeBytes); 41 PLUGIN_CHECK(ret == writeBytes, writeBytes = -1, "WritePowerOffReason: write poweroff reason failed\n"); 42 close(fd); 43 return writeBytes; 44} 45 46static void ParseRebootReason(const char *name, int argc, const char **argv) 47{ 48 char str[BUFF_SIZE] = {0}; 49 int len = sizeof(str); 50 char *tmp = str; 51 int ret; 52 for (int i = 0; i < argc; i++) { 53 ret = sprintf_s(tmp, len - 1, "%s ", argv[i]); 54 if (ret <= 0) { 55 PLUGIN_LOGW("ParseRebootReason: sprintf_s arg %s failed!", argv[i]); 56 break; 57 } 58 len -= ret; 59 tmp += ret; 60 } 61 ret = WritePowerOffReason(str); 62 PLUGIN_CHECK(ret >= 0, return, "ParseRebootReason: write poweroff reason failed\n"); 63} 64 65PLUGIN_STATIC int DoRoot_(const char *jobName, int type) 66{ 67 // by job to stop service and unmount 68 if (jobName != NULL) { 69 DoJobNow(jobName); 70 } 71#ifndef STARTUP_INIT_TEST 72 return reboot(type); 73#else 74 return 0; 75#endif 76} 77 78static int DoReboot(int id, const char *name, int argc, const char **argv) 79{ 80 UNUSED(id); 81 ParseRebootReason(name, argc, argv); 82 // clear misc 83 (void)UpdateMiscMessage(NULL, "reboot", NULL, NULL); 84 return DoRoot_("reboot", RB_AUTOBOOT); 85} 86 87static int DoRebootPanic(int id, const char *name, int argc, const char **argv) 88{ 89 UNUSED(id); 90 ParseRebootReason(name, argc, argv); 91 if (InRescueMode() == 0) { 92 PLUGIN_LOGI("Don't panic in resuce mode!"); 93 return 0; 94 } 95 // clear misc 96 (void)UpdateMiscMessage(NULL, "reboot", NULL, NULL); 97 DoJobNow("reboot"); 98#ifndef STARTUP_INIT_TEST 99 FILE *panic = fopen("/proc/sysrq-trigger", "wb"); 100 if (panic == NULL) { 101 return reboot(RB_AUTOBOOT); 102 } 103 if (fwrite((void *)"c", 1, 1, panic) != 1) { 104 (void)fclose(panic); 105 PLUGIN_LOGI("fwrite to panic failed"); 106 return -1; 107 } 108 (void)fclose(panic); 109#endif 110 return 0; 111} 112 113PLUGIN_STATIC int DoRebootShutdown(int id, const char *name, int argc, const char **argv) 114{ 115 UNUSED(id); 116 PLUGIN_CHECK(argc >= 1, return -1, "Invalid parameter"); 117 ParseRebootReason(name, argc, argv); 118 // clear misc 119 (void)UpdateMiscMessage(NULL, "reboot", NULL, NULL); 120 const size_t len = strlen("reboot,"); 121 const char *cmd = strstr(argv[0], "reboot,"); 122 if (cmd != NULL && strlen(cmd) > len) { 123 PLUGIN_LOGI("DoRebootShutdown argv %s", cmd + len); 124 // by job to stop service and unmount 125 DoJobNow("reboot"); 126#ifndef STARTUP_INIT_TEST 127 return syscall(__NR_reboot, 128 LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_POWER_OFF, cmd + len); 129#else 130 return 0; 131#endif 132 } 133 return DoRoot_("reboot", RB_POWER_OFF); 134} 135 136static int DoRebootUpdater(int id, const char *name, int argc, const char **argv) 137{ 138 UNUSED(id); 139 PLUGIN_LOGI("DoRebootUpdater argc %d %s", argc, name); 140 PLUGIN_CHECK(argc >= 1, return -1, "Invalid parameter"); 141 PLUGIN_LOGI("DoRebootUpdater argv %s", argv[0]); 142 ParseRebootReason(name, argc, argv); 143 int ret = UpdateMiscMessage(argv[0], "updater", "updater:", "boot_updater"); 144 if (ret == 0) { 145 return DoRoot_("reboot", RB_AUTOBOOT); 146 } 147 return ret; 148} 149 150PLUGIN_STATIC int DoRebootFlashed(int id, const char *name, int argc, const char **argv) 151{ 152 UNUSED(id); 153 PLUGIN_LOGI("DoRebootFlashed argc %d %s", argc, name); 154 PLUGIN_CHECK(argc >= 1, return -1, "Invalid parameter"); 155 PLUGIN_LOGI("DoRebootFlashd argv %s", argv[0]); 156 ParseRebootReason(name, argc, argv); 157 int ret = UpdateMiscMessage(argv[0], "flash", "flash:", "boot_flash"); 158 if (ret == 0) { 159 return DoRoot_("reboot", RB_AUTOBOOT); 160 } 161 return ret; 162} 163 164PLUGIN_STATIC int DoRebootCharge(int id, const char *name, int argc, const char **argv) 165{ 166 UNUSED(id); 167 ParseRebootReason(name, argc, argv); 168 int ret = UpdateMiscMessage(NULL, "charge", "charge:", "boot_charge"); 169 if (ret == 0) { 170 return DoRoot_("reboot", RB_AUTOBOOT); 171 } 172 return ret; 173} 174 175static int DoRebootSuspend(int id, const char *name, int argc, const char **argv) 176{ 177 UNUSED(id); 178 ParseRebootReason(name, argc, argv); 179 return DoRoot_("suspend", RB_AUTOBOOT); 180} 181 182PLUGIN_STATIC int DoRebootOther(int id, const char *name, int argc, const char **argv) 183{ 184 UNUSED(id); 185 PLUGIN_CHECK(argc >= 1, return -1, "Invalid parameter argc %d", argc); 186 const char *cmd = strstr(argv[0], "reboot,"); 187 PLUGIN_CHECK(cmd != NULL, return -1, "Invalid parameter argc %s", argv[0]); 188 PLUGIN_LOGI("DoRebootOther argv %s", argv[0]); 189 ParseRebootReason(name, argc, argv); 190 // clear misc 191 (void)UpdateMiscMessage(NULL, "reboot", NULL, NULL); 192 DoJobNow("reboot"); 193#ifndef STARTUP_INIT_TEST 194 return syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, 195 LINUX_REBOOT_CMD_RESTART2, cmd + strlen("reboot,")); 196#else 197 return 0; 198#endif 199} 200 201static void RebootAdpInit(void) 202{ 203 // add default reboot cmd 204 (void)AddCmdExecutor("reboot", DoReboot); 205 (void)AddCmdExecutor("reboot.other", DoRebootOther); 206 AddRebootCmdExecutor("shutdown", DoRebootShutdown); 207 AddRebootCmdExecutor("flashd", DoRebootFlashed); 208 AddRebootCmdExecutor("updater", DoRebootUpdater); 209 AddRebootCmdExecutor("charge", DoRebootCharge); 210 AddRebootCmdExecutor("suspend", DoRebootSuspend); 211 AddRebootCmdExecutor("panic", DoRebootPanic); 212 (void)AddCmdExecutor("panic", DoRebootPanic); 213} 214 215MODULE_CONSTRUCTOR(void) 216{ 217 PLUGIN_LOGI("Reboot adapter plug-in init now ..."); 218 RebootAdpInit(); 219} 220 221MODULE_DESTRUCTOR(void) 222{ 223 PLUGIN_LOGI("Reboot adapter plug-in exit now ..."); 224} 225