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