1d9f0492fSopenharmony_ci/* 2d9f0492fSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd. 3d9f0492fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4d9f0492fSopenharmony_ci * you may not use this file except in compliance with the License. 5d9f0492fSopenharmony_ci * You may obtain a copy of the License at 6d9f0492fSopenharmony_ci * 7d9f0492fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8d9f0492fSopenharmony_ci * 9d9f0492fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10d9f0492fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11d9f0492fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12d9f0492fSopenharmony_ci * See the License for the specific language governing permissions and 13d9f0492fSopenharmony_ci * limitations under the License. 14d9f0492fSopenharmony_ci */ 15d9f0492fSopenharmony_ci 16d9f0492fSopenharmony_ci#include "ueventd_device_handler.h" 17d9f0492fSopenharmony_ci 18d9f0492fSopenharmony_ci#include <errno.h> 19d9f0492fSopenharmony_ci#include <libgen.h> 20d9f0492fSopenharmony_ci#include <limits.h> 21d9f0492fSopenharmony_ci#include <stdbool.h> 22d9f0492fSopenharmony_ci#include <stdlib.h> 23d9f0492fSopenharmony_ci#include <string.h> 24d9f0492fSopenharmony_ci#include <sys/stat.h> 25d9f0492fSopenharmony_ci#include <sys/sysmacros.h> 26d9f0492fSopenharmony_ci#include "init_utils.h" 27d9f0492fSopenharmony_ci#include "ueventd.h" 28d9f0492fSopenharmony_ci#ifndef __RAMDISK__ 29d9f0492fSopenharmony_ci#include "ueventd_parameter.h" 30d9f0492fSopenharmony_ci#endif 31d9f0492fSopenharmony_ci#include "ueventd_read_cfg.h" 32d9f0492fSopenharmony_ci#include "ueventd_utils.h" 33d9f0492fSopenharmony_ci#include "securec.h" 34d9f0492fSopenharmony_ci#define INIT_LOG_TAG "ueventd" 35d9f0492fSopenharmony_ci#include "init_log.h" 36d9f0492fSopenharmony_ci#ifdef WITH_SELINUX 37d9f0492fSopenharmony_ci#include <selinux/selinux.h> 38d9f0492fSopenharmony_ci#include <policycoreutils.h> 39d9f0492fSopenharmony_ci#endif 40d9f0492fSopenharmony_ci 41d9f0492fSopenharmony_cistatic inline void AdjustDeviceNodePermissions(const char *deviceNode, uid_t uid, gid_t gid, mode_t mode) 42d9f0492fSopenharmony_ci{ 43d9f0492fSopenharmony_ci if (INVALIDSTRING(deviceNode)) { 44d9f0492fSopenharmony_ci return; 45d9f0492fSopenharmony_ci } 46d9f0492fSopenharmony_ci if (chown(deviceNode, uid, gid) != 0) { 47d9f0492fSopenharmony_ci INIT_LOGW("Failed to change \" %s \" owner, errno %d", deviceNode, errno); 48d9f0492fSopenharmony_ci } 49d9f0492fSopenharmony_ci 50d9f0492fSopenharmony_ci if (chmod(deviceNode, mode) != 0) { 51d9f0492fSopenharmony_ci INIT_LOGW("Failed to change \" %s \" mode, errno %d", deviceNode, errno); 52d9f0492fSopenharmony_ci } 53d9f0492fSopenharmony_ci} 54d9f0492fSopenharmony_ci 55d9f0492fSopenharmony_cistatic void CreateSymbolLinks(const char *deviceNode, char **symLinks) 56d9f0492fSopenharmony_ci{ 57d9f0492fSopenharmony_ci if (INVALIDSTRING(deviceNode) || symLinks == NULL) { 58d9f0492fSopenharmony_ci return; 59d9f0492fSopenharmony_ci } 60d9f0492fSopenharmony_ci 61d9f0492fSopenharmony_ci uid_t uid = 0; 62d9f0492fSopenharmony_ci gid_t gid = 0; 63d9f0492fSopenharmony_ci mode_t mode = DEVMODE; 64d9f0492fSopenharmony_ci 65d9f0492fSopenharmony_ci for (int i = 0; symLinks[i] != NULL; i++) { 66d9f0492fSopenharmony_ci const char *linkName = symLinks[i]; 67d9f0492fSopenharmony_ci char linkBuf[DEVICE_FILE_SIZE] = {}; 68d9f0492fSopenharmony_ci 69d9f0492fSopenharmony_ci if (strstr(linkName, "/dev/block/by-name") != NULL) { 70d9f0492fSopenharmony_ci int res = GetDeviceNodePermissions(linkName, &uid, &gid, &mode); 71d9f0492fSopenharmony_ci INIT_CHECK(res != 0, AdjustDeviceNodePermissions(deviceNode, uid, gid, mode)); 72d9f0492fSopenharmony_ci } 73d9f0492fSopenharmony_ci 74d9f0492fSopenharmony_ci if (strncpy_s(linkBuf, DEVICE_FILE_SIZE - 1, linkName, strlen(linkName)) != EOK) { 75d9f0492fSopenharmony_ci INIT_LOGE("Failed to copy link name"); 76d9f0492fSopenharmony_ci return; 77d9f0492fSopenharmony_ci } 78d9f0492fSopenharmony_ci const char *linkDir = dirname(linkBuf); 79d9f0492fSopenharmony_ci if (MakeDirRecursive(linkDir, DIRMODE) < 0) { 80d9f0492fSopenharmony_ci INIT_LOGE("[uevent] Failed to create dir \" %s \", err = %d", linkDir, errno); 81d9f0492fSopenharmony_ci return; 82d9f0492fSopenharmony_ci } 83d9f0492fSopenharmony_ci 84d9f0492fSopenharmony_ci errno = 0; 85d9f0492fSopenharmony_ci INIT_LOGI("symlink %s->%s", deviceNode, linkName); 86d9f0492fSopenharmony_ci int rc = symlink(deviceNode, linkName); 87d9f0492fSopenharmony_ci if (rc != 0) { 88d9f0492fSopenharmony_ci if (errno != EEXIST) { 89d9f0492fSopenharmony_ci INIT_LOGE("Failed to link \" %s \" to \" %s \", err = %d", deviceNode, linkName, errno); 90d9f0492fSopenharmony_ci } 91d9f0492fSopenharmony_ci } 92d9f0492fSopenharmony_ci } 93d9f0492fSopenharmony_ci} 94d9f0492fSopenharmony_ci 95d9f0492fSopenharmony_ci#if defined(WITH_SELINUX) && !defined(__RAMDISK__) 96d9f0492fSopenharmony_cistatic void SetDeviceLable(const char *path, char **symLinks) 97d9f0492fSopenharmony_ci{ 98d9f0492fSopenharmony_ci int rc = 0; 99d9f0492fSopenharmony_ci char buffer[PATH_MAX] = {}; 100d9f0492fSopenharmony_ci const char *p = NULL; 101d9f0492fSopenharmony_ci char *slash = NULL; 102d9f0492fSopenharmony_ci 103d9f0492fSopenharmony_ci p = path; 104d9f0492fSopenharmony_ci slash = strchr(path, '/'); 105d9f0492fSopenharmony_ci while (slash != NULL) { 106d9f0492fSopenharmony_ci int gap = slash - p; 107d9f0492fSopenharmony_ci p = slash + 1; 108d9f0492fSopenharmony_ci if (gap == 0) { 109d9f0492fSopenharmony_ci slash = strchr(p, '/'); 110d9f0492fSopenharmony_ci continue; 111d9f0492fSopenharmony_ci } 112d9f0492fSopenharmony_ci if (gap < 0) { // end with '/' 113d9f0492fSopenharmony_ci return; 114d9f0492fSopenharmony_ci } 115d9f0492fSopenharmony_ci 116d9f0492fSopenharmony_ci if (memcpy_s(buffer, PATH_MAX, path, p - path - 1) != EOK) { 117d9f0492fSopenharmony_ci INIT_LOGE("[uevent] Failed to memcpy path %s", path); 118d9f0492fSopenharmony_ci return; 119d9f0492fSopenharmony_ci } 120d9f0492fSopenharmony_ci rc += Restorecon(buffer); 121d9f0492fSopenharmony_ci slash = strchr(p, '/'); 122d9f0492fSopenharmony_ci } 123d9f0492fSopenharmony_ci 124d9f0492fSopenharmony_ci rc += Restorecon(path); 125d9f0492fSopenharmony_ci if (rc != 0) { 126d9f0492fSopenharmony_ci INIT_LOGE("[uevent] Failed to Restorecon \" %s \"", path); 127d9f0492fSopenharmony_ci } 128d9f0492fSopenharmony_ci 129d9f0492fSopenharmony_ci INIT_CHECK_ONLY_RETURN(symLinks != NULL); 130d9f0492fSopenharmony_ci char *context = NULL; 131d9f0492fSopenharmony_ci for (int i = 0; symLinks[i] != NULL; i++) { 132d9f0492fSopenharmony_ci const char *linkName = symLinks[i]; 133d9f0492fSopenharmony_ci const char *byNamePath = "/dev/block/by-name"; 134d9f0492fSopenharmony_ci if (strncmp(linkName, byNamePath, strlen(byNamePath)) == 0) { 135d9f0492fSopenharmony_ci (void)Restorecon(linkName); 136d9f0492fSopenharmony_ci lgetfilecon(linkName, &context); 137d9f0492fSopenharmony_ci if (context != NULL) { 138d9f0492fSopenharmony_ci setfilecon(path, context); 139d9f0492fSopenharmony_ci } 140d9f0492fSopenharmony_ci return; 141d9f0492fSopenharmony_ci } 142d9f0492fSopenharmony_ci } 143d9f0492fSopenharmony_ci 144d9f0492fSopenharmony_ci return; 145d9f0492fSopenharmony_ci} 146d9f0492fSopenharmony_ci#endif 147d9f0492fSopenharmony_ci 148d9f0492fSopenharmony_cistatic int CreateDeviceNode(const struct Uevent *uevent, const char *deviceNode, char **symLinks, bool isBlock) 149d9f0492fSopenharmony_ci{ 150d9f0492fSopenharmony_ci int rc = -1; 151d9f0492fSopenharmony_ci int major = uevent->major; 152d9f0492fSopenharmony_ci int minor = uevent->minor; 153d9f0492fSopenharmony_ci uid_t uid = uevent->ug.uid; 154d9f0492fSopenharmony_ci gid_t gid = uevent->ug.gid; 155d9f0492fSopenharmony_ci mode_t mode = DEVMODE; 156d9f0492fSopenharmony_ci 157d9f0492fSopenharmony_ci if (deviceNode == NULL || *deviceNode == '\0') { 158d9f0492fSopenharmony_ci INIT_LOGE("Invalid device file"); 159d9f0492fSopenharmony_ci return rc; 160d9f0492fSopenharmony_ci } 161d9f0492fSopenharmony_ci 162d9f0492fSopenharmony_ci char deviceNodeBuffer[DEVICE_FILE_SIZE] = {}; 163d9f0492fSopenharmony_ci if (strncpy_s(deviceNodeBuffer, DEVICE_FILE_SIZE - 1, deviceNode, strlen(deviceNode)) != EOK) { 164d9f0492fSopenharmony_ci INIT_LOGE("Failed to copy device node"); 165d9f0492fSopenharmony_ci return rc; 166d9f0492fSopenharmony_ci } 167d9f0492fSopenharmony_ci const char *devicePath = dirname(deviceNodeBuffer); 168d9f0492fSopenharmony_ci // device node always installed in /dev, should not be other locations. 169d9f0492fSopenharmony_ci if (STRINGEQUAL(devicePath, ".") || STRINGEQUAL(devicePath, "/")) { 170d9f0492fSopenharmony_ci INIT_LOGE("device path is not valid. should be starts with /dev"); 171d9f0492fSopenharmony_ci return rc; 172d9f0492fSopenharmony_ci } 173d9f0492fSopenharmony_ci 174d9f0492fSopenharmony_ci rc = MakeDirRecursive(devicePath, DIRMODE); 175d9f0492fSopenharmony_ci if (rc < 0) { 176d9f0492fSopenharmony_ci INIT_LOGE("Create path \" %s \" failed", devicePath); 177d9f0492fSopenharmony_ci return rc; 178d9f0492fSopenharmony_ci } 179d9f0492fSopenharmony_ci 180d9f0492fSopenharmony_ci (void)GetDeviceNodePermissions(deviceNode, &uid, &gid, &mode); 181d9f0492fSopenharmony_ci mode |= isBlock ? S_IFBLK : S_IFCHR; 182d9f0492fSopenharmony_ci dev_t dev = makedev((unsigned int)major, (unsigned int)minor); 183d9f0492fSopenharmony_ci setegid(0); 184d9f0492fSopenharmony_ci rc = mknod(deviceNode, mode, dev); 185d9f0492fSopenharmony_ci if (rc < 0) { 186d9f0492fSopenharmony_ci if (errno != EEXIST) { 187d9f0492fSopenharmony_ci INIT_LOGE("Create device node[%s %d, %d] failed. %d", deviceNode, major, minor, errno); 188d9f0492fSopenharmony_ci return rc; 189d9f0492fSopenharmony_ci } 190d9f0492fSopenharmony_ci } 191d9f0492fSopenharmony_ci AdjustDeviceNodePermissions(deviceNode, uid, gid, mode); 192d9f0492fSopenharmony_ci if (symLinks != NULL) { 193d9f0492fSopenharmony_ci CreateSymbolLinks(deviceNode, symLinks); 194d9f0492fSopenharmony_ci } 195d9f0492fSopenharmony_ci#if defined(WITH_SELINUX) && !defined(__RAMDISK__) 196d9f0492fSopenharmony_ci SetDeviceLable(deviceNode, symLinks); 197d9f0492fSopenharmony_ci#endif 198d9f0492fSopenharmony_ci // No matter what result the symbol links returns, 199d9f0492fSopenharmony_ci // as long as create device node done, just returns success. 200d9f0492fSopenharmony_ci rc = 0; 201d9f0492fSopenharmony_ci return rc; 202d9f0492fSopenharmony_ci} 203d9f0492fSopenharmony_ci 204d9f0492fSopenharmony_cistatic int RemoveDeviceNode(const char *deviceNode, char **symLinks) 205d9f0492fSopenharmony_ci{ 206d9f0492fSopenharmony_ci if (INVALIDSTRING(deviceNode)) { 207d9f0492fSopenharmony_ci INIT_LOGE("Invalid device node"); 208d9f0492fSopenharmony_ci return -1; 209d9f0492fSopenharmony_ci } 210d9f0492fSopenharmony_ci if (symLinks != NULL) { 211d9f0492fSopenharmony_ci for (int i = 0; symLinks[i] != NULL; i++) { 212d9f0492fSopenharmony_ci char realPath[DEVICE_FILE_SIZE] = {0}; 213d9f0492fSopenharmony_ci const char *linkName = symLinks[i]; 214d9f0492fSopenharmony_ci ssize_t ret = readlink(linkName, realPath, DEVICE_FILE_SIZE - 1); 215d9f0492fSopenharmony_ci if (ret < 0) { 216d9f0492fSopenharmony_ci continue; 217d9f0492fSopenharmony_ci } 218d9f0492fSopenharmony_ci if (STRINGEQUAL(deviceNode, realPath)) { 219d9f0492fSopenharmony_ci INIT_LOGI("unlink %s", linkName); 220d9f0492fSopenharmony_ci unlink(linkName); 221d9f0492fSopenharmony_ci } 222d9f0492fSopenharmony_ci } 223d9f0492fSopenharmony_ci } 224d9f0492fSopenharmony_ci INIT_LOGI("unlink %s", deviceNode); 225d9f0492fSopenharmony_ci return unlink(deviceNode); 226d9f0492fSopenharmony_ci} 227d9f0492fSopenharmony_ci 228d9f0492fSopenharmony_cistatic char *FindPlatformDeviceName(char *path) 229d9f0492fSopenharmony_ci{ 230d9f0492fSopenharmony_ci if (INVALIDSTRING(path)) { 231d9f0492fSopenharmony_ci return NULL; 232d9f0492fSopenharmony_ci } 233d9f0492fSopenharmony_ci 234d9f0492fSopenharmony_ci if (STARTSWITH(path, "/sys/devices/platform/")) { 235d9f0492fSopenharmony_ci path += strlen("/sys/devices/platform/"); 236d9f0492fSopenharmony_ci return path; 237d9f0492fSopenharmony_ci } 238d9f0492fSopenharmony_ci 239d9f0492fSopenharmony_ci // Some platform devices may not be registered under platform device. 240d9f0492fSopenharmony_ci if (STARTSWITH(path, "/sys/devices/")) { 241d9f0492fSopenharmony_ci path += strlen("/sys/devices/"); 242d9f0492fSopenharmony_ci return path; 243d9f0492fSopenharmony_ci } 244d9f0492fSopenharmony_ci return NULL; 245d9f0492fSopenharmony_ci} 246d9f0492fSopenharmony_ci 247d9f0492fSopenharmony_cistatic int BuildDeviceSymbolLinks(char **links, int linkNum, const char *parent, 248d9f0492fSopenharmony_ci const char *partitionName, const char *deviceName) 249d9f0492fSopenharmony_ci{ 250d9f0492fSopenharmony_ci int num = linkNum; 251d9f0492fSopenharmony_ci links[num] = calloc(DEVICE_FILE_SIZE, sizeof(char)); 252d9f0492fSopenharmony_ci if (links[num] == NULL) { 253d9f0492fSopenharmony_ci INIT_LOGE("Failed to allocate memory for link, err = %d", errno); 254d9f0492fSopenharmony_ci return num; 255d9f0492fSopenharmony_ci } 256d9f0492fSopenharmony_ci 257d9f0492fSopenharmony_ci // If a block device without partition name. 258d9f0492fSopenharmony_ci // For now, we will not create symbol link for it. 259d9f0492fSopenharmony_ci if (!INVALIDSTRING(partitionName)) { 260d9f0492fSopenharmony_ci if (snprintf_s(links[num], DEVICE_FILE_SIZE, DEVICE_FILE_SIZE - 1, 261d9f0492fSopenharmony_ci "/dev/block/platform/%s/by-name/%s", parent, partitionName) == -1) { 262d9f0492fSopenharmony_ci INIT_LOGE("Failed to build link"); 263d9f0492fSopenharmony_ci } 264d9f0492fSopenharmony_ci if (STRINGEQUAL(parent, bootDevice)) { 265d9f0492fSopenharmony_ci num = linkNum + 1; 266d9f0492fSopenharmony_ci links[num] = calloc(DEVICE_FILE_SIZE, sizeof(char)); 267d9f0492fSopenharmony_ci if (links[num] == NULL) { 268d9f0492fSopenharmony_ci INIT_LOGE("Failed to allocate memory for link, err = %d", errno); 269d9f0492fSopenharmony_ci return linkNum; 270d9f0492fSopenharmony_ci } 271d9f0492fSopenharmony_ci if (snprintf_s(links[num], DEVICE_FILE_SIZE, DEVICE_FILE_SIZE - 1, 272d9f0492fSopenharmony_ci "/dev/block/by-name/%s", partitionName) == -1) { 273d9f0492fSopenharmony_ci INIT_LOGE("Failed to build link"); 274d9f0492fSopenharmony_ci } 275d9f0492fSopenharmony_ci } else { 276d9f0492fSopenharmony_ci INIT_LOGI("%s and %s is not match", parent, bootDevice); 277d9f0492fSopenharmony_ci } 278d9f0492fSopenharmony_ci } else if (!INVALIDSTRING(deviceName)) { 279d9f0492fSopenharmony_ci if (snprintf_s(links[num], DEVICE_FILE_SIZE, DEVICE_FILE_SIZE - 1, 280d9f0492fSopenharmony_ci "/dev/block/platform/%s/%s", parent, deviceName) == -1) { 281d9f0492fSopenharmony_ci INIT_LOGE("Failed to build link"); 282d9f0492fSopenharmony_ci } 283d9f0492fSopenharmony_ci } 284d9f0492fSopenharmony_ci 285d9f0492fSopenharmony_ci return num; 286d9f0492fSopenharmony_ci} 287d9f0492fSopenharmony_ci 288d9f0492fSopenharmony_cistatic void FreeSymbolLinks(char **links, int length) 289d9f0492fSopenharmony_ci{ 290d9f0492fSopenharmony_ci if (links != NULL) { 291d9f0492fSopenharmony_ci for (int i = 0; i < length && links[i] != NULL; i++) { 292d9f0492fSopenharmony_ci free(links[i]); 293d9f0492fSopenharmony_ci links[i] = NULL; 294d9f0492fSopenharmony_ci } 295d9f0492fSopenharmony_ci free(links); 296d9f0492fSopenharmony_ci links = NULL; 297d9f0492fSopenharmony_ci } 298d9f0492fSopenharmony_ci} 299d9f0492fSopenharmony_ci 300d9f0492fSopenharmony_cistatic char **GetBlockDeviceSymbolLinks(const struct Uevent *uevent) 301d9f0492fSopenharmony_ci{ 302d9f0492fSopenharmony_ci if (uevent == NULL || uevent->subsystem == NULL || STRINGEQUAL(uevent->subsystem, "block") == 0) { 303d9f0492fSopenharmony_ci INIT_LOGW("Invalid arguments, Skip to get device symbol links."); 304d9f0492fSopenharmony_ci return NULL; 305d9f0492fSopenharmony_ci } 306d9f0492fSopenharmony_ci 307d9f0492fSopenharmony_ci // Only if current uevent is for real device. 308d9f0492fSopenharmony_ci if (!STARTSWITH(uevent->syspath, "/devices")) { 309d9f0492fSopenharmony_ci return NULL; 310d9f0492fSopenharmony_ci } 311d9f0492fSopenharmony_ci // For block device under one platform device. 312d9f0492fSopenharmony_ci // check subsystem file under directory, see if it links to bus/platform. 313d9f0492fSopenharmony_ci // For now, only support platform device. 314d9f0492fSopenharmony_ci char sysPath[SYSPATH_SIZE] = {}; 315d9f0492fSopenharmony_ci if (snprintf_s(sysPath, SYSPATH_SIZE, SYSPATH_SIZE - 1, "/sys%s", uevent->syspath) == -1) { 316d9f0492fSopenharmony_ci INIT_LOGE("Failed to build sys path for device %s", uevent->syspath); 317d9f0492fSopenharmony_ci return NULL; 318d9f0492fSopenharmony_ci } 319d9f0492fSopenharmony_ci char **links = calloc(BLOCKDEVICE_LINKS, sizeof(char *)); 320d9f0492fSopenharmony_ci int linkNum = 0; 321d9f0492fSopenharmony_ci if (links == NULL) { 322d9f0492fSopenharmony_ci INIT_LOGE("Failed to allocate memory for links, err = %d", errno); 323d9f0492fSopenharmony_ci return NULL; 324d9f0492fSopenharmony_ci } 325d9f0492fSopenharmony_ci 326d9f0492fSopenharmony_ci // Reverse walk through sysPath, and check subsystem file under each directory. 327d9f0492fSopenharmony_ci char *parent = dirname(sysPath); 328d9f0492fSopenharmony_ci while (parent != NULL && !STRINGEQUAL(parent, "/") && !STRINGEQUAL(parent, ".")) { 329d9f0492fSopenharmony_ci char subsystem[SYSPATH_SIZE]; 330d9f0492fSopenharmony_ci if (snprintf_s(subsystem, SYSPATH_SIZE, SYSPATH_SIZE - 1, "%s/subsystem", parent) == -1) { 331d9f0492fSopenharmony_ci INIT_LOGE("Failed to build subsystem path for device \" %s \"", uevent->syspath); 332d9f0492fSopenharmony_ci FreeSymbolLinks(links, BLOCKDEVICE_LINKS); 333d9f0492fSopenharmony_ci return NULL; 334d9f0492fSopenharmony_ci } 335d9f0492fSopenharmony_ci char *bus = GetRealPath(subsystem); 336d9f0492fSopenharmony_ci if (bus == NULL) { 337d9f0492fSopenharmony_ci parent = dirname(parent); 338d9f0492fSopenharmony_ci continue; 339d9f0492fSopenharmony_ci } 340d9f0492fSopenharmony_ci if (STRINGEQUAL(bus, "/sys/bus/platform")) { 341d9f0492fSopenharmony_ci INIT_LOGV("Find a platform device: %s", parent); 342d9f0492fSopenharmony_ci parent = FindPlatformDeviceName(parent); 343d9f0492fSopenharmony_ci if (parent != NULL) { 344d9f0492fSopenharmony_ci INIT_WARNING_CHECK(linkNum < BLOCKDEVICE_LINKS - 1, links[linkNum] = NULL; 345d9f0492fSopenharmony_ci return links, "Too many links, ignore"); 346d9f0492fSopenharmony_ci linkNum = BuildDeviceSymbolLinks(links, linkNum, parent, uevent->partitionName, uevent->deviceName); 347d9f0492fSopenharmony_ci linkNum++; 348d9f0492fSopenharmony_ci } 349d9f0492fSopenharmony_ci } 350d9f0492fSopenharmony_ci free(bus); 351d9f0492fSopenharmony_ci parent = dirname(parent); 352d9f0492fSopenharmony_ci } 353d9f0492fSopenharmony_ci 354d9f0492fSopenharmony_ci links[linkNum] = NULL; 355d9f0492fSopenharmony_ci return links; 356d9f0492fSopenharmony_ci} 357d9f0492fSopenharmony_ci 358d9f0492fSopenharmony_cistatic void HandleDeviceNode(const struct Uevent *uevent, const char *deviceNode, bool isBlock) 359d9f0492fSopenharmony_ci{ 360d9f0492fSopenharmony_ci ACTION action = uevent->action; 361d9f0492fSopenharmony_ci char **symLinks = NULL; 362d9f0492fSopenharmony_ci 363d9f0492fSopenharmony_ci // Block device path and name maybe not human readable. 364d9f0492fSopenharmony_ci // Consider to create symbol links for them. 365d9f0492fSopenharmony_ci // Make block device more readable. 366d9f0492fSopenharmony_ci if (isBlock) { 367d9f0492fSopenharmony_ci symLinks = GetBlockDeviceSymbolLinks(uevent); 368d9f0492fSopenharmony_ci } 369d9f0492fSopenharmony_ci 370d9f0492fSopenharmony_ci if (action == ACTION_ADD) { 371d9f0492fSopenharmony_ci if (CreateDeviceNode(uevent, deviceNode, symLinks, isBlock) < 0) { 372d9f0492fSopenharmony_ci INIT_LOGE("Create device \" %s \" failed", deviceNode); 373d9f0492fSopenharmony_ci } else { 374d9f0492fSopenharmony_ci#ifndef __RAMDISK__ 375d9f0492fSopenharmony_ci if (SetUeventDeviceParameter(deviceNode, action) != 0) { 376d9f0492fSopenharmony_ci INIT_LOGE("Set device parameter added failed"); 377d9f0492fSopenharmony_ci } 378d9f0492fSopenharmony_ci#endif 379d9f0492fSopenharmony_ci } 380d9f0492fSopenharmony_ci } else if (action == ACTION_REMOVE) { 381d9f0492fSopenharmony_ci if (RemoveDeviceNode(deviceNode, symLinks) < 0) { 382d9f0492fSopenharmony_ci INIT_LOGE("Remove device \" %s \" failed", deviceNode); 383d9f0492fSopenharmony_ci } else { 384d9f0492fSopenharmony_ci#ifndef __RAMDISK__ 385d9f0492fSopenharmony_ci if (SetUeventDeviceParameter(deviceNode, action) != 0) { 386d9f0492fSopenharmony_ci INIT_LOGE("Set device parameter removed failed"); 387d9f0492fSopenharmony_ci } 388d9f0492fSopenharmony_ci#endif 389d9f0492fSopenharmony_ci } 390d9f0492fSopenharmony_ci } else if (action == ACTION_CHANGE) { 391d9f0492fSopenharmony_ci INIT_LOGV("Device %s changed", uevent->syspath); 392d9f0492fSopenharmony_ci } 393d9f0492fSopenharmony_ci // Ignore other actions 394d9f0492fSopenharmony_ci FreeSymbolLinks(symLinks, BLOCKDEVICE_LINKS); 395d9f0492fSopenharmony_ci} 396d9f0492fSopenharmony_ci 397d9f0492fSopenharmony_cistatic const char *GetDeviceName(char *sysPath, const char *deviceName) 398d9f0492fSopenharmony_ci{ 399d9f0492fSopenharmony_ci const char *devName = NULL; 400d9f0492fSopenharmony_ci if (INVALIDSTRING(sysPath)) { 401d9f0492fSopenharmony_ci INIT_LOGE("Invalid sys path"); 402d9f0492fSopenharmony_ci return NULL; 403d9f0492fSopenharmony_ci } 404d9f0492fSopenharmony_ci if (deviceName != NULL && deviceName[0] != '\0') { 405d9f0492fSopenharmony_ci // if device name reported by kernel includes '/', skip it. 406d9f0492fSopenharmony_ci // use entire device name reported by kernel 407d9f0492fSopenharmony_ci devName = basename((char *)deviceName); 408d9f0492fSopenharmony_ci char *p = strrchr(deviceName, '/'); 409d9f0492fSopenharmony_ci if (p != NULL) { // device name includes slash 410d9f0492fSopenharmony_ci p++; 411d9f0492fSopenharmony_ci if (p == NULL || *p == '\0') { 412d9f0492fSopenharmony_ci // device name ends with '/', which should never happen. 413d9f0492fSopenharmony_ci // Get name from sys path. 414d9f0492fSopenharmony_ci devName = basename(sysPath); 415d9f0492fSopenharmony_ci } else { 416d9f0492fSopenharmony_ci devName = p; 417d9f0492fSopenharmony_ci } 418d9f0492fSopenharmony_ci } 419d9f0492fSopenharmony_ci } else { 420d9f0492fSopenharmony_ci // kernel does not report DEVNAME, which is possible. use base name of syspath instead. 421d9f0492fSopenharmony_ci devName = basename(sysPath); 422d9f0492fSopenharmony_ci } 423d9f0492fSopenharmony_ci return devName; 424d9f0492fSopenharmony_ci} 425d9f0492fSopenharmony_ci 426d9f0492fSopenharmony_cistatic const char *GetDeviceBasePath(const char *subsystem) 427d9f0492fSopenharmony_ci{ 428d9f0492fSopenharmony_ci char *devPath = NULL; 429d9f0492fSopenharmony_ci if (INVALIDSTRING(subsystem)) { 430d9f0492fSopenharmony_ci return devPath; 431d9f0492fSopenharmony_ci } 432d9f0492fSopenharmony_ci 433d9f0492fSopenharmony_ci if (STRINGEQUAL(subsystem, "block")) { 434d9f0492fSopenharmony_ci devPath = "/dev/block"; 435d9f0492fSopenharmony_ci } else if (STRINGEQUAL(subsystem, "input")) { 436d9f0492fSopenharmony_ci devPath = "/dev/input"; 437d9f0492fSopenharmony_ci } else if (STRINGEQUAL(subsystem, "drm")) { 438d9f0492fSopenharmony_ci devPath = "/dev/dri"; 439d9f0492fSopenharmony_ci } else if (STRINGEQUAL(subsystem, "graphics")) { 440d9f0492fSopenharmony_ci devPath = "/dev/graphics"; 441d9f0492fSopenharmony_ci } else if (STRINGEQUAL(subsystem, "sound")) { 442d9f0492fSopenharmony_ci devPath = "/dev/snd"; 443d9f0492fSopenharmony_ci } else if (STRINGEQUAL(subsystem, "functionfs")) { 444d9f0492fSopenharmony_ci devPath = "/dev/functionfs"; 445d9f0492fSopenharmony_ci } else if (STRINGEQUAL(subsystem, "dma_heap")) { 446d9f0492fSopenharmony_ci devPath = "/dev/dma_heap"; 447d9f0492fSopenharmony_ci } else { 448d9f0492fSopenharmony_ci devPath = "/dev"; 449d9f0492fSopenharmony_ci } 450d9f0492fSopenharmony_ci return devPath; 451d9f0492fSopenharmony_ci} 452d9f0492fSopenharmony_ci 453d9f0492fSopenharmony_civoid HandleBlockDeviceEvent(const struct Uevent *uevent) 454d9f0492fSopenharmony_ci{ 455d9f0492fSopenharmony_ci // Sanity checks 456d9f0492fSopenharmony_ci if (uevent == NULL || uevent->subsystem == NULL) { 457d9f0492fSopenharmony_ci INIT_LOGE("Invalid uevent message received"); 458d9f0492fSopenharmony_ci return; 459d9f0492fSopenharmony_ci } 460d9f0492fSopenharmony_ci 461d9f0492fSopenharmony_ci if (strcmp(uevent->subsystem, "block") != 0) { 462d9f0492fSopenharmony_ci INIT_LOGE("Unexpected uevent subsystem \" %s \" received in block device handler", uevent->subsystem); 463d9f0492fSopenharmony_ci return; 464d9f0492fSopenharmony_ci } 465d9f0492fSopenharmony_ci 466d9f0492fSopenharmony_ci if (uevent->major < 0 || uevent->minor < 0) { 467d9f0492fSopenharmony_ci return; 468d9f0492fSopenharmony_ci } 469d9f0492fSopenharmony_ci 470d9f0492fSopenharmony_ci bool isBlock = true; 471d9f0492fSopenharmony_ci // Block device always installed into /dev/block 472d9f0492fSopenharmony_ci const char *devPath = GetDeviceBasePath(uevent->subsystem); 473d9f0492fSopenharmony_ci char deviceNode[DEVICE_FILE_SIZE] = {}; 474d9f0492fSopenharmony_ci char sysPath[SYSPATH_SIZE] = {}; 475d9f0492fSopenharmony_ci 476d9f0492fSopenharmony_ci if (uevent->syspath == NULL) { 477d9f0492fSopenharmony_ci return; 478d9f0492fSopenharmony_ci } 479d9f0492fSopenharmony_ci if (strncpy_s(sysPath, SYSPATH_SIZE - 1, uevent->syspath, strlen(uevent->syspath) != EOK)) { 480d9f0492fSopenharmony_ci INIT_LOGE("Failed to copy sys path"); 481d9f0492fSopenharmony_ci return; 482d9f0492fSopenharmony_ci } 483d9f0492fSopenharmony_ci const char *devName = GetDeviceName(sysPath, uevent->deviceName); 484d9f0492fSopenharmony_ci 485d9f0492fSopenharmony_ci if (devPath == NULL || devName == NULL) { 486d9f0492fSopenharmony_ci INIT_LOGE("Cannot get device path or device name"); 487d9f0492fSopenharmony_ci return; 488d9f0492fSopenharmony_ci } 489d9f0492fSopenharmony_ci if (snprintf_s(deviceNode, DEVICE_FILE_SIZE, DEVICE_FILE_SIZE - 1, "%s/%s", devPath, devName) == -1) { 490d9f0492fSopenharmony_ci INIT_LOGE("Make device file for device [%d : %d]", uevent->major, uevent->minor); 491d9f0492fSopenharmony_ci return; 492d9f0492fSopenharmony_ci } 493d9f0492fSopenharmony_ci HandleDeviceNode(uevent, deviceNode, isBlock); 494d9f0492fSopenharmony_ci} 495d9f0492fSopenharmony_ci 496d9f0492fSopenharmony_civoid HandleOtherDeviceEvent(const struct Uevent *uevent) 497d9f0492fSopenharmony_ci{ 498d9f0492fSopenharmony_ci if (uevent == NULL || uevent->subsystem == NULL || uevent->syspath == NULL) { 499d9f0492fSopenharmony_ci INIT_LOGE("Invalid uevent received"); 500d9f0492fSopenharmony_ci return; 501d9f0492fSopenharmony_ci } 502d9f0492fSopenharmony_ci 503d9f0492fSopenharmony_ci if (uevent->major < 0 || uevent->minor < 0) { 504d9f0492fSopenharmony_ci return; 505d9f0492fSopenharmony_ci } 506d9f0492fSopenharmony_ci 507d9f0492fSopenharmony_ci char deviceNode[DEVICE_FILE_SIZE] = {}; 508d9f0492fSopenharmony_ci char sysPath[SYSPATH_SIZE] = {}; 509d9f0492fSopenharmony_ci if (strncpy_s(sysPath, SYSPATH_SIZE - 1, uevent->syspath, strlen(uevent->syspath)) != EOK) { 510d9f0492fSopenharmony_ci INIT_LOGE("Failed to copy sys path"); 511d9f0492fSopenharmony_ci return; 512d9f0492fSopenharmony_ci } 513d9f0492fSopenharmony_ci const char *devName = GetDeviceName(sysPath, uevent->deviceName); 514d9f0492fSopenharmony_ci const char *devPath = GetDeviceBasePath(uevent->subsystem); 515d9f0492fSopenharmony_ci 516d9f0492fSopenharmony_ci if (devPath == NULL || devName == NULL) { 517d9f0492fSopenharmony_ci INIT_LOGE("Cannot get device path or device name"); 518d9f0492fSopenharmony_ci return; 519d9f0492fSopenharmony_ci } 520d9f0492fSopenharmony_ci INIT_LOGV("HandleOtherDeviceEvent, devPath = %s, devName = %s", devPath, devName); 521d9f0492fSopenharmony_ci 522d9f0492fSopenharmony_ci // For usb devices, should take care of it specially. 523d9f0492fSopenharmony_ci // if usb devices report DEVNAME, just create device node. 524d9f0492fSopenharmony_ci // otherwise, create deviceNode with bus number and device number. 525d9f0492fSopenharmony_ci if (STRINGEQUAL(uevent->subsystem, "usb")) { 526d9f0492fSopenharmony_ci if (uevent->deviceName != NULL) { 527d9f0492fSopenharmony_ci if (snprintf_s(deviceNode, DEVICE_FILE_SIZE, DEVICE_FILE_SIZE - 1, "/dev/%s", uevent->deviceName) == -1) { 528d9f0492fSopenharmony_ci INIT_LOGE("Make device file for device [%d : %d]", uevent->major, uevent->minor); 529d9f0492fSopenharmony_ci return; 530d9f0492fSopenharmony_ci } 531d9f0492fSopenharmony_ci } else { 532d9f0492fSopenharmony_ci if (uevent->busNum < 0 || uevent->devNum < 0) { 533d9f0492fSopenharmony_ci // usb device should always report bus number and device number. 534d9f0492fSopenharmony_ci INIT_LOGE("usb device with invalid bus number or device number"); 535d9f0492fSopenharmony_ci return; 536d9f0492fSopenharmony_ci } 537d9f0492fSopenharmony_ci if (snprintf_s(deviceNode, DEVICE_FILE_SIZE, DEVICE_FILE_SIZE - 1, 538d9f0492fSopenharmony_ci "/dev/bus/usb/%03d/%03d", uevent->busNum, uevent->devNum) == -1) { 539d9f0492fSopenharmony_ci INIT_LOGE("Make usb device node for device [%d : %d]", uevent->busNum, uevent->devNum); 540d9f0492fSopenharmony_ci } 541d9f0492fSopenharmony_ci } 542d9f0492fSopenharmony_ci } else if (STARTSWITH(uevent->subsystem, "usb")) { 543d9f0492fSopenharmony_ci // Other usb devies, do not handle it. 544d9f0492fSopenharmony_ci return; 545d9f0492fSopenharmony_ci } else { 546d9f0492fSopenharmony_ci if (strcmp(uevent->deviceName, "mapper/control") == 0) { 547d9f0492fSopenharmony_ci devName = "mapper/control"; 548d9f0492fSopenharmony_ci } 549d9f0492fSopenharmony_ci if (snprintf_s(deviceNode, DEVICE_FILE_SIZE, DEVICE_FILE_SIZE - 1, "%s/%s", devPath, devName) == -1) { 550d9f0492fSopenharmony_ci INIT_LOGE("Make device file for device [%d : %d]", uevent->major, uevent->minor); 551d9f0492fSopenharmony_ci return; 552d9f0492fSopenharmony_ci } 553d9f0492fSopenharmony_ci } 554d9f0492fSopenharmony_ci HandleDeviceNode(uevent, deviceNode, false); 555d9f0492fSopenharmony_ci} 556