提交 c5789272 编写于 作者: O openharmony_ci 提交者: Gitee

!100 feat : ueventd 功能重构

Merge pull request !100 from 熊磊/init831
......@@ -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"
]
}
}
......
......@@ -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",
......
......@@ -474,7 +474,7 @@
],
"services" : [{
"name" : "ueventd",
"path" : ["/system/bin/updaterueventd"],
"path" : ["/system/bin/ueventd"],
"critical" : 1
}, {
"name" : "console",
......
......@@ -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
此差异已折叠。
# 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",
]
}
}
# 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]
# <device name> <mode> <uid> <gid>
/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
......@@ -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);
......
/*
* 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 <dirent.h>
#include <limits.h>
#include <fcntl.h>
#include <errno.h>
#include <poll.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#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;
}
/*
* 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 <unistd.h>
// 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
/*
* 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 <errno.h>
#include <libgen.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#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);
}
/*
* 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
/*
* 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 <errno.h>
#include <stdlib.h>
#include <string.h>
#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.");
}
/*
* 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
/*
* 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 <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#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: <device node> <mode> <uid> <gid>
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: <syspath> <attribute> <mode> <uid> <gid>
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);
}
}
/*
* 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 <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#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 */
/*
* 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 <poll.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <ctype.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <linux/netlink.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#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;
}
/*
* 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 <sys/types.h>
int UeventdSocketInit();
ssize_t ReadUeventMessage(int sockFd, char *buffer, size_t length);
#endif // BASE_STARTUP_INITLITE_LIST_H
/*
* 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 <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#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;
}
/*
* 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 <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册