diff --git a/ohos.build b/ohos.build index c6cdbf243676ed456a75ccd691441b85613a6645..a8ef47b0a3477a78a0bcf6fbf4077ca1a0450568 100644 --- a/ohos.build +++ b/ohos.build @@ -3,7 +3,9 @@ "parts": { "init": { "module_list": [ - "//base/startup/init_lite/services:startup_init" + "//base/startup/init_lite/services:startup_init", + "//base/startup/init_lite/ueventd:ueventd", + "//base/startup/init_lite/ueventd:ueventd.config" ] } } diff --git a/services/BUILD.gn b/services/BUILD.gn index 8366d79f31da29e24928941da7b0bdbdbe520fb8..1994c2efafb84e51013f454979fdc76ae94f7bf0 100644 --- a/services/BUILD.gn +++ b/services/BUILD.gn @@ -84,28 +84,6 @@ if (defined(ohos_lite)) { } } else { import("//build/ohos.gni") - ohos_executable("updaterueventd") { - sources = [ - "src/list.c", - "src/uevent.c", - ] - include_dirs = [ - "include", - "//third_party/bounds_checking_function/include", - "//base/startup/init_lite/services/log", - ] - deps = [ - "//base/startup/init_lite/services/log:init_log", - "//third_party/bounds_checking_function:libsec_static", - ] - module_install_dir = "bin" - install_images = [ - "system", - "updater", - ] - install_enable = true - part_name = "init" - } ohos_executable("init") { sources = [ @@ -156,7 +134,6 @@ if (defined(ohos_lite)) { deps = [ ":init", ":init_etc", - ":updaterueventd", "//base/startup/init_lite/interfaces/innerkits/socket:libsocket", "//base/startup/init_lite/services/cmds/reboot:reboot", "//base/startup/init_lite/services/cmds/service_control:service_control", diff --git a/services/etc/init.cfg b/services/etc/init.cfg index 5d82483ef3a39bf534c9b74edf4652321fa8d447..f435edbd6f0f03de580243ef5d76dd903224d7fd 100755 --- a/services/etc/init.cfg +++ b/services/etc/init.cfg @@ -474,7 +474,7 @@ ], "services" : [{ "name" : "ueventd", - "path" : ["/system/bin/updaterueventd"], + "path" : ["/system/bin/ueventd"], "critical" : 1 }, { "name" : "console", diff --git a/services/etc/ohos.para b/services/etc/ohos.para index 9e1d571f0a50183aa6e9f1fdcb36725375e92897..f53e55ad3588c8a2cb9cd2054a60bae68ebb52b6 100755 --- a/services/etc/ohos.para +++ b/services/etc/ohos.para @@ -33,7 +33,7 @@ ro.secure=1 security.perf_harden=1 ro.allow.mock.location=0 ro.debuggable=1 -ro.build.characteristics="Default" +ro.build.characteristics="default" ro.product.model="ohos" ro.product.name="OpenHarmony 2.0 Canary" persist.sys.usb.config=hdc diff --git a/services/src/uevent.c b/services/src/uevent.c deleted file mode 100644 index 759a3401271dbeea760b03b884bec03dec6b2435..0000000000000000000000000000000000000000 --- a/services/src/uevent.c +++ /dev/null @@ -1,828 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "init_log.h" -#include "list.h" -#include "securec.h" - -#define LINK_NUMBER 4 -#define DEFAULT_DIR_MODE (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) -#define TRIGGER_ADDR_SIZE 4 -#define BASE_BUFFER_SIZE 1024 -#define MAX_BUFFER 256 -#define EVENT_MAX_BUFFER 1026 -#define MAX_DEV_PATH 96 -#define MINORS_GROUPS 128 -#define SYS_LINK_NUMBER 2 -#define MAX_DEVICE_LEN 64 -#define DEFAULT_MODE 0000 -#define DEVICE_DEFAULT_MODE (S_IRUSR | S_IWUSR | S_IRGRP) - -int g_ueventFD = -1; - -struct Uevent { - const char *action; - const char *path; - const char *subsystem; - const char *firmware; - const char *partitionName; - const char *deviceName; - int partitionNum; - int major; - int minor; -}; - -struct PlatformSubsystem { - char *name; - char *path; - size_t pathLen; - struct ListNode list; -}; - -static struct ListNode g_platformNames = { - .next = &g_platformNames, - .prev = &g_platformNames, -}; - -const char *g_trigger = "/dev/.trigger_uevent"; -static void HandleUevent(); - -static int UeventFD() -{ - return g_ueventFD; -} - -static void DoTrigger(DIR *dir, const char *path, int32_t pathLen) -{ - if (pathLen < 0) { - return; - } - struct dirent *dirent = NULL; - char ueventPath[MAX_BUFFER]; - if (snprintf_s(ueventPath, sizeof(ueventPath), sizeof(ueventPath) - 1, "%s/uevent", path) == -1) { - return; - } - int fd = open(ueventPath, O_WRONLY); - if (fd >= 0) { - write(fd, "add\n", TRIGGER_ADDR_SIZE); - close(fd); - HandleUevent(); - } - - while ((dirent = readdir(dir)) != NULL) { - if (dirent->d_name[0] == '.' || dirent->d_type != DT_DIR) { - continue; - } - char tmpPath[MAX_BUFFER]; - if (snprintf_s(tmpPath, sizeof(tmpPath), sizeof(tmpPath) - 1, "%s/%s", path, dirent->d_name) == -1) { - continue; - } - - DIR *dir2 = opendir(tmpPath); - if (dir2) { - DoTrigger(dir2, tmpPath, strlen(tmpPath)); - closedir(dir2); - } - } -} - -void Trigger(const char *sysPath) -{ - DIR *dir = opendir(sysPath); - if (dir) { - DoTrigger(dir, sysPath, strlen(sysPath)); - closedir(dir); - } -} - -static void RetriggerUevent() -{ - if (access(g_trigger, F_OK) == 0) { - INIT_LOGI("Skip trigger uevent, alread done"); - return; - } - Trigger("/sys/class"); - Trigger("/sys/block"); - Trigger("/sys/devices"); - int fd = open(g_trigger, O_WRONLY | O_CREAT | O_CLOEXEC, DEFAULT_MODE); - if (fd >= 0) { - close(fd); - } - INIT_LOGI("Re-trigger uevent done"); -} - -static void UeventSockInit() -{ - struct sockaddr_nl addr; - int buffSize = MAX_BUFFER * BASE_BUFFER_SIZE; - int on = 1; - - if (memset_s(&addr, sizeof(addr), 0, sizeof(addr)) != 0) { - return; - } - addr.nl_family = AF_NETLINK; - addr.nl_pid = getpid(); - addr.nl_groups = 0xffffffff; - - int sockfd = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT); - if (sockfd < 0) { - INIT_LOGE("Create socket failed. %d", errno); - return; - } - - setsockopt(sockfd, SOL_SOCKET, SO_RCVBUFFORCE, &buffSize, sizeof(buffSize)); - setsockopt(sockfd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); - - if (bind(sockfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - INIT_LOGE("Bind socket failed. %d", errno); - close(sockfd); - return; - } - g_ueventFD = sockfd; - fcntl(g_ueventFD, F_SETFD, FD_CLOEXEC); - fcntl(g_ueventFD, F_SETFL, O_NONBLOCK); - RetriggerUevent(); - return; -} - -ssize_t ReadUeventMessage(int fd, void *buf, size_t len) -{ - struct iovec iov = { buf, len }; - struct sockaddr_nl addr; - char control[CMSG_SPACE(sizeof(struct ucred))]; - struct msghdr hdr; - hdr.msg_name = &addr; - hdr.msg_namelen = sizeof(addr); - hdr.msg_iov = &iov; - hdr.msg_iovlen = 1; - hdr.msg_control = control; - hdr.msg_controllen = sizeof(control); - hdr.msg_flags = 0; - ssize_t n = recvmsg(fd, &hdr, 0); - INIT_CHECK_RETURN_VALUE(n > 0, n); - struct cmsghdr *cMsg = CMSG_FIRSTHDR(&hdr); - if (cMsg == NULL || cMsg->cmsg_type != SCM_CREDENTIALS) { - bzero(buf, len); - errno = -EIO; - return n; - } - struct ucred *cRed = (struct ucred *)CMSG_DATA(cMsg); - if (cRed->uid != 0) { - bzero(buf, len); - errno = -EIO; - return n; - } - - if (addr.nl_groups == 0 || addr.nl_pid != 0) { - /* ignoring non-kernel or unicast netlink message */ - bzero(buf, len); - errno = -EIO; - return n; - } - - return n; -} - -static void InitUevent(struct Uevent *event) -{ - event->action = ""; - event->path = ""; - event->subsystem = ""; - event->firmware = ""; - event->partitionName = ""; - event->deviceName = ""; - event->partitionNum = -1; - event->major = -1; - event->minor = -1; -} - -static inline const char *ParseUeventMessage(const char **buf, const char *name) -{ - if (strncmp(*buf, name, strlen(name)) == 0) { - *buf += strlen(name); - return *buf; - } else { - return NULL; - } -} - -static void ParseUevent(const char *buf, struct Uevent *event) -{ - InitUevent(event); - while (*buf) { - if (ParseUeventMessage(&buf, "ACTION=")) { - event->action = buf; - } else if (ParseUeventMessage(&buf, "DEVPATH=")) { - event->path = buf; - } else if (ParseUeventMessage(&buf, "SUBSYSTEM=")) { - event->subsystem = buf; - } else if (ParseUeventMessage(&buf, "FIRMWARE=")) { - event->firmware = buf; - } else if (ParseUeventMessage(&buf, "MAJOR=")) { - event->major = atoi(buf); - } else if (ParseUeventMessage(&buf, "MINOR=")) { - event->minor = atoi(buf); - } else if (ParseUeventMessage(&buf, "PARTN=")) { - event->partitionNum = atoi(buf); - } else if (ParseUeventMessage(&buf, "PARTNAME=")) { - event->partitionName = buf; - } else if (ParseUeventMessage(&buf, "DEVNAME=")) { - event->deviceName = buf; - } - // Drop reset. - while (*buf++) {} - } -} - -static int MakeDir(const char *path, mode_t mode) -{ - int rc = mkdir(path, mode); - if (rc < 0 && errno != EEXIST) { - INIT_LOGE("Create %s failed. %d", path, errno); - } - return rc; -} - -static struct PlatformSubsystem *FindPlatformDevice(const char *path) -{ - size_t pathLen = strlen(path); - struct ListNode *node = NULL; - struct PlatformSubsystem *bus = NULL; - - for (node = (&g_platformNames)->prev; node != &g_platformNames; node = node->prev) { - bus = (struct PlatformSubsystem *)(((char*)(node)) - offsetof(struct PlatformSubsystem, list)); - if ((bus->pathLen < pathLen) && (path[bus->pathLen] == '/') && !strncmp(path, bus->path, bus->pathLen)) { - return bus; - } - } - return NULL; -} - -static void CheckValidPartitionName(char *partitionName) -{ - INIT_CHECK_ONLY_RETURN(partitionName != NULL); - const char* supportPartition = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-"; - for (size_t i = 0; i < strlen(partitionName); i++) { - int len = strspn(partitionName, supportPartition); - partitionName += len; - i = len; - if (*partitionName) { - *partitionName = '_'; - } - } -} - -static char **ParsePlatformBlockDevice(const struct Uevent *uevent) -{ - char linkPath[MAX_BUFFER]; - int linkNum = 0; - char *p = NULL; - - struct PlatformSubsystem *node = FindPlatformDevice(uevent->path); - INIT_CHECK_RETURN_VALUE(node != NULL, NULL); - - char **links = calloc(sizeof(char *), LINK_NUMBER); - INIT_CHECK_RETURN_VALUE(links != NULL, NULL); - if (snprintf_s(linkPath, sizeof(linkPath), sizeof(linkPath) - 1, "/dev/block/%s/%s", "platform", - node->name) == -1) { - free(links); - return NULL; - } - if (uevent->partitionName) { - p = strdup(uevent->partitionName); - CheckValidPartitionName(p); - if (strcmp(uevent->partitionName, p)) { - INIT_LOGI("Linking partition '%s' as '%s'", uevent->partitionName, p); - } - if (asprintf(&links[linkNum], "%s/by-name/%s", linkPath, p) > 0) { - linkNum++; - } else { - links[linkNum] = NULL; - } - free(p); - } - if (uevent->partitionNum >= 0) { - if (asprintf(&links[linkNum], "%s/by-num/p%d", linkPath, uevent->partitionNum) > 0) { - linkNum++; - } else { - links[linkNum] = NULL; - } - } - char *linkPos = strrchr(uevent->path, '/'); - if (asprintf(&links[linkNum], "%s/%s", linkPath, linkPos + 1) > 0) { - linkNum++; - } else { - links[linkNum] = NULL; - } - return links; -} - -struct DevPermissionMapper { - char *devName; - mode_t devMode; - uid_t uid; - gid_t gid; -}; - -struct DevPermissionMapper DEV_MAPPER[] = { - {"/dev/binder", 0666, 0, 0}, - {"/dev/input/event0", 0660, 0, 0}, - {"/dev/input/event1", 0660, 0, 1004}, - {"/dev/input/mice", 0660, 0, 1004}, - {"/dev/input/mouse0", 0660, 0, 0}, - {"/dev/snd/timer", 0660, 1000, 1005}, - {"/dev/zero", 0666, 0, 0}, - {"/dev/full", 0666, 0, 0}, - {"/dev/ptmx", 0666, 0, 0}, - {"/dev/tty", 0666, 0, 0}, - {"/dev/random", 0666, 0, 0}, - {"/dev/urandom", 0666, 0, 0}, - {"/dev/ashmem", 0666, 0, 0}, - {"/dev/pmsg0", 0222, 0, 1007}, - {"/dev/jpeg", 0666, 1000, 1003}, - {"/dev/vinput", 0660, 1000, 1004}, - {"/dev/mmz_userdev", 0644, 1000, 1005}, - {"/dev/graphics/fb0", 0660, 1000, 1003}, - {"/dev/mem", 0660, 1000, 1005}, - {"/dev/ion", 0666, 1000, 1000}, - {"/dev/btusb0", 0660, 1002, 1002}, - {"/dev/uhid", 0660, 3011, 3011}, - {"/dev/tc_ns_client", 0660, 1000, 1005}, - {"/dev/rtk_btusb", 0660, 1002, 0}, - {"/dev/sil9293", 0660, 1000, 1005}, - {"/dev/stpbt", 0660, 1002, 1001}, - {"/dev/avs", 0660, 1000, 1005}, - {"/dev/gdc", 0660, 1000, 1005}, - {"/dev/hdmi", 0660, 1000, 1005}, - {"/dev/hi_mipi", 0660, 1000, 1005}, - {"/dev/hi_mipi_tx", 0660, 1000, 1005}, - {"/dev/hi_tde", 0644, 1000, 1003}, - {"/dev/isp_dev", 0660, 1000, 1006}, - {"/dev/match", 0660, 1000, 1005}, - {"/dev/photo", 0660, 1000, 1005}, - {"/dev/rect", 0660, 1000, 1005}, - {"/dev/rgn", 0660, 1000, 1005}, - {"/dev/sys", 0660, 1000, 1005}, - {"/dev/vb", 0666, 1000, 1005}, - {"/dev/vdec", 0666, 1000, 1005}, - {"/dev/venc", 0666, 1000, 1005}, - {"/dev/vi", 0660, 1000, 1005}, - {"/dev/vo", 0660, 1000, 1005}, - {"/dev/vpss", 0660, 1000, 1005}, - {"/dev/i2c-0", 0660, 1000, 1006}, - {"/dev/i2c-1", 0660, 1000, 1006}, - {"/dev/i2c-2", 0660, 1000, 1006}, - {"/dev/i2c-3", 0660, 1000, 1006}, - {"/dev/i2c-4", 0660, 1000, 1006}, - {"/dev/i2c-5", 0660, 1000, 1006}, - {"/dev/i2c-6", 0660, 1000, 1006}, - {"/dev/i2c-7", 0660, 1000, 1006}, - {"/dev/vgs", 0666, 1000, 1005}, - {"/dev/dri/card0", 0666, 0, 1003}, - {"/dev/dri/card0-DSI-1", 0666, 0, 1003}, - {"/dev/dri/card0-HDMI-A-1", 0666, 0, 1003}, - {"/dev/dri/renderD128", 0666, 0, 1003}, - {"/dev/rtc0", 0640, 1000, 1000}, - {"/dev/tty0", 0660, 0, 1000}, - {"/dev/uinput", 0660, 3011, 3011} -}; - -static void AdjustDevicePermission(const char *devPath) -{ - for (unsigned int i = 0; i < sizeof(DEV_MAPPER) / sizeof(struct DevPermissionMapper); ++i) { - if (strcmp(devPath, DEV_MAPPER[i].devName) == 0) { - if (chmod(devPath, DEV_MAPPER[i].devMode) != 0) { - INIT_LOGE("AdjustDevicePermission, failed for %s, err %d.", devPath, errno); - return; - } - if (chown(devPath, DEV_MAPPER[i].uid, DEV_MAPPER[i].gid) != 0) { - INIT_LOGE("AdjustDevicePermission, failed for %s, err %d.", devPath, errno); - return; - } - INIT_LOGI("AdjustDevicePermission :%s success", devPath); - } - } -} - -static void MakeDevice(const char *devPath, const char *path, int block, int major, int minor) -{ - /* Only for super user */ - gid_t gid = 0; - mode_t mode = DEVICE_DEFAULT_MODE; - mode |= (block ? S_IFBLK : S_IFCHR); - dev_t dev = makedev(major, minor); - setegid(gid); - if (mknod(devPath, mode, dev) != 0) { - if (errno != EEXIST) { - INIT_LOGE("Make device node[%d, %d] failed. %d", major, minor, errno); - } - } - AdjustDevicePermission(devPath); -} - -int MkdirRecursive(const char *pathName, mode_t mode) -{ - char buf[MAX_BUFFER]; - const char *pos; - const char *p = pathName; - struct stat info; - - while ((pos = strchr(p, '/')) != NULL) { - int pathLength = pos - pathName; - p = pos + 1; - INIT_CHECK(pathLength >= 0, break); - INIT_CHECK(pathLength != 0, continue); - INIT_ERROR_CHECK((unsigned int)pathLength <= sizeof(buf) - 1, return -1, - "path too long for MkdirRecursive"); - INIT_CHECK_RETURN_VALUE(memcpy_s(buf, pathLength, pathName, pathLength) == 0, -1); - buf[pathLength] = 0; - if (stat(buf, &info) != 0) { - int ret = MakeDir(buf, mode); - INIT_CHECK_RETURN_VALUE(!(ret && errno != EEXIST), ret); - } - } - int ret = MakeDir(pathName, mode); - INIT_CHECK_RETURN_VALUE(!(ret && errno != EEXIST), ret); - return 0; -} - -void RemoveLink(const char *oldpath, const char *newpath) -{ - char path[MAX_BUFFER]; - ssize_t ret = readlink(newpath, path, sizeof(path) - 1); - INIT_CHECK_ONLY_RETURN(ret > 0); - path[ret] = 0; - INIT_CHECK(strcmp(path, oldpath) != 0, unlink(newpath)); - return; -} - -static void MakeLink(const char *oldPath, const char *newPath) -{ - char buf[MAX_BUFFER]; - char *linkPos = strrchr(newPath, '/'); - INIT_CHECK_ONLY_RETURN(linkPos != NULL); - - int length = linkPos - newPath; - INIT_CHECK_ONLY_RETURN(length > 0 && length <= (int)sizeof(buf) - 1); - INIT_CHECK_ONLY_RETURN(memcpy_s(buf, sizeof(buf), newPath, length) == 0); - buf[length] = 0; - int ret = MkdirRecursive(buf, DEFAULT_DIR_MODE); - if (ret) { - INIT_LOGE("Failed to create directory %s: %s (%d)", buf, strerror(errno), errno); - } - ret = symlink(oldPath, newPath); - if (ret && errno != EEXIST) { - INIT_LOGE("Failed to symlink %s to %s: %s (%d)", oldPath, newPath, strerror(errno), errno); - } -} - -static void HandleDevice(const struct Uevent *event, const char *devpath, int block, char **links) -{ - int i; - if (!strcmp(event->action, "add")) { - MakeDevice(devpath, event->path, block, event->major, event->minor); - if (links) { - for (i = 0; links[i]; i++) { - MakeLink(devpath, links[i]); - } - } - } - - if (!strcmp(event->action, "remove")) { - if (links) { - for (i = 0; links[i]; i++) { - RemoveLink(devpath, links[i]); - } - } - unlink(devpath); - } - - if (links) { - for (i = 0; links[i]; i++) { - free(links[i]); - } - free(links); - } -} - -static void HandleBlockDevice(const struct Uevent *event) -{ - INIT_CHECK_ONLY_RETURN(event->major >= 0 && event->minor >= 0); - - const char *base = "/dev/block"; - char devpath[MAX_DEV_PATH]; - char **links = NULL; - - const char *name = strrchr(event->path, '/'); - INIT_CHECK_ONLY_RETURN(name != NULL); - name++; - INIT_CHECK_ONLY_RETURN(strlen(name) <= MAX_DEVICE_LEN); // too long - - if (snprintf_s(devpath, sizeof(devpath), sizeof(devpath) - 1, "%s/%s", base, name) == -1) { - return; - } - MakeDir(base, DEFAULT_DIR_MODE); - if (strncmp(event->path, "/devices/", strlen("/devices/")) == 0) { - links = ParsePlatformBlockDevice(event); - } - HandleDevice(event, devpath, 1, links); -} - -static void AddPlatformDevice(const char *path) -{ - size_t pathLen = strlen(path); - const char *name = path; - size_t deviceLength = strlen("/devices/"); - size_t platformLength = strlen("platform/"); - if (strncmp(path, "/devices/", deviceLength) == 0) { - name += deviceLength; - if (strncmp(name, "platform/", platformLength) == 0) { - name += platformLength; - } - } - INIT_LOGI("adding platform device %s (%s)", name, path); - struct PlatformSubsystem *bus = calloc(1, sizeof(struct PlatformSubsystem)); - if (!bus) { - return; - } - bus->path = strdup(path); - bus->pathLen = pathLen; - bus->name = bus->path + (name - path); - ListAddTail(&g_platformNames, &bus->list); - return; -} - -static void RemovePlatformDevice(const char *path) -{ - struct ListNode *node = NULL; - struct PlatformSubsystem *bus = NULL; - - for (node = (&g_platformNames)->prev; node != &g_platformNames; node = node->prev) { - bus = (struct PlatformSubsystem *)(((char*)(node)) - offsetof(struct PlatformSubsystem, list)); - if (!strcmp(path, bus->path)) { - INIT_LOGI("removing platform device %s", bus->name); - free(bus->path); - ListRemove(node); - free(bus); - return; - } - } -} - -static void HandlePlatformDevice(const struct Uevent *event) -{ - const char *path = event->path; - if (strcmp(event->action, "add") == 0) { - AddPlatformDevice(path); - } else if (strcmp(event->action, "remove") == 0) { - RemovePlatformDevice(path); - } -} - -static const char *ParseDeviceName(const struct Uevent *uevent, unsigned int len) -{ - INIT_CHECK_RETURN_VALUE(uevent->major >= 0 && uevent->minor >= 0, NULL); - - const char *name = strrchr(uevent->path, '/'); - INIT_CHECK_RETURN_VALUE(name != NULL, NULL); - name++; - - INIT_CHECK_RETURN_VALUE(strlen(name) <= len, NULL); - return name; -} - -static char **GetCharDeviceSymlinks(const struct Uevent *uevent) -{ - char *linkPos = NULL; - int linkNum = 0; - int length; - - struct PlatformSubsystem *node = FindPlatformDevice(uevent->path); - INIT_CHECK_RETURN_VALUE(node != NULL, NULL); - - char **links = calloc(sizeof(char *), SYS_LINK_NUMBER); - INIT_CHECK_RETURN_VALUE(links != NULL, NULL); - - const char *parent = strchr(uevent->path + node->pathLen, '/'); - INIT_CHECK(parent != NULL, goto err); - - INIT_CHECK(strncmp(parent, "/usb", strlen("/usb")) == 0, goto err); - INIT_CHECK(parent != NULL, goto err); - - linkPos = strchr(++parent, '/'); - INIT_CHECK(linkPos != NULL, goto err); - - length = linkPos - parent; - INIT_CHECK(length > 0, goto err); - - if (asprintf(&links[linkNum], "/dev/usb/%s%.*s", uevent->subsystem, length, parent) > 0) { - linkNum++; - } else { - links[linkNum] = NULL; - } - mkdir("/dev/usb", DEFAULT_DIR_MODE); - return links; -err: - free(links); - return NULL; -} - -static int HandleUsbDevice(const struct Uevent *event, char *devpath, int len) -{ - if (event->deviceName) { - char *p = devpath; - if (snprintf_s(devpath, len, len - 1, "/dev/%s", event->deviceName) == -1) { - return -1; - } - p += strlen("/dev/"); - while (*p) { - if (*p == '/') { - *p = 0; - MakeDir(devpath, DEFAULT_DIR_MODE); - *p = '/'; - } - p++; - } - } else { - int busId = event->minor / MINORS_GROUPS + 1; - int deviceId = event->minor % MINORS_GROUPS + 1; - MakeDir("/dev/bus", DEFAULT_DIR_MODE); - MakeDir("/dev/bus/usb", DEFAULT_DIR_MODE); - if (snprintf_s(devpath, len, len - 1, "/dev/bus/usb/%03d", busId) == -1) { - return -1; - } - MakeDir(devpath, DEFAULT_DIR_MODE); - if (snprintf_s(devpath, len, len - 1, "/dev/bus/usb/%03d/%03d", busId, - deviceId) == -1) { - return -1; - } - } - return 0; -} - -static void HandleDeviceEvent(struct Uevent *event, char *devpath, int len, const char *base, const char *name) -{ - char **links = NULL; - links = GetCharDeviceSymlinks(event); - if (!devpath[0]) { - if (snprintf_s(devpath, len, len - 1, "%s%s", base, name) == -1) { - INIT_LOGE("snprintf_s err "); - goto err; - } - } - HandleDevice(event, devpath, 0, links); - return; -err: - if (links) { - for (int i = 0; links[i]; i++) { - free(links[i]); - } - free(links); - } - return; -} - -struct CommonDev { - char *subsystem; - unsigned int length; - char *path; -}; - -static const struct CommonDev COMMON_DEV_MAPPER[] = { - {"graphics", 8, "/dev/graphics/"}, - {"drm", 3, "/dev/dri/"}, - {"oncrpc", 6, "/dev/oncrpc/"}, - {"adsp", 4, "/dev/adsp/"}, - {"input", 5, "/dev/input/"}, - {"mtd", 3, "/dev/mtd/"}, - {"sound", 5, "/dev/snd/"} -}; - -static void HandleCommonDevice(struct Uevent *event) -{ - char *base = NULL; - char devpath[MAX_DEV_PATH] = {0}; - const char *name = ParseDeviceName(event, MAX_DEVICE_LEN); - INIT_CHECK_ONLY_RETURN(name != NULL); - - size_t count = sizeof(COMMON_DEV_MAPPER) / sizeof(COMMON_DEV_MAPPER[0]); - unsigned int i = 0; - for (; i < count; ++i) { - if (strncmp(event->subsystem, COMMON_DEV_MAPPER[i].subsystem, COMMON_DEV_MAPPER[i].length) == 0) { - base = COMMON_DEV_MAPPER[i].path; - MakeDir(base, DEFAULT_DIR_MODE); - break; - } - } - - if (i == count) { - if (strncmp(event->subsystem, "usb", strlen("usb")) == 0) { - if (strcmp(event->subsystem, "usb") == 0) { - INIT_CHECK_ONLY_RETURN(HandleUsbDevice(event, devpath, MAX_DEV_PATH) != -1); - } else { - return; // only support usb event - } - } else { - base = "/dev/"; - } - } - HandleDeviceEvent(event, devpath, MAX_DEV_PATH, base, name); - return; -} - -struct UeventHandleTable { - char *name; - unsigned int length; - void (*HandleDeviceFunction)(const struct Uevent *event); -}; - -static const struct UeventHandleTable UEVNET_HANDLE_TABLE[] = { - {"block", 5, HandleBlockDevice}, - {"platform", 8, HandlePlatformDevice} -}; - -static void HandleDeviceUevent(struct Uevent *event) -{ - size_t count = sizeof(UEVNET_HANDLE_TABLE) / sizeof(UEVNET_HANDLE_TABLE[0]); - unsigned int i = 0; - for (; i < count; ++i) { - if (strncmp(event->subsystem, UEVNET_HANDLE_TABLE[i].name, UEVNET_HANDLE_TABLE[i].length) == 0) { - UEVNET_HANDLE_TABLE[i].HandleDeviceFunction(event); - break; - } - } - if (i == count) { - HandleCommonDevice(event); - } - return; -} - -static void HandleUevent() -{ - char buf[EVENT_MAX_BUFFER]; - int ret; - struct Uevent event; - while ((ret = ReadUeventMessage(g_ueventFD, buf, BASE_BUFFER_SIZE)) > 0) { - if (ret >= BASE_BUFFER_SIZE) { - continue; - } - buf[ret] = '\0'; - buf[ret + 1] = '\0'; - ParseUevent(buf, &event); - HandleDeviceUevent(&event); - } - return; -} - -void UeventInit() -{ - struct pollfd ufd; - UeventSockInit(); - ufd.events = POLLIN; - ufd.fd = UeventFD(); - while (1) { - ufd.revents = 0; - int ret = poll(&ufd, 1, -1); - if (ret <= 0) { - continue; - } - if (ufd.revents & POLLIN) { - HandleUevent(); - } - } - return; -} - -int main(const int argc, const char **argv) -{ - INIT_LOGI("Uevent demo starting..."); - UeventInit(); - return 0; -} diff --git a/ueventd/BUILD.gn b/ueventd/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..c2dda3cbd76e3b7ba0ab05df57e4e7cc5a4f105b --- /dev/null +++ b/ueventd/BUILD.gn @@ -0,0 +1,55 @@ +# 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. + +if (!defined(ohos_lite)) { + import("//build/ohos.gni") + + ohos_executable("ueventd") { + sources = [ + "list.c", + "ueventd.c", + "ueventd_device_handler.c", + "ueventd_firmware_handler.c", + "ueventd_read_cfg.c", + "ueventd_socket.c", + "ueventd_utils.c", + ] + + include_dirs = [ + "include", + "//third_party/bounds_checking_function/include", + "//base/startup/init_lite/services/log", + ] + + deps = [ + "//base/startup/init_lite/services/log:init_log", + "//third_party/bounds_checking_function:libsec_static", + ] + + install_images = [ + "system", + "updater", + ] + install_enable = true + part_name = "init" + } + + ohos_prebuilt_etc("ueventd.config") { + source = "//base/startup/init_lite/ueventd/etc/ueventd.config" + part_name = "init" + install_images = [ + "system", + "updater", + ] + } +} diff --git a/ueventd/etc/ueventd.config b/ueventd/etc/ueventd.config new file mode 100755 index 0000000000000000000000000000000000000000..771075ae83305433598136d6552083e1f44355fa --- /dev/null +++ b/ueventd/etc/ueventd.config @@ -0,0 +1,76 @@ +# Copyright (c) 2021 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. + +[device] +# +/dev/binder 0666 0 0 +/dev/input/event0 0660 0 0 +/dev/input/event1 0660 0 1004 +/dev/input/mice 0660 0 1004 +/dev/input/mouse0 0660 0 0 +/dev/snd/timer 0660 1000 1005 +/dev/zero 0666 0 0 +/dev/full 0666 0 0 +/dev/ptmx 0666 0 0 +/dev/tty 0666 0 0 +/dev/random 0666 0 0 +/dev/urandom 0666 0 0 +/dev/ashmem 0666 0 0 +/dev/pmsg0 0222 0 1007 +/dev/jpeg 0666 1000 1003 +/dev/vinput 0660 1000 1004 +/dev/mmz_userdev 0644 1000 1005 +/dev/graphics/fb0 0660 1000 1003 +/dev/mem 0660 1000 1005 +/dev/ion 0666 1000 1000 +/dev/btusb0 0660 1002 1002 +/dev/uhid 0660 3011 3011 +/dev/tc_ns_client 0660 1000 1005 +/dev/rtk_btusb 0660 1002 0 +/dev/sil9293 0660 1000 1005 +/dev/stpbt 0660 1002 1001 +/dev/avs 0660 1000 1005 +/dev/gdc 0660 1000 1005 +/dev/hdmi 0660 1000 1005 +/dev/hi_mipi 0660 1000 1005 +/dev/hi_mipi_tx 0660 1000 1005 +/dev/hi_tde 0644 1000 1003 +/dev/isp_dev 0660 1000 1006 +/dev/match 0660 1000 1005 +/dev/photo 0660 1000 1005 +/dev/rect 0660 1000 1005 +/dev/rgn 0660 1000 1005 +/dev/sys 0660 1000 1005 +/dev/vb 0666 1000 1005 +/dev/vdec 0666 1000 1005 +/dev/venc 0666 1000 1005 +/dev/vi 0660 1000 1005 +/dev/vo 0660 1000 1005 +/dev/vpss 0660 1000 1005 +/dev/i2c-0 0660 1000 1006 +/dev/i2c-1 0660 1000 1006 +/dev/i2c-2 0660 1000 1006 +/dev/i2c-3 0660 1000 1006 +/dev/i2c-4 0660 1000 1006 +/dev/i2c-5 0660 1000 1006 +/dev/i2c-6 0660 1000 1006 +/dev/i2c-7 0660 1000 1006 +/dev/vgs 0666 1000 1005 +/dev/dri/card0 0666 0 1003 +/dev/dri/card0-DSI-1 0666 0 1003 +/dev/dri/card0-HDMI-A-1 0666 0 1003 +/dev/dri/renderD128 0666 0 1003 +/dev/rtc0 0640 1000 1000 +/dev/tty0 0660 0 1000 +/dev/uinput 0660 3011 3011 + diff --git a/services/src/list.c b/ueventd/list.c old mode 100644 new mode 100755 similarity index 100% rename from services/src/list.c rename to ueventd/list.c diff --git a/services/include/list.h b/ueventd/list.h old mode 100644 new mode 100755 similarity index 92% rename from services/include/list.h rename to ueventd/list.h index 4aaf9dcf65bc02fe7b4e416c011995719c7bbb78..06eaaff05d799f7c4c5f2f7c172c09fa69f8d841 --- a/services/include/list.h +++ b/ueventd/list.h @@ -29,6 +29,8 @@ typedef struct ListNode { #define ListEmpty(node) ((node).next == &(node) && (node).prev == &(node)) #define ListEntry(ptr, type, member) (type *)((char *)(ptr) - offsetof(type, member)) +#define ForEachListEntry(list, node) \ + for (node = (list)->next; node != (list); node = node->next) void ListInit(struct ListNode *list); void ListAddTail(struct ListNode *list, struct ListNode *item); diff --git a/ueventd/ueventd.c b/ueventd/ueventd.c new file mode 100755 index 0000000000000000000000000000000000000000..98ab43e55731cffa7cd9cc2d6a5e158dccc563c2 --- /dev/null +++ b/ueventd/ueventd.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2021 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 "ueventd.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "ueventd_device_handler.h" +#include "ueventd_firmware_handler.h" +#include "ueventd_read_cfg.h" +#include "ueventd_socket.h" +#include "ueventd_utils.h" +#include "securec.h" +#define INIT_LOG_TAG "ueventd" +#include "init_log.h" + +// buffer size refer to kernel kobject uevent +#define UEVENT_BUFFER_SIZE (2048 + 1) + +static const char *actions[] = { + [ACTION_ADD] = "add", + [ACTION_REMOVE] = "remove", + [ACTION_CHANGE] = "change", + [ACTION_MOVE] = "move", + [ACTION_ONLINE] = "online", + [ACTION_OFFLINE] = "offline", + [ACTION_BIND] = "bind", + [ACTION_UNBIND] = "unbind", + [ACTION_UNKNOWN] = "unknow", +}; + +static SUBSYSTEMTYPE GetSubsystemType(const char *subsystem) +{ + if (subsystem == NULL || *subsystem == '\0') { + return SUBSYSTEM_EMPTY; + } + + if (strcmp(subsystem, "block") == 0) { + return SUBSYSTEM_BLOCK; + } else if (strcmp(subsystem, "platform") == 0) { + return SUBSYSTEM_PLATFORM; + } else if (strcmp(subsystem, "firmware") == 0) { + return SUBSYSTEM_FIRMWARE; + } else { + return SUBSYSTEM_OTHERS; + } +} + +const char *ActionString(ACTION action) +{ + return actions[action]; +} + +static ACTION GetUeventAction(const char *action) +{ + if (action == NULL || *action == '\0') { + return ACTION_UNKNOWN; + } + + if (STRINGEQUAL(action, "add")) { + return ACTION_ADD; + } else if (STRINGEQUAL(action, "remove")) { + return ACTION_REMOVE; + } else if (STRINGEQUAL(action, "change")) { + return ACTION_CHANGE; + } else if (STRINGEQUAL(action, "move")) { + return ACTION_MOVE; + } else if (STRINGEQUAL(action, "online")) { + return ACTION_ONLINE; + } else if (STRINGEQUAL(action, "offline")) { + return ACTION_OFFLINE; + } else if (STRINGEQUAL(action, "bind")) { + return ACTION_BIND; + } else if (STRINGEQUAL(action, "unbind")) { + return ACTION_UNBIND; + } else { + return ACTION_UNKNOWN; + } +} + +static void HandleUevent(const struct Uevent *uevent) +{ + if (uevent->action == ACTION_ADD || uevent->action == ACTION_CHANGE || uevent->action == ACTION_ONLINE) { + ChangeSysAttributePermissions(uevent->syspath); + } + + SUBSYSTEMTYPE type = GetSubsystemType(uevent->subsystem); + switch (type) { + case SUBSYSTEM_BLOCK: + HandleBlockDeviceEvent(uevent); + break; + case SUBSYSTEM_FIRMWARE: + HandleFimwareDeviceEvent(uevent); + break; + case SUBSYSTEM_OTHERS: + HandleOtherDeviceEvent(uevent); + break; + default: + break; + } +} + +static void AddUevent(struct Uevent *uevent, const char *event, size_t len) +{ + if (uevent == NULL || uevent == NULL || len == 0) { + return; + } + + if (STARTSWITH(event, "DEVPATH=")) { + uevent->syspath = event + strlen("DEVPATH="); + } else if (STARTSWITH(event, "SUBSYSTEM=")) { + uevent->subsystem = event + strlen("SUBSYSTEM="); + } else if (STARTSWITH(event, "ACTION=")) { + uevent->action = GetUeventAction(event + strlen("ACTION=")); + } else if (STARTSWITH(event, "DEVNAME=")) { + uevent->deviceName = event + strlen("DEVNAME="); + } else if (STARTSWITH(event, "PARTNAME=")) { + uevent->partitionName = event + strlen("PARTNAME="); + } else if (STARTSWITH(event, "PARTN=")) { + uevent->partitionNum = StringToInt(event + strlen("PARTN="), -1); + } else if (STARTSWITH(event, "MAJOR=")) { + uevent->major = StringToInt(event + strlen("MAJOR="), -1); + } else if (STARTSWITH(event, "MINOR=")) { + uevent->minor = StringToInt(event + strlen("MINOR="), -1); + } else if (STARTSWITH(event, "DEVUID")) { + uevent->ug.uid = StringToInt(event + strlen("DEVUID="), 0); + } else if (STARTSWITH(event, "DEVGID")) { + uevent->ug.gid = StringToInt(event + strlen("DEVGID="), 0); + } else if (STARTSWITH(event, "FIRMWARE=")) { + uevent->firmware = event + strlen("FIRMWARE="); + } else if (STARTSWITH(event, "BUSNUM=")) { + uevent->busNum = StringToInt(event + strlen("BUSNUM="), -1); + } else if (STARTSWITH(event, "DEVNUM=")) { + uevent->devNum = StringToInt(event + strlen("DEVNUM="), -1); + } + // Ignore other events +} + +static void ParseUeventMessage(char *buffer, ssize_t length, struct Uevent *uevent) +{ + if (buffer == NULL || uevent == NULL || length == 0) { + // Ignore invalid buffer + return; + } + + // reset parititon number, major and minor. + uevent->partitionNum = -1; + uevent->major = -1; + uevent->minor = -1; + uevent->busNum = -1; + uevent->devNum = -1; + ssize_t pos = 0; + while (pos < length) { + char *event = buffer + pos; + size_t len = strlen(event); + if (len == 0) { + break; + } + AddUevent(uevent, event, len); + pos += (ssize_t)len + 1; + } +} + +static void ProcessUevent(int sockFd) +{ + // One more bytes for '\0' + char ueventBuffer[UEVENT_BUFFER_SIZE] = {}; + ssize_t n = 0; + struct Uevent uevent = {}; + while ((n = ReadUeventMessage(sockFd, ueventBuffer, sizeof(ueventBuffer) - 1)) > 0) { + ParseUeventMessage(ueventBuffer, n, &uevent); + if (uevent.syspath == NULL) { + INIT_LOGD("Ignore unexpected uevent"); + return; + } + HandleUevent(&uevent); + } +} + +static int g_triggerDone = 0; +static void DoTrigger(const char *ueventPath, int sockFd) +{ + if (ueventPath == NULL || ueventPath[0] == '\0') { + return; + } + + int fd = open(ueventPath, O_WRONLY | O_CLOEXEC); + if (fd < 0) { + INIT_LOGE("Open \" %s \" failed, err = %d", ueventPath, errno); + } else { + ssize_t n = write(fd, "add\n", 4); + if (n < 0) { + INIT_LOGE("Write \" %s \" failed, err = %d", ueventPath, errno); + close(fd); + } else { + close(fd); + // uevent triggered, now handle it. + if (sockFd >= 0) { + ProcessUevent(sockFd); + } + } + } +} + +static void Trigger(const char *path, int sockFd) +{ + DIR *dir = opendir(path); + if (dir != NULL) { + struct dirent *dirent = NULL; + while ((dirent = readdir(dir)) != NULL) { + if (dirent->d_name[0] == '.') { + continue; + } + if (dirent->d_type == DT_DIR) { + char pathBuffer[PATH_MAX]; + if (snprintf_s(pathBuffer, PATH_MAX, PATH_MAX - 1, "%s/%s", path, dirent->d_name) == -1) { + continue; + } + Trigger(pathBuffer, sockFd); + } else { + if (!strcmp(dirent->d_name, "uevent")) { + char ueventBuffer[PATH_MAX]; + if (snprintf_s(ueventBuffer, PATH_MAX, PATH_MAX - 1, "%s/%s", path, "uevent") == -1) { + INIT_LOGW("Cannnot build uevent path under %s", path); + continue; + } + DoTrigger(ueventBuffer, sockFd); + } + } + } + closedir(dir); + } +} + +static void RetriggerUevent(int sockFd) +{ + if (!g_triggerDone) { + Trigger("/sys/block", sockFd); + Trigger("/sys/class", sockFd); + Trigger("/sys/devices", sockFd); + g_triggerDone = 1; + } +} + +int main(int argc, char **argv) +{ + char *ueventdConfigs[] = {"/etc/ueventd.config", NULL}; + int i = 0; + int ret = -1; + while (ueventdConfigs[i] != NULL) { + ParseUeventdConfigFile(ueventdConfigs[i++]); + } + int ueventSockFd = UeventdSocketInit(); + if (ueventSockFd < 0) { + INIT_LOGE("Failed to create uevent socket"); + return -1; + } + + RetriggerUevent(ueventSockFd); + struct pollfd pfd = {}; + pfd.events = POLLIN; + pfd.fd = ueventSockFd; + + while (1) { + pfd.revents = 0; + ret = poll(&pfd, 1, -1); + if (ret <= 0) { + continue; + } + if (pfd.revents & POLLIN) { + ProcessUevent(ueventSockFd); + } + } + return 0; +} diff --git a/ueventd/ueventd.h b/ueventd/ueventd.h new file mode 100755 index 0000000000000000000000000000000000000000..76cb3be40d4b175b4572250c6e583b58f0062a4b --- /dev/null +++ b/ueventd/ueventd.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021 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. + */ + +#ifndef BASE_STARTUP_INITLITE_UEVENTD_H +#define BASE_STARTUP_INITLITE_UEVENTD_H +#include + +// Refer to linux kernel kobject.h +typedef enum ACTION { + ACTION_ADD, + ACTION_REMOVE, + ACTION_CHANGE, + ACTION_MOVE, + ACTION_ONLINE, + ACTION_OFFLINE, + ACTION_BIND, + ACTION_UNBIND, + ACTION_UNKNOWN, +} ACTION; + +struct UidGid { + uid_t uid; + gid_t gid; +}; + +struct Uevent { + const char *subsystem; + const char *syspath; + // DEVNAME may has slash + const char *deviceName; + const char *partitionName; + const char *firmware; + ACTION action; + int partitionNum; + int major; + int minor; + struct UidGid ug; + // for usb device. + int busNum; + int devNum; +}; + +typedef enum SUBYSTEM { + SUBSYSTEM_EMPTY = -1, + SUBSYSTEM_BLOCK = 0, + SUBSYSTEM_PLATFORM = 1, + SUBSYSTEM_FIRMWARE = 2, + SUBSYSTEM_OTHERS = 3, +} SUBSYSTEMTYPE; + +const char *ActionString(ACTION action); +#endif // BASE_STARTUP_INITLITE_UEVENTD_H \ No newline at end of file diff --git a/ueventd/ueventd_device_handler.c b/ueventd/ueventd_device_handler.c new file mode 100755 index 0000000000000000000000000000000000000000..c7f222687aca9a9de822c242e8f4af5e4e9e329f --- /dev/null +++ b/ueventd/ueventd_device_handler.c @@ -0,0 +1,414 @@ +/* + * Copyright (c) 2021 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 "ueventd_device_handler.h" +#include +#include +#include +#include +#include +#include +#include +#include "list.h" +#include "ueventd.h" +#include "ueventd_read_cfg.h" +#include "ueventd_utils.h" +#include "securec.h" +#define INIT_LOG_TAG "ueventd" +#include "init_log.h" + +static void CreateSymbolLinks(const char *deviceNode, char **symLinks) +{ + if (INVALIDSTRING(deviceNode) || symLinks == NULL) { + return; + } + + for (int i = 0; symLinks[i] != NULL; i++) { + const char *linkName = symLinks[i]; + char linkBuf[DEVICE_FILE_SIZE] = {}; + + if (strncpy_s(linkBuf, DEVICE_FILE_SIZE - 1, linkName, strlen(linkName)) != EOK) { + INIT_LOGE("Failed to copy link name"); + return; + } + const char *linkDir = dirname(linkBuf); + if (MakeDirRecursive(linkDir, DIRMODE) < 0) { + INIT_LOGE("[uevent] Failed to create dir \" %s \", err = %d", linkDir, errno); + } + errno = 0; + int rc = symlink(deviceNode, linkName); + if (rc != 0) { + if (errno == EEXIST) { + INIT_LOGW("Link \" %s \" already linked to other target", linkName); + } else { + INIT_LOGE("Failed to link \" %s \" to \" %s \", err = %d", deviceNode, linkName, errno); + } + } + } +} + +static inline void AdjustDeviceNodePermissions(const char *deviceNode, uid_t uid, gid_t gid, mode_t mode) +{ + if (INVALIDSTRING(deviceNode)) { + return; + } + if (chown(deviceNode, uid, gid) != 0) { + INIT_LOGW("Failed to change \" %s \" owner", deviceNode); + } + + if (chmod(deviceNode, mode) != 0) { + INIT_LOGW("Failed to change \" %s \" mode", deviceNode); + } +} + +static int CreateDeviceNode(const struct Uevent *uevent, const char *deviceNode, char **symLinks, bool isBlock) +{ + int rc = -1; + int major = uevent->major; + int minor = uevent->minor; + uid_t uid = uevent->ug.uid; + gid_t gid = uevent->ug.gid; + mode_t mode = DEVMODE; + + if (deviceNode == NULL || *deviceNode == '\0') { + INIT_LOGE("Invalid device file"); + return rc; + } + + char deviceNodeBuffer[DEVICE_FILE_SIZE] = {}; + if (strncpy_s(deviceNodeBuffer, DEVICE_FILE_SIZE - 1, deviceNode, strlen(deviceNode)) != EOK) { + INIT_LOGE("Failed to copy device node"); + return rc; + } + const char *devicePath = dirname(deviceNodeBuffer); + // device node always installed in /dev, should not be other locations. + if (STRINGEQUAL(devicePath, ".") || STRINGEQUAL(devicePath, "/")) { + INIT_LOGE("device path is not valid. should be starts with /dev"); + return rc; + } + + rc = MakeDirRecursive(devicePath, DIRMODE); + if (rc < 0) { + INIT_LOGE("Create path \" %s \" failed", devicePath); + return rc; + } + + GetDeviceNodePermissions(deviceNode, &uid, &gid, &mode); + mode |= isBlock ? S_IFBLK : S_IFCHR; + dev_t dev = makedev(major, minor); + setegid(0); + rc = mknod(deviceNode, mode, dev); + if (rc < 0) { + if (errno != EEXIST) { + INIT_LOGE("Create device node[%s %d, %d] failed", deviceNode, major, minor, errno); + return rc; + } + } + AdjustDeviceNodePermissions(deviceNode, uid, gid, mode); + if (symLinks) { + CreateSymbolLinks(deviceNode, symLinks); + } + // No matter what result the symbol links returns, + // as long as create device node done, just returns success. + rc = 0; + return rc; +} + +static int RemoveDeviceNode(const char *deviceNode, char **symLinks) +{ + int rc = -1; + if (INVALIDSTRING(deviceNode)) { + INIT_LOGE("Invalid device node"); + return rc; + } + if (symLinks != NULL) { + for (int i = 0; symLinks[i] != NULL; i++) { + char realPath[DEVICE_FILE_SIZE] = {}; + const char *linkName = symLinks[i]; + ssize_t ret = readlink(linkName, realPath, DEVICE_FILE_SIZE - 1); + if (ret < 0) { + continue; + } + if (STRINGEQUAL(deviceNode, realPath)) { + unlink(linkName); + } + } + } + return unlink(deviceNode); +} + +static char **GetBlockDeviceSymbolLinks(const struct Uevent *uevent) +{ + if (uevent == NULL || !STRINGEQUAL(uevent->subsystem, "block")) { + INIT_LOGW("Invalid arguments, Skip to get device symbol links."); + return NULL; + } + + // Only if current uevent is for real device. + if (!STARTSWITH(uevent->syspath, "/devices")) { + return NULL; + } + // For block device under one platform device. + // check subsystem file under directory, see if it links to bus/platform. + // For now, only support platform device. + char sysPath[SYSPATH_SIZE] = {}; + if (snprintf_s(sysPath, SYSPATH_SIZE, SYSPATH_SIZE - 1, "/sys%s", uevent->syspath) == -1) { + INIT_LOGE("Failed to build sys path for device %s", uevent->syspath); + return NULL; + } + + char **links = calloc(sizeof(char *), BLOCKDEVICE_LINKS); + int linkNum = 0; + if (links == NULL) { + INIT_LOGE("Failed to allocate memory for links, err = %d", errno); + } + + // Reverse walk through sysPath, and check subystem file under each directory. + char *parent = dirname(sysPath); + while (parent != NULL && !STRINGEQUAL(parent, "/") && !STRINGEQUAL(parent, ".")) { + char subsystem[SYSPATH_SIZE]; + if (snprintf_s(subsystem, SYSPATH_SIZE, SYSPATH_SIZE - 1, "%s/subsystem", parent) == -1) { + INIT_LOGE("Failed to build subsystem path for device \" %s \"", uevent->syspath); + return NULL; + } + + char *bus = realpath(subsystem, NULL); + if (bus == NULL) { + goto loop; + } + + if (STRINGEQUAL(bus, "/sys/bus/platform")) { + INIT_LOGD("Find a platform device: %s", parent); + if (STARTSWITH(parent, "/sys/devices/platform/")) { + parent += strlen("/sys/devices/platform/"); + if (linkNum > BLOCKDEVICE_LINKS - 1) { + INIT_LOGW("Too much links, ignore"); + break; + } + links[linkNum] = calloc(sizeof(char), DEVICE_FILE_SIZE); + if (links[linkNum] == NULL) { + INIT_LOGE("Failed to allocate memory for link, err = %d", errno); + break; + } + // If a block device without partition name. + // For now, we will not create symbol link for it. + if (!INVALIDSTRING(uevent->partitionName)) { + if (snprintf_s(links[linkNum], DEVICE_FILE_SIZE, DEVICE_FILE_SIZE - 1, + "/dev/block/platform/%s/by-name/%s", parent, uevent->partitionName) == -1) { + INIT_LOGE("Failed to build link"); + break; + } + } + linkNum++; + } + } +loop: + parent = dirname(parent); + continue; + } + links[linkNum] = NULL; + return links; +} + +static void FreeSymbolLinks(char **links) +{ + if (links != NULL) { + for (int i = 0; links[i] != NULL; i++) { + free(links[i]); + links[i] = NULL; + } + free(links); + links = NULL; + } +} + +static void HandleDeviceNode(const struct Uevent *uevent, const char *deviceNode, bool isBlock) +{ + ACTION action = uevent->action; + char **symLinks = NULL; + + // Block device path and name maybe not human readable. + // Consider to create symbol links for them. + // Make block device more readable. + if (isBlock) { + symLinks = GetBlockDeviceSymbolLinks(uevent); + } + + if (action == ACTION_ADD) { + if (CreateDeviceNode(uevent, deviceNode, symLinks, isBlock) < 0) { + INIT_LOGE("Create device \" %s \" failed", deviceNode); + } + } else if (action == ACTION_REMOVE) { + if (RemoveDeviceNode(deviceNode, symLinks) < 0) { + INIT_LOGE("Remove device \" %s \" failed", deviceNode); + } + } else if (action == ACTION_CHANGE) { + INIT_LOGI("Device %s changed", uevent->syspath); + } + // Ignore other actions + FreeSymbolLinks(symLinks); +} + +static const char *GetDeviceName(char *sysPath, const char *deviceName) +{ + const char *devName = NULL; + if (INVALIDSTRING(sysPath)) { + INIT_LOGE("Invalid sys path"); + return NULL; + } + if (deviceName != NULL && deviceName[0] != '\0') { + // if device name reported by kernel includes '/', skip it. + // TODO: use entire device name reported by kernel + devName = basename((char *)deviceName); + char *p = strrchr(deviceName, '/'); + if (p != NULL) { // device name includes slash + p++; + if (p == NULL || *p == '\0') { + // device name ends with '/', which should never happen. + // Get name from sys path. + devName = basename(sysPath); + } else { + devName = p; + } + } + } else { + // kernel does not report DEVNAME, which is possible. use base name is syspath instead. + devName = basename(sysPath); + } + return devName; +} + +static const char *GetDeviceBasePath(const char *subsystem) +{ + char *devPath = NULL; + if (INVALIDSTRING(subsystem)) { + return devPath; + } + + if (STRINGEQUAL(subsystem, "block")) { + devPath = "/dev/block"; + } else if (STRINGEQUAL(subsystem, "input")) { + devPath = "/dev/input"; + } else if (STRINGEQUAL(subsystem, "drm")) { + devPath = "/dev/dri"; + } else if (STRINGEQUAL(subsystem, "input")) { + devPath = "/dev/input"; + } else if (STRINGEQUAL(subsystem, "graphics")) { + devPath = "/dev/graphics"; + } else if (STRINGEQUAL(subsystem, "sound")) { + devPath = "/dev/snd"; + } else { + devPath = "/dev"; + } + return devPath; +} + +void HandleBlockDeviceEvent(const struct Uevent *uevent) +{ + // Sanity checks + if (uevent == NULL || uevent->subsystem == NULL) { + INIT_LOGE("Invalid uevent message received"); + return; + } + + if (strcmp(uevent->subsystem, "block") != 0) { + INIT_LOGE("Unexpceted uevent subsystem \" %s \" received in block device handler", uevent->subsystem); + return; + } + + if (uevent->major < 0 || uevent->minor < 0) { + return; + } + + bool isBlock = true; + // Block device always installed into /dev/block + const char *devPath = GetDeviceBasePath(uevent->subsystem); + char deviceNode[DEVICE_FILE_SIZE] = {}; + char sysPath[SYSPATH_SIZE] = {}; + + if (strncpy_s(sysPath, SYSPATH_SIZE - 1, uevent->syspath, strlen(uevent->syspath) != EOK)) { + INIT_LOGE("Failed to copy sys path"); + return; + } + const char *devName = GetDeviceName(sysPath, uevent->deviceName); + + if (devPath == NULL || devName == NULL) { + INIT_LOGE("Cannot get device path or device name"); + return; + } + if (snprintf_s(deviceNode, DEVICE_FILE_SIZE, DEVICE_FILE_SIZE - 1, "%s/%s", devPath, devName) == -1) { + INIT_LOGE("Make device file for device [%d : %d]", uevent->major, uevent->minor); + return; + } + HandleDeviceNode(uevent, deviceNode, isBlock); +} + +void HandleOtherDeviceEvent(const struct Uevent *uevent) +{ + if (uevent == NULL || uevent->subsystem == NULL) { + INIT_LOGE("Invalid uevent received"); + return; + } + + if (uevent->major < 0 || uevent->minor < 0) { + return; + } + + char deviceNode[DEVICE_FILE_SIZE] = {}; + char sysPath[SYSPATH_SIZE] = {}; + if (strncpy_s(sysPath, SYSPATH_SIZE - 1, uevent->syspath, strlen(uevent->syspath) != EOK)) { + INIT_LOGE("Failed to copy sys path"); + return; + } + const char *devName = GetDeviceName(sysPath, uevent->deviceName); + const char *devPath = GetDeviceBasePath(uevent->subsystem); + + if (devPath == NULL || devName == NULL) { + INIT_LOGE("Cannot get device path or device name"); + return; + } + INIT_LOGD("HandleOtherDeviceEvent, devPath = %s, devName = %s", devPath, devName); + + // For usb devices, should take care of it specially. + // if usb devices report DEVNAME, just create device node. + // otherwise, create deviceNode with bus number and device number. + if (STRINGEQUAL(uevent->subsystem, "usb")) { + if (uevent->deviceName != NULL) { + if (snprintf_s(deviceNode, DEVICE_FILE_SIZE, DEVICE_FILE_SIZE - 1, "/dev/%s", uevent->deviceName) == -1) { + INIT_LOGE("Make device file for device [%d : %d]", uevent->major, uevent->minor); + return; + } + } else { + if (uevent->busNum < 0 || uevent->devNum < 0) { + // usb device should always report bus number and device number. + INIT_LOGE("usb device with invalid bus number or device number"); + return; + } + if (snprintf_s(deviceNode, DEVICE_FILE_SIZE, DEVICE_FILE_SIZE - 1, + "/dev/bus/usb/%03d/%03d", uevent->busNum, uevent->devNum) == -1) { + INIT_LOGE("Make usb device node for device [%d : %d]", uevent->busNum, uevent->devNum); + } + } + } else if (STARTSWITH(uevent->subsystem, "usb")) { + // Other usb devies, do not handle it. + return; + } else { + if (snprintf_s(deviceNode, DEVICE_FILE_SIZE, DEVICE_FILE_SIZE - 1, "%s/%s", devPath, devName) == -1) { + INIT_LOGE("Make device file for device [%d : %d]", uevent->major, uevent->minor); + return; + } + } + HandleDeviceNode(uevent, deviceNode, false); +} diff --git a/ueventd/ueventd_device_handler.h b/ueventd/ueventd_device_handler.h new file mode 100755 index 0000000000000000000000000000000000000000..ab34db61bb08ae8e381bcfde20958330cc6687fd --- /dev/null +++ b/ueventd/ueventd_device_handler.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2021 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. + */ + +#ifndef BASE_STARTUP_INITLITE_UEVENTD_DEVICE_HANDLER_H +#define BASE_STARTUP_INITLITE_UEVENTD_DEVICE_HANDLER_H +#include "ueventd.h" +void HandleBlockDeviceEvent(const struct Uevent *uevent); +void HandleOtherDeviceEvent(const struct Uevent *uevent); + +#endif // BASE_STARTUP_INITLITE_UEVENTD_DEVICE_HANDLER_H diff --git a/ueventd/ueventd_firmware_handler.c b/ueventd/ueventd_firmware_handler.c new file mode 100755 index 0000000000000000000000000000000000000000..16b4fffed2292cfaf2aa8716c94fa2452337e627 --- /dev/null +++ b/ueventd/ueventd_firmware_handler.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2021 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 +#include +#include + +#include "ueventd_firmware_handler.h" +#include "ueventd.h" +#define INIT_LOG_TAG "ueventd" +#include "init_log.h" + +void HandleFimwareDeviceEvent(const struct Uevent *uevent) +{ + // TODO, implement it later. + INIT_LOGI("Firmware handler not implemented yet."); +} diff --git a/ueventd/ueventd_firmware_handler.h b/ueventd/ueventd_firmware_handler.h new file mode 100755 index 0000000000000000000000000000000000000000..1f7e16850ea197243b4907b56fd1be3c34203e7a --- /dev/null +++ b/ueventd/ueventd_firmware_handler.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2021 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. + */ + +#ifndef BASE_STARTUP_INITLITE_UEVENTD_FIRMWARE_HANDLER_H +#define BASE_STARTUP_INITLITE_UEVENTD_FIRMWARE_HANDLER_H +#include "ueventd.h" +void HandleFimwareDeviceEvent(const struct Uevent *uevent); +#endif // BASE_STARTUP_INITLITE_UEVENTD_FIRMWARE_HANDLER_H diff --git a/ueventd/ueventd_read_cfg.c b/ueventd/ueventd_read_cfg.c new file mode 100755 index 0000000000000000000000000000000000000000..ef938be08f15a481061fe186f1521fc0935a79ce --- /dev/null +++ b/ueventd/ueventd_read_cfg.c @@ -0,0 +1,403 @@ +/* + * Copyright (c) 2021 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 "ueventd_read_cfg.h" +#include +#include +#include +#include +#include +#include +#include +#include "list.h" +#include "ueventd_utils.h" +#include "securec.h" +#define INIT_LOG_TAG "ueventd" +#include "init_log.h" + +// default item count in config files +#define DEFAULTITEMCOUNT (100) +typedef enum SECTION { + SECTION_INVALID = -1, + SECTION_DEVICE = 0, + SECTION_SYSFS, + SECTION_FIRMWARE +} SECTION; + +typedef int (*ParseConfigFunc)(char *); +typedef struct FunctionMapper { + char *name; + ParseConfigFunc func; +} FUNCTIONMAPPER; + +struct ListNode g_devices = { + .next = &g_devices, + .prev = &g_devices, +}; + +struct ListNode g_sysDevices = { + .next = &g_sysDevices, + .prev = &g_sysDevices, +}; + +struct ListNode g_firmwares = { + .next = &g_firmwares, + .prev = &g_firmwares, +}; + +static void FreeConfigItems(char **items, int count) +{ + if (items != NULL) { + for (int i = 0; i < count; i++) { + if (items[i] != NULL) { + free(items[i]); + } + } + free(items); + items = NULL; + } +} + +static char **SplitUeventConfig(char *buffer, const char *del, int *returnCount, int maxItemCount) +{ + char *rest = NULL; + int count = 0; + char *p = strtok_r(buffer, del, &rest); + if (maxItemCount < 0) { + return NULL; + } + if (maxItemCount > DEFAULTITEMCOUNT) { + maxItemCount = DEFAULTITEMCOUNT; + } + char **items = (char **)malloc(sizeof(char*) * maxItemCount); + if (items == NULL) { + INIT_LOGE("No enough memory to store uevent config"); + return NULL; + } + while (p != NULL) { + if (count > maxItemCount - 1) { + maxItemCount += (maxItemCount / 2) + 1; + INIT_LOGD("Too many items,expand size"); + char **expand = (char **)(realloc(items, sizeof(char *) * maxItemCount)); + if (expand == NULL) { + INIT_LOGE("Failed to expand memory for uevent config parser"); + FreeConfigItems(items, count); + return NULL; + } + items = expand; + } + size_t len = strlen(p); + items[count] = (char *)malloc(len + 1); + if (items[count] == NULL) { + FreeConfigItems(items, count); + return NULL; + } + if (strncpy_s(items[count], len + 1, p, len) != EOK) { + INIT_LOGE("Copy string failed"); + FreeConfigItems(items, count); + return NULL; + } + items[count][strlen(p)] = '\0'; + count++; + p = strtok_r(NULL, del, &rest); + } + items[count] = NULL; + *returnCount = count; + return items; +} + +static int ParseDeviceConfig(char *p) +{ + INIT_LOGD("Parse device config info: %s", p); + char **items = NULL; + int count = -1; + // format: + int expectedCount = 4; + + if (INVALIDSTRING(p)) { + INIT_LOGE("Invalid argument"); + } + items = SplitUeventConfig(p, " ", &count, expectedCount); + if (count != expectedCount) { + INIT_LOGE("Ignore invalid item: %s", p); + FreeConfigItems(items, count); + return 0; + } + + struct DeviceUdevConf *config = calloc(1, sizeof(struct DeviceUdevConf)); + if (config == NULL) { + errno = ENOMEM; + FreeConfigItems(items, count); + return -1; + } + config->name = strdup(items[0]); // device node + errno = 0; + config->mode = strtoul(items[1], NULL, OCTONARY); + if (errno != 0) { + INIT_LOGE("Invalid mode in config file for device node %s. use default mode", config->name); + config->mode = DEVMODE; + } + config->uid = StringToInt(items[2], 0); + config->gid = StringToInt(items[3], 0); + ListAddTail(&g_devices, &config->list); + FreeConfigItems(items, count); + return 0; +} + +static int ParseSysfsConfig(char *p) +{ + INIT_LOGD("Parse sysfs config info: %s", p); + char **items = NULL; + int count = -1; + // format: + int expectedCount = 5; + + if (INVALIDSTRING(p)) { + INIT_LOGE("Invalid argument"); + } + items = SplitUeventConfig(p, " ", &count, expectedCount); + if (count != expectedCount) { + INIT_LOGE("Ignore invalid item: %s", p); + FreeConfigItems(items, count); + return 0; + } + struct SysUdevConf *config = calloc(1, sizeof(struct SysUdevConf)); + if (config == NULL) { + errno = ENOMEM; + FreeConfigItems(items, count); + return -1; + } + config->sysPath = strdup(items[0]); // sys path + config->attr = strdup(items[1]); // attribute + errno = 0; + config->mode = strtoul(items[2], NULL, OCTONARY); + if (errno != 0) { + INIT_LOGE("Invalid mode in config file for sys path %s. use default mode", config->sysPath); + config->mode = DEVMODE; + } + config->uid = StringToInt(items[3], 0); + config->gid = StringToInt(items[4], 0); + ListAddTail(&g_sysDevices, &config->list); + return 0; +} + +static int ParseFirmwareConfig(char *p) +{ + INIT_LOGD("Parse firmware config info: %s", p); + if (INVALIDSTRING(p)) { + INIT_LOGE("Invalid argument"); + } + struct FirmwareUdevConf *config = calloc(1, sizeof(struct FirmwareUdevConf)); + if (config == NULL) { + errno = ENOMEM; + return -1; + } + + // Sanity checks + struct stat st = {}; + if (stat(p, &st) != 0) { + INIT_LOGE("Invalid firware file: %s, err = %d", p, errno); + return -1; + } + + if (!S_ISDIR(st.st_mode)) { + INIT_LOGE("Expect directory in firmware config"); + return -1; + } + + config->fmPath = strdup(p); + ListAddTail(&g_firmwares, &config->list); + return 0; +} + +static SECTION GetSection(char *section) +{ + if (INVALIDSTRING(section)) { + return SECTION_INVALID; + } + + if (STRINGEQUAL(section, "device")) { + return SECTION_DEVICE; + } else if (STRINGEQUAL(section, "sysfs")) { + return SECTION_SYSFS; + } else if (STRINGEQUAL(section, "firmware")) { + return SECTION_FIRMWARE; + } else { + return SECTION_INVALID; + } +} + +static FUNCTIONMAPPER funcMapper[3] = { + {"device", ParseDeviceConfig}, + {"sysfs", ParseSysfsConfig}, + {"firmware", ParseFirmwareConfig} +}; + +ParseConfigFunc callback; +int ParseUeventConfig(char *buffer) +{ + char *section = NULL; + char *right = NULL; + char *p = buffer; + SECTION type; + + if (INVALIDSTRING(buffer)) { + return -1; + } + if (*p == '[') { + p++; + if ((right = strchr(p, ']')) == NULL) { + INIT_LOGE("Invalid line \"%s\", miss ']'", buffer); + return -1; + } + *right = '\0'; // Replace ']' with '\0'; + section = p; + INIT_LOGD("section is [%s]", section); + if ((type = GetSection(section)) == SECTION_INVALID) { + INIT_LOGE("Invalid section \" %s \"", section); + callback = NULL; // reset callback + return -1; + } + callback = funcMapper[type].func; + return 0; + } + return callback != NULL ? callback(p) : -1; +} + +static void DoUeventConfigParse(char *buffer) +{ + char **items = NULL; + int count = -1; + int maxItemCount = DEFAULTITEMCOUNT; + + items = SplitUeventConfig(buffer, "\n", &count, maxItemCount); + INIT_LOGD("Dump items count = %d", count); + for (int i = 0; i < count; i++) { + char *p = items[i]; + // Skip lead white space + while (isspace(*p)) { + p++; + } + + // Skip comment or empty line + if (*p == '\0' || *p == '#') { + continue; + } + int rc = ParseUeventConfig(p); + if (rc < 0) { + INIT_LOGE("Parse uevent config from %s failed", p); + } + } + // release memory + FreeConfigItems(items, count); +} + +void ParseUeventdConfigFile(const char *file) +{ + if (INVALIDSTRING(file)) { + return; + } + + int fd = open(file, O_RDONLY | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd < 0) { + INIT_LOGE("Read from %s failed", file); + return; + } + + struct stat st; + if (fstat(fd, &st) < 0) { + INIT_LOGE("Failed to get file stat. err = %d", errno); + close(fd); + return; + } + + // st_size should never be less than 0 + size_t size = (size_t)st.st_size; + char *buffer = malloc(size + 1); + if (buffer == NULL) { + INIT_LOGE("Failed to malloc memory. err = %d", errno); + close(fd); + return; + } + + if (read(fd, buffer, size) != (ssize_t)size) { + INIT_LOGE("Read from file %s failed. err = %d", file, errno); + free(buffer); + buffer = NULL; + close(fd); + return; + } + + buffer[size] = '\0'; + DoUeventConfigParse(buffer); + free(buffer); + buffer = NULL; + close(fd); +} + +void GetDeviceNodePermissions(const char *devNode, uid_t *uid, gid_t *gid, mode_t *mode) +{ + if (INVALIDSTRING(devNode)) { + return; + } + + struct ListNode *node = NULL; + if (!ListEmpty(g_devices)) { + ForEachListEntry(&g_devices, node) { + struct DeviceUdevConf *config = ListEntry(node, struct DeviceUdevConf, list); + if (STRINGEQUAL(config->name, devNode)) { + *uid = config->uid; + *gid = config->gid; + *mode = config->mode; + break; + } + } + } + return; +} + +void ChangeSysAttributePermissions(const char *sysPath) +{ + if (INVALIDSTRING(sysPath)) { + return; + } + + struct ListNode *node = NULL; + struct SysUdevConf *config = NULL; + if (!ListEmpty(g_sysDevices)) { + ForEachListEntry(&g_sysDevices, node) { + config = ListEntry(node, struct SysUdevConf, list); + if (STRINGEQUAL(config->sysPath, sysPath)) { + break; + } + } + } + + if (config == NULL) { + return; + } + char sysAttr[SYSPATH_SIZE] = {}; + if (snprintf_s(sysAttr, SYSPATH_SIZE, SYSPATH_SIZE - 1, "/sys%s/%s", config->sysPath, config->attr) == -1) { + INIT_LOGE("Failed to build sys attribute for sys path %s, attr: %s", config->sysPath, config->attr); + return; + } + if (chown(sysAttr, config->uid, config->gid) < 0) { + INIT_LOGE("chown for file %s failed, err = %d", sysAttr, errno); + } + + if (chmod(sysAttr, config->mode) < 0) { + INIT_LOGE("[uevent][error] chmod for file %s failed, err = %d", sysAttr, errno); + } +} diff --git a/ueventd/ueventd_read_cfg.h b/ueventd/ueventd_read_cfg.h new file mode 100755 index 0000000000000000000000000000000000000000..c87476c2a6569425bfa32b9c3ed97a6215007be8 --- /dev/null +++ b/ueventd/ueventd_read_cfg.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021 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. + */ + +#ifndef __UEVENTD_READ_CFG_H +#define __UEVENTD_READ_CFG_H +#include +#include +#include +#include +#include +#include +#include +#include "list.h" + +struct DeviceUdevConf { + const char *name; + mode_t mode; + uid_t uid; + gid_t gid; + struct ListNode list; +}; + +struct SysUdevConf { + const char *sysPath; + const char *attr; + mode_t mode; + uid_t uid; + gid_t gid; + struct ListNode list; +}; + +struct FirmwareUdevConf { + const char *fmPath; + struct ListNode list; +}; +void ParseUeventdConfigFile(const char *file); +void GetDeviceNodePermissions(const char *devNode, uid_t *uid, gid_t *gid, mode_t *mode); +void ChangeSysAttributePermissions(const char *sysPath); +#endif /* __UEVENTD_READ_CFG_H */ diff --git a/ueventd/ueventd_socket.c b/ueventd/ueventd_socket.c new file mode 100755 index 0000000000000000000000000000000000000000..2243aa7f37e8b48fe647ab2b06f46f6b1bacd7c1 --- /dev/null +++ b/ueventd/ueventd_socket.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2021 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "securec.h" +#define INIT_LOG_TAG "ueventd" +#include "init_log.h" + +int UeventdSocketInit() +{ + struct sockaddr_nl addr; + int sockfd; + int buffSize = 256 * 1024; + int on = 1; + + if (memset_s(&addr, sizeof(addr), 0, sizeof(addr) != EOK)) { + INIT_LOGE("Faild to clear socket address"); + return -1; + } + addr.nl_family = AF_NETLINK; + addr.nl_pid = getpid(); + addr.nl_groups = 0xffffffff; + + sockfd = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT); + + if (sockfd < 0) { + INIT_LOGE("Create socket failed, err = %d", errno); + return -1; + } + + setsockopt(sockfd, SOL_SOCKET, SO_RCVBUFFORCE, &buffSize, sizeof(buffSize)); + setsockopt(sockfd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); + + if(bind(sockfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + INIT_LOGE("Bind socket failed, err = %d", errno); + close(sockfd); + return -1; + } + return sockfd; +} + +ssize_t ReadUeventMessage(int sockFd, char *buffer, size_t length) +{ + ssize_t n = -1; + struct msghdr msghdr; + struct iovec iov; + struct sockaddr_nl addr; + char credMsg[CMSG_SPACE(sizeof(struct ucred))]; + struct cmsghdr *cmsghdr; + + // sanity check + if (sockFd < 0 || buffer == NULL) { + return n; + } + + iov.iov_base = buffer; + iov.iov_len = length; + msghdr.msg_name = &addr; + msghdr.msg_namelen = sizeof(addr); + msghdr.msg_iov = &iov; + msghdr.msg_iovlen = 1; + msghdr.msg_control = credMsg; + msghdr.msg_controllen = sizeof(credMsg); + + n = recvmsg(sockFd, &msghdr, 0); + if (n <= 0) { + return n; + } + cmsghdr = CMSG_FIRSTHDR(&msghdr); + if (cmsghdr == NULL || cmsghdr->cmsg_type != SCM_CREDENTIALS) { + INIT_LOGE("Unexpected control message, ignored"); + // Drop this message + *buffer = '\0'; + n = -1; + } + return n; +} diff --git a/ueventd/ueventd_socket.h b/ueventd/ueventd_socket.h new file mode 100755 index 0000000000000000000000000000000000000000..922a94ce18f25a6f34f5c58afa541ef31caa6452 --- /dev/null +++ b/ueventd/ueventd_socket.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2021 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. + */ + +#ifndef BASE_STARTUP_INITLITE_UEVENTD_SOCKET_H +#define BASE_STARTUP_INITLITE_UEVENTD_SOCKET_H +#include +int UeventdSocketInit(); +ssize_t ReadUeventMessage(int sockFd, char *buffer, size_t length); +#endif // BASE_STARTUP_INITLITE_LIST_H diff --git a/ueventd/ueventd_utils.c b/ueventd/ueventd_utils.c new file mode 100755 index 0000000000000000000000000000000000000000..22b03da4b15ec64f066f654345867684aee66754 --- /dev/null +++ b/ueventd/ueventd_utils.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2021 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 "ueventd_utils.h" +#include +#include +#include +#include +#include "securec.h" +#define INIT_LOG_TAG "ueventd" +#include "init_log.h" + +int MakeDir(const char *dir, mode_t mode) +{ + int rc = -1; + if (INVALIDSTRING(dir)) { + errno = EINVAL; + return rc; + } + rc = mkdir(dir, mode); + if (rc < 0 && errno != EEXIST) { + INIT_LOGE("Create directory \" %s \" failed, err = %d", dir, errno); + return rc; + } + // create dir success or it already exist. + return 0; +} + +int MakeDirRecursive(const char *dir, mode_t mode) +{ + int rc = -1; + char buffer[PATH_MAX] = {}; + const char *p = NULL; + if (INVALIDSTRING(dir)) { + errno = EINVAL; + return rc; + } + char *slash = strchr(dir, '/'); + p = dir; + while (slash != NULL) { + int gap = slash - p; + p = slash + 1; + if (gap == 0) { + slash = strchr(p, '/'); + continue; + } + if (gap < 0) { // end with '/' + break; + } + if (memcpy_s(buffer, PATH_MAX, dir, p - dir -1) != 0) { + return -1; + } + rc = MakeDir(buffer, mode); + if (rc < 0) { + return rc; + } + slash = strchr(p, '/'); + } + return MakeDir(dir, mode); +} + +int StringToInt(const char *str, int defaultValue) +{ + if (INVALIDSTRING(str)) { + return defaultValue; + } + errno = 0; + int value = strtoul(str, NULL, DECIMALISM); + return errno != 0 ? defaultValue : value; +} diff --git a/ueventd/ueventd_utils.h b/ueventd/ueventd_utils.h new file mode 100755 index 0000000000000000000000000000000000000000..e8593f2346256e4936d69a015d4c779014fc139b --- /dev/null +++ b/ueventd/ueventd_utils.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 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. + */ + +#ifndef BASE_STARTUP_INITLITE_UEVENTD_UTILS_H +#define BASE_STARTUP_INITLITE_UEVENTD_UTILS_H +#include +#include +#include + +#define DECIMALISM 10 +#define OCTONARY 8 +#define DEVICE_FILE_SIZE 128U +#define SYSPATH_SIZE 512U +#define BLOCKDEVICE_LINKS 3 + +#define STARTSWITH(str, prefix) (strncmp((str), (prefix), strlen(prefix)) == 0) +#define STRINGEQUAL(src, tgt) (strcmp((src), (tgt)) == 0) +#define INVALIDSTRING(str) ((str) == NULL || *(str) == '\0') + +#define DIRMODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) +// Default device mode is 0660 +#define DEVMODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) + +int MakeDirRecursive(const char *dir, mode_t mode); +int MakeDir(const char *dir, mode_t mode); +int StringToInt(const char *str, int defaultValue); +#endif // BASE_STARTUP_INITLITE_UEVENTD_UTILS_H \ No newline at end of file