• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ueventd_read_cfg.h"
17 
18 #include <ctype.h>
19 #include <string.h>
20 #include <stdbool.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <sys/stat.h>
26 #include "init_utils.h"
27 #include "list.h"
28 #include "ueventd_utils.h"
29 #include "securec.h"
30 #define INIT_LOG_TAG "ueventd"
31 #include "init_log.h"
32 
33 // default item count in config files
34 #define DEFAULTITEMCOUNT (50)
35 
36 #define SYS_CONFIG_PATH_NUM 0
37 #define SYS_CONFIG_ATTR_NUM 1
38 #define SYS_CONFIG_MODE_NUM 2
39 #define SYS_CONFIG_UID_NUM 3
40 #define SYS_CONFIG_GID_NUM 4
41 
42 #define DEVICE_CONFIG_NAME_NUM 0
43 #define DEVICE_CONFIG_MODE_NUM 1
44 #define DEVICE_CONFIG_UID_NUM 2
45 #define DEVICE_CONFIG_GID_NUM 3
46 #define DEVICE_CONFIG_PARAM_NUM 4
47 
48 typedef enum SECTION {
49     SECTION_INVALID = -1,
50     SECTION_DEVICE = 0,
51     SECTION_SYSFS,
52     SECTION_FIRMWARE
53 } SECTION;
54 
55 typedef int (*ParseConfigFunc)(char *);
56 typedef struct FunctionMapper {
57     char *name;
58     ParseConfigFunc func;
59 } FUNCTIONMAPPER;
60 
61 struct ListNode g_devices = {
62     .next = &g_devices,
63     .prev = &g_devices,
64 };
65 
66 struct ListNode g_sysDevices = {
67     .next = &g_sysDevices,
68     .prev = &g_sysDevices,
69 };
70 
71 struct ListNode g_firmwares = {
72     .next = &g_firmwares,
73     .prev = &g_firmwares,
74 };
75 
ParseDeviceConfig(char * p)76 static int ParseDeviceConfig(char *p)
77 {
78     INIT_LOGV("Parse device config info: %s", p);
79     char **items = NULL;
80     int count = -1;
81     // format: <device node> <mode> <uid> <gid> <parameter>
82     const int expectedCount = 5;
83 
84     INIT_CHECK_ONLY_ELOG(!INVALIDSTRING(p), "Invalid argument");
85     items = SplitStringExt(p, " ", &count, expectedCount);
86     if ((count != expectedCount) && (count != expectedCount - 1)) {
87         INIT_LOGE("Ignore invalid item: %s", p);
88         FreeStringVector(items, count);
89         return 0;
90     }
91 
92     struct DeviceUdevConf *config = calloc(1, sizeof(struct DeviceUdevConf));
93     if (config == NULL) {
94         errno = ENOMEM;
95         FreeStringVector(items, count);
96         return -1;
97     }
98     config->name = strdup(items[DEVICE_CONFIG_NAME_NUM]); // device node
99     errno = 0;
100     config->mode = strtoul(items[DEVICE_CONFIG_MODE_NUM], NULL, OCTAL_BASE);
101     INIT_ERROR_CHECK(errno == 0, config->mode = DEVMODE,
102         "Invalid mode in config file for device node %s. use default mode", config->name);
103     config->uid = (uid_t)DecodeUid(items[DEVICE_CONFIG_UID_NUM]);
104     config->gid = (gid_t)DecodeGid(items[DEVICE_CONFIG_GID_NUM]);
105     if (count == expectedCount) {
106         config->parameter = strdup(items[DEVICE_CONFIG_PARAM_NUM]); // device parameter
107     } else {
108         config->parameter = NULL;
109     }
110     OH_ListInit(&config->paramNode);
111     OH_ListAddTail(&g_devices, &config->list);
112     FreeStringVector(items, count);
113     return 0;
114 }
115 
ParseSysfsConfig(char * p)116 static int ParseSysfsConfig(char *p)
117 {
118     INIT_LOGV("Parse sysfs config info: %s", p);
119     char **items = NULL;
120     int count = -1;
121     // format: <syspath> <attribute> <mode> <uid> <gid>
122     const int expectedCount = 5;
123 
124     INIT_CHECK_ONLY_ELOG(!INVALIDSTRING(p), "Invalid argument");
125     items = SplitStringExt(p, " ", &count, expectedCount);
126     if (count != expectedCount) {
127         INIT_LOGE("Ignore invalid item: %s", p);
128         FreeStringVector(items, count);
129         return 0;
130     }
131     struct SysUdevConf *config = calloc(1, sizeof(struct SysUdevConf));
132     if (config == NULL) {
133         errno = ENOMEM;
134         FreeStringVector(items, count);
135         return -1;
136     }
137     config->sysPath = strdup(items[SYS_CONFIG_PATH_NUM]); // sys path
138     config->attr = strdup(items[SYS_CONFIG_ATTR_NUM]);  // attribute
139     errno = 0;
140     config->mode = strtoul(items[SYS_CONFIG_MODE_NUM], NULL, OCTAL_BASE);
141     INIT_ERROR_CHECK(errno == 0, config->mode = DEVMODE,
142         "Invalid mode in config file for sys path %s. use default mode", config->sysPath);
143     config->uid = (uid_t)DecodeUid(items[SYS_CONFIG_UID_NUM]);
144     config->gid = (gid_t)DecodeGid(items[SYS_CONFIG_GID_NUM]);
145     OH_ListAddTail(&g_sysDevices, &config->list);
146     FreeStringVector(items, count);
147     return 0;
148 }
149 
ParseFirmwareConfig(char * p)150 static int ParseFirmwareConfig(char *p)
151 {
152     INIT_LOGV("Parse firmware config info: %s", p);
153     INIT_ERROR_CHECK(!INVALIDSTRING(p), return -1, "Invalid argument");
154 
155     // Sanity checks
156     struct stat st = {};
157     INIT_ERROR_CHECK(stat(p, &st) == 0, return -1, "Invalid firmware file: %s, err = %d", p, errno);
158     INIT_ERROR_CHECK(S_ISDIR(st.st_mode), return -1, "Expect directory in firmware config");
159     struct FirmwareUdevConf *config = calloc(1, sizeof(struct FirmwareUdevConf));
160     INIT_CHECK(config != NULL, errno = ENOMEM;
161         return -1);
162     config->fmPath = strdup(p);
163     OH_ListAddTail(&g_firmwares, &config->list);
164     return 0;
165 }
166 
GetSection(const char * section)167 static SECTION GetSection(const char *section)
168 {
169     INIT_CHECK_RETURN_VALUE(!INVALIDSTRING(section), SECTION_INVALID);
170     if (STRINGEQUAL(section, "device")) {
171         return SECTION_DEVICE;
172     } else if (STRINGEQUAL(section, "sysfs")) {
173         return SECTION_SYSFS;
174     } else if (STRINGEQUAL(section, "firmware")) {
175         return SECTION_FIRMWARE;
176     } else {
177         return SECTION_INVALID;
178     }
179 }
180 
181 static FUNCTIONMAPPER funcMapper[3] = {
182     {"device", ParseDeviceConfig},
183     {"sysfs", ParseSysfsConfig},
184     {"firmware", ParseFirmwareConfig}
185 };
186 
187 ParseConfigFunc callback;
ParseUeventConfig(char * buffer)188 int ParseUeventConfig(char *buffer)
189 {
190     char *section = NULL;
191     char *right = NULL;
192     char *p = buffer;
193     SECTION type;
194 
195     INIT_CHECK_RETURN_VALUE(!INVALIDSTRING(buffer), -1);
196     if (*p == '[') {
197         p++;
198         if ((right = strchr(p, ']')) == NULL) {
199             INIT_LOGE("Invalid line \"%s\", miss ']'", buffer);
200             return -1;
201         }
202         *right = '\0'; // Replace ']' with '\0';
203         section = p;
204         INIT_LOGV("section is [%s]", section);
205         if ((type = GetSection(section)) == SECTION_INVALID) {
206             INIT_LOGE("Invalid section \" %s \"", section);
207             callback = NULL; // reset callback
208             return -1;
209         }
210         callback = funcMapper[type].func;
211         return 0;
212     }
213     return (callback != NULL) ? callback(p) : -1;
214 }
215 
DoUeventConfigParse(char * buffer,size_t length)216 static void DoUeventConfigParse(char *buffer, size_t length)
217 {
218     char **items = NULL;
219     int count = -1;
220     const int maxItemCount = DEFAULTITEMCOUNT;
221 
222     items = SplitStringExt(buffer, "\n", &count, maxItemCount);
223     INIT_LOGV("Dump items count = %d", count);
224     for (int i = 0; i < count; i++) {
225         char *p = items[i];
226         // Skip lead white space
227         while (isspace(*p)) {
228             p++;
229         }
230 
231         // Skip comment or empty line
232         if (*p == '\0' || *p == '#') {
233             continue;
234         }
235         int rc = ParseUeventConfig(p);
236         if (rc < 0) {
237             INIT_LOGE("Parse uevent config from %s failed", p);
238         }
239     }
240     // release memory
241     FreeStringVector(items, count);
242 }
243 
ParseUeventdConfigFile(const char * file)244 void ParseUeventdConfigFile(const char *file)
245 {
246     INIT_CHECK_ONLY_RETURN(!INVALIDSTRING(file));
247     char *config = GetRealPath(file);
248     INIT_CHECK_ONLY_RETURN(config != NULL);
249     int fd = open(config, O_RDONLY | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
250     free(config);
251     INIT_ERROR_CHECK(fd >= 0, return, "Read from %s failed", file);
252 
253     struct stat st;
254     if (fstat(fd, &st) < 0) {
255         INIT_LOGE("Failed to get file stat. err = %d", errno);
256         close(fd);
257         fd = -1;
258         return;
259     }
260 
261     // st_size should never be less than 0
262     size_t size = (size_t)st.st_size;
263     char *buffer = malloc(size + 1);
264     if (buffer == NULL) {
265         INIT_LOGE("Failed to malloc memory. err = %d", errno);
266         close(fd);
267         fd = -1;
268         return;
269     }
270 
271     if (read(fd, buffer, size) != (ssize_t)size) {
272         INIT_LOGE("Read from file %s failed. err = %d", file, errno);
273         free(buffer);
274         buffer = NULL;
275         close(fd);
276         fd = -1;
277         return;
278     }
279 
280     buffer[size] = '\0';
281     DoUeventConfigParse(buffer, size);
282     free(buffer);
283     buffer = NULL;
284     close(fd);
285     fd = -1;
286 }
287 
288 // support '*' to match all characters
289 // '?' match one character.
IsMatch(const char * target,const char * pattern)290 bool IsMatch(const char *target, const char *pattern)
291 {
292     INIT_CHECK_RETURN_VALUE(target != NULL, false);
293     INIT_CHECK_RETURN_VALUE(pattern != NULL, true);
294 
295     const char *t = target;
296     const char *p = pattern;
297     const char *plast = NULL;
298     bool reMatch = false;
299     while (*t != '\0') {
300         if (*t == *p) {
301             t++;
302             p++;
303             continue;
304         }
305 
306         // Match one character.
307         if (*p == '?') {
308             p++;
309             t++;
310             continue;
311         }
312 
313         if (*p == '\0') {
314             return reMatch;
315         }
316 
317         if (*p == '*') {
318             reMatch = true;
319             // Met '*', record where we will start over.
320             // plast point to next character that we will compare it again.
321             plast = ++p;
322             t++;
323             continue;
324         }
325 
326         if (reMatch) {
327             // Start over.
328             p = plast;
329             t++;
330         } else {
331             return false;
332         }
333     }
334 
335     while (*p == '*') {
336         p++;
337     }
338     return (*p == '\0');
339 }
340 
GetDeviceUdevConfByDevNode(const char * devNode)341 struct DeviceUdevConf *GetDeviceUdevConfByDevNode(const char *devNode)
342 {
343     if (INVALIDSTRING(devNode)) {
344         return NULL;
345     }
346 
347     struct ListNode *node = NULL;
348     if (!ListEmpty(g_devices)) {
349         ForEachListEntry(&g_devices, node) {
350             struct DeviceUdevConf *config = ListEntry(node, struct DeviceUdevConf, list);
351             if (IsMatch(devNode, config->name)) {
352                 return config;
353             }
354         }
355     }
356     return NULL;
357 }
358 
GetDeviceNodePermissions(const char * devNode,uid_t * uid,gid_t * gid,mode_t * mode)359 void GetDeviceNodePermissions(const char *devNode, uid_t *uid, gid_t *gid, mode_t *mode)
360 {
361     if (INVALIDSTRING(devNode)) {
362         return;
363     }
364 
365     struct ListNode *node = NULL;
366     if (!ListEmpty(g_devices)) {
367         ForEachListEntry(&g_devices, node) {
368             struct DeviceUdevConf *config = ListEntry(node, struct DeviceUdevConf, list);
369             if (IsMatch(devNode, config->name)) {
370                 *uid = config->uid;
371                 *gid = config->gid;
372                 *mode = config->mode;
373                 break;
374             }
375         }
376     }
377     return;
378 }
379 
ChangeSysAttributePermissions(const char * sysPath)380 void ChangeSysAttributePermissions(const char *sysPath)
381 {
382     if (INVALIDSTRING(sysPath)) {
383         return;
384     }
385 
386     struct ListNode *node = NULL;
387     struct SysUdevConf *config = NULL;
388     int matched = 0;
389     if (!ListEmpty(g_sysDevices)) {
390         ForEachListEntry(&g_sysDevices, node) {
391             config = ListEntry(node, struct SysUdevConf, list);
392             if (STRINGEQUAL(config->sysPath, sysPath)) {
393                 matched = 1;
394                 break;
395             }
396         }
397     }
398 
399     if (matched == 0) {
400         return;
401     }
402     char sysAttr[SYSPATH_SIZE] = {};
403     if (snprintf_s(sysAttr, SYSPATH_SIZE, SYSPATH_SIZE - 1, "/sys%s/%s", config->sysPath, config->attr) == -1) {
404         INIT_LOGE("Failed to build sys attribute for sys path %s, attr: %s", config->sysPath, config->attr);
405         return;
406     }
407     if (chown(sysAttr, config->uid, config->gid) < 0) {
408         INIT_LOGE("chown for file %s failed, err = %d", sysAttr, errno);
409     }
410 
411     if (chmod(sysAttr, config->mode) < 0) {
412         INIT_LOGE("[uevent][error] chmod for file %s failed, err = %d", sysAttr, errno);
413     }
414 }
415