1 /*
2  * Copyright (c) 2022 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 <errno.h>
17 #include <linux/netlink.h>
18 #include <poll.h>
19 #include <stdlib.h>
20 #include <sys/socket.h>
21 #include <unistd.h>
22 
23 #include "devmgr_service.h"
24 #include "hdf_dlist.h"
25 #include "hdf_log.h"
26 #include "osal_mem.h"
27 #include "osal_thread.h"
28 #include "osal_time.h"
29 #include "securec.h"
30 
31 #define HDF_LOG_TAG devmgr_uevent
32 
33 #define UEVENT_SOCKET_BUFF_SIZE (256 * 1024)
34 
35 #ifndef LINE_MAX
36 #define LINE_MAX 4096
37 #endif
38 
39 #define ACTION_STR          "ACTION=="
40 #define PNP_EVENT_STR       "HDF_PNP_EVENT="
41 #define KEY_VALUE_DELIMITER "==\""
42 #define KEY_DELIMITER       "\","
43 #define UEVENT_DELIMITER    "="
44 
45 enum DEVMGR_ACTION_TYPE {
46     DEVMGR_ACTION_LOAD,
47     DEVMGR_ACTION_UNLOAD,
48     DEVMGR_ACTION_MAX,
49 };
50 
51 struct DevMgrUeventRuleCfg {
52     char *serviceName;
53     enum DEVMGR_ACTION_TYPE action;
54     struct DListHead matchKeyList;
55     struct DListHead entry;
56 };
57 
58 struct DevMgrMatchKey {
59     char *key;
60     char *value;
61     struct DListHead entry;
62 };
63 
DevMgrUeventRuleCfgList(void)64 static struct DListHead *DevMgrUeventRuleCfgList(void)
65 {
66     static struct DListHead ruleCfgList;
67     static bool initFlag = false;
68 
69     if (!initFlag) {
70         DListHeadInit(&ruleCfgList);
71         initFlag = true;
72     }
73 
74     return &ruleCfgList;
75 }
76 
DevMgrUeventReleaseKeyList(struct DListHead * keyList)77 static void DevMgrUeventReleaseKeyList(struct DListHead *keyList)
78 {
79     struct DevMgrMatchKey *matchKey = NULL;
80     struct DevMgrMatchKey *matchKeyTmp = NULL;
81 
82     if (keyList == NULL) {
83         HDF_LOGE("keyList is null");
84         return;
85     }
86     DLIST_FOR_EACH_ENTRY_SAFE(matchKey, matchKeyTmp, keyList, struct DevMgrMatchKey, entry) {
87         DListRemove(&matchKey->entry);
88         OsalMemFree(matchKey->key);
89         OsalMemFree(matchKey->value);
90         OsalMemFree(matchKey);
91     }
92 }
93 
DevMgrUeventReleaseRuleCfgList(void)94 static void DevMgrUeventReleaseRuleCfgList(void)
95 {
96     struct DevMgrUeventRuleCfg *ruleCfg = NULL;
97     struct DevMgrUeventRuleCfg *ruleCfgTmp = NULL;
98     struct DListHead *ruleCfgList = DevMgrUeventRuleCfgList();
99 
100     DLIST_FOR_EACH_ENTRY_SAFE(ruleCfg, ruleCfgTmp, ruleCfgList, struct DevMgrUeventRuleCfg, entry) {
101         DListRemove(&ruleCfg->entry);
102         DevMgrUeventReleaseKeyList(&ruleCfg->matchKeyList);
103         OsalMemFree(ruleCfg->serviceName);
104         OsalMemFree(ruleCfg);
105     }
106 }
107 
108 // replace substrings "\n" or "\r" in a string with characters '\n' or '\r'
DevMgrUeventReplaceLineFeed(char * str,const char * subStr,char c)109 static void DevMgrUeventReplaceLineFeed(char *str, const char *subStr, char c)
110 {
111     char *ptr = NULL;
112 
113     while ((ptr = strstr(str, subStr)) != NULL) {
114         ptr[0] = c;
115         uint32_t i = 1;
116         if (strlen(ptr) < 1 || strlen(ptr) > SIZE_MAX) {
117             HDF_LOGE("strlen(ptr) overflows");
118             return;
119         }
120         const size_t len = strlen(ptr) - 1;
121         for (; i < len; i++) {
122             ptr[i] = ptr[i + 1];
123         }
124         ptr[i] = '\0';
125     }
126 
127     return;
128 }
129 
DevMgrUeventParseKeyValue(char * str,struct DevMgrMatchKey * matchKey,const char * sep)130 static int32_t DevMgrUeventParseKeyValue(char *str, struct DevMgrMatchKey *matchKey, const char *sep)
131 {
132     char *subPtr = strstr(str, sep);
133     if (subPtr == NULL) {
134         if (strstr(str, "@/") == NULL) {
135             HDF_LOGE("parse Key value failed:[%{public}s]", str);
136         }
137         return HDF_FAILURE;
138     }
139 
140     if (strlen(subPtr) < (strlen(sep) + 1)) {
141         HDF_LOGE("value part invalid:[%{public}s]", str);
142         return HDF_FAILURE;
143     }
144 
145     char *value = subPtr + strlen(sep);
146     *subPtr = '\0';
147     HDF_LOGD("key:%{private}s,value:[%{private}s]", str, value);
148     matchKey->key = strdup(str);
149     matchKey->value = strdup(value);
150     if (matchKey->key == NULL || matchKey->value == NULL) {
151         HDF_LOGE("invalid param : matchKey->key or matchKey->value");
152         return HDF_FAILURE;
153     }
154 
155     return HDF_SUCCESS;
156 }
157 
DevMgrUeventCheckRuleValid(const char * line)158 static bool DevMgrUeventCheckRuleValid(const char *line)
159 {
160     if (strlen(line) < strlen(PNP_EVENT_STR) || line[0] == '#') {
161         return false;
162     }
163 
164     if (strstr(line, PNP_EVENT_STR) == NULL) {
165         HDF_LOGE("%{public}s invalid rule: %{public}s", __func__, line);
166         return false;
167     }
168 
169     return true;
170 }
171 
DevMgrUeventParseMatchKey(char * subStr,struct DListHead * matchKeyList)172 static int32_t DevMgrUeventParseMatchKey(char *subStr, struct DListHead *matchKeyList)
173 {
174     if (subStr == NULL || strlen(subStr) == 0) {
175         HDF_LOGE("match key invalid [%{public}s]", subStr);
176         return HDF_FAILURE;
177     }
178 
179     struct DevMgrMatchKey *matchKey = (struct DevMgrMatchKey *)OsalMemCalloc(sizeof(*matchKey));
180     if (matchKey == NULL) {
181         HDF_LOGE("%{public}s OsalMemCalloc matchKey failed", __func__);
182         return HDF_FAILURE;
183     }
184     if (matchKey->value == NULL || matchKey->key == NULL) {
185         HDF_LOGW("%{public}s OsalMemCalloc matchKey->value or matchKey->key failed", __func__);
186     }
187     DListHeadInit(&matchKey->entry);
188 
189     if (DevMgrUeventParseKeyValue(subStr, matchKey, KEY_VALUE_DELIMITER) == HDF_SUCCESS) {
190         DevMgrUeventReplaceLineFeed(matchKey->value, "\\n", '\n');
191         DevMgrUeventReplaceLineFeed(matchKey->value, "\\r", '\r');
192         DListInsertTail(&matchKey->entry, matchKeyList);
193         return HDF_SUCCESS;
194     } else {
195         OsalMemFree(matchKey);
196         return HDF_FAILURE;
197     }
198 }
199 
DevMgrUeventParseHdfEvent(char * subStr,struct DevMgrUeventRuleCfg * ruleCfg)200 static int32_t DevMgrUeventParseHdfEvent(char *subStr, struct DevMgrUeventRuleCfg *ruleCfg)
201 {
202     if (strncmp(subStr, PNP_EVENT_STR, strlen(PNP_EVENT_STR)) != 0 || strlen(subStr) < strlen(PNP_EVENT_STR) + 1) {
203         HDF_LOGE("parse hdf event %{public}s failed", subStr);
204         return HDF_FAILURE;
205     }
206 
207     char *event = subStr + strlen(PNP_EVENT_STR);
208     char *ptr = strchr(event, ':');
209     if (ptr == NULL) {
210         HDF_LOGE("parse event %{public}s fail, no action", subStr);
211         return HDF_FAILURE;
212     }
213 
214     if (strlen(ptr) < strlen(":load")) {
215         HDF_LOGE("event action part invalid [%{public}s]", ptr);
216         return HDF_FAILURE;
217     }
218 
219     *ptr = '\0';
220     char *action = ptr + 1;
221 
222     // replace line feed
223     ptr = strchr(action, '\n');
224     if (ptr != NULL) {
225         *ptr = '\0';
226     }
227 
228     // replace carriage return
229     ptr = strchr(action, '\r');
230     if (ptr != NULL) {
231         *ptr = '\0';
232     }
233 
234     if (strcmp(action, "load") == 0) {
235         ruleCfg->action = DEVMGR_ACTION_LOAD;
236     } else if (strcmp(action, "unload") == 0) {
237         ruleCfg->action = DEVMGR_ACTION_UNLOAD;
238     } else {
239         HDF_LOGE("parse event action fail [%{public}s]", action);
240         return HDF_FAILURE;
241     }
242 
243     HDF_LOGD("event:%{public}s:%{public}d\n", event, ruleCfg->action);
244     ruleCfg->serviceName = strdup(event);
245     if (ruleCfg->serviceName == NULL) {
246         HDF_LOGE("ruleCfg->serviceName is NULL");
247         return HDF_FAILURE;
248     }
249     if (DListGetCount(&ruleCfg->matchKeyList) == 0) {
250         HDF_LOGE("parse failed, no match key");
251         return HDF_FAILURE;
252     }
253 
254     return HDF_SUCCESS;
255 }
256 
DevMgrUeventParseRule(char * line)257 static int32_t DevMgrUeventParseRule(char *line)
258 {
259     if (!DevMgrUeventCheckRuleValid(line)) {
260         return HDF_FAILURE;
261     }
262 
263     struct DevMgrUeventRuleCfg *ruleCfg = (struct DevMgrUeventRuleCfg *)OsalMemCalloc(sizeof(*ruleCfg));
264     if (ruleCfg == NULL) {
265         HDF_LOGE("%{public}s OsalMemCalloc ruleCfg failed", __func__);
266         return HDF_FAILURE;
267     }
268     if (ruleCfg->serviceName == NULL) {
269         HDF_LOGW("%{public}s OsalMemCalloc ruleCfg->serviceName failed", __func__);
270     }
271     DListHeadInit(&ruleCfg->matchKeyList);
272 
273     char *ptr = line;
274     char *subStr = line;
275     while (ptr != NULL && *ptr != '\0') {
276         ptr = strstr(ptr, KEY_DELIMITER);
277         if (ptr != NULL) {
278             *ptr = '\0';
279             if (DevMgrUeventParseMatchKey(subStr, &ruleCfg->matchKeyList) != HDF_SUCCESS) {
280                 goto FAIL;
281             }
282             ptr += strlen(KEY_DELIMITER);
283             subStr = ptr;
284         } else {
285             if (DevMgrUeventParseHdfEvent(subStr, ruleCfg) != HDF_SUCCESS) {
286                 goto FAIL;
287             }
288             DListInsertTail(&ruleCfg->entry, DevMgrUeventRuleCfgList());
289         }
290     }
291 
292     return HDF_SUCCESS;
293 
294 FAIL:
295     DevMgrUeventReleaseKeyList(&ruleCfg->matchKeyList);
296     OsalMemFree(ruleCfg->serviceName);
297     OsalMemFree(ruleCfg);
298     return HDF_FAILURE;
299 }
300 
DevMgrUeventDisplayRuleCfgList(void)301 static void DevMgrUeventDisplayRuleCfgList(void)
302 {
303     struct DevMgrUeventRuleCfg *ruleCfg = NULL;
304     struct DevMgrMatchKey *matchKey = NULL;
305     struct DListHead *ruleCfgList = DevMgrUeventRuleCfgList();
306 
307     DLIST_FOR_EACH_ENTRY(ruleCfg, ruleCfgList, struct DevMgrUeventRuleCfg, entry) {
308         HDF_LOGD("service:%{public}s action:%{public}d", ruleCfg->serviceName, ruleCfg->action);
309         DLIST_FOR_EACH_ENTRY(matchKey, &ruleCfg->matchKeyList, struct DevMgrMatchKey, entry) {
310             HDF_LOGD("key:%{public}s value:%{public}s", matchKey->key, matchKey->value);
311         }
312     }
313 }
314 
DevMgrUeventParseConfig(void)315 static int32_t DevMgrUeventParseConfig(void)
316 {
317     char path[PATH_MAX] = {0};
318     int ret = sprintf_s(path, PATH_MAX - 1, "%s/hdf_pnp.cfg", HDF_CONFIG_DIR);
319     if (ret < 0) {
320         HDF_LOGE("%{public}s generate file path failed", __func__);
321         return HDF_FAILURE;
322     }
323 
324     char resolvedPath[PATH_MAX] = {0};
325     if (realpath(path, resolvedPath) == NULL) {
326         HDF_LOGE("realpath file: %{public}s failed, errno:%{public}d", path, errno);
327         return HDF_FAILURE;
328     }
329     if (strncmp(resolvedPath, HDF_CONFIG_DIR, strlen(HDF_CONFIG_DIR)) != 0) {
330         HDF_LOGE("%{public}s invalid path %{public}s", __func__, resolvedPath);
331         return HDF_FAILURE;
332     }
333     FILE *file = fopen(resolvedPath, "r");
334     if (file == NULL) {
335         HDF_LOGE("%{public}s fopen %{public}s failed:%{public}d", __func__, resolvedPath, errno);
336         return HDF_FAILURE;
337     }
338 
339     char line[LINE_MAX] = {0};
340     while (fgets(line, sizeof(line), file) != NULL) {
341         HDF_LOGD("%{public}s, %{public}s", __func__, line);
342         DevMgrUeventParseRule(line);
343         (void)memset_s(line, sizeof(line), 0, sizeof(line));
344     }
345 
346     (void)fclose(file);
347     DevMgrUeventDisplayRuleCfgList();
348 
349     return HDF_SUCCESS;
350 }
351 
DevMgrUeventSocketInit(void)352 static int32_t DevMgrUeventSocketInit(void)
353 {
354     struct sockaddr_nl addr;
355     (void)memset_s(&addr, sizeof(addr), 0, sizeof(addr));
356     addr.nl_family = AF_NETLINK;
357     addr.nl_pid = (__u32)getpid();
358     addr.nl_groups = 0xffffffff;
359 
360     int32_t sockfd = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT);
361     if (sockfd < 0) {
362         HDF_LOGE("create socket failed, err = %{public}d", errno);
363         return HDF_FAILURE;
364     }
365 
366     int32_t buffSize = UEVENT_SOCKET_BUFF_SIZE;
367     if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &buffSize, sizeof(buffSize)) != 0) {
368         HDF_LOGE("setsockopt: SO_RCVBUF failed err = %{public}d", errno);
369         close(sockfd);
370         return HDF_FAILURE;
371     }
372 
373     const int32_t on = 1;
374     if (setsockopt(sockfd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) != 0) {
375         HDF_LOGE("setsockopt: SO_PASSCRED failed, err = %{public}d", errno);
376         close(sockfd);
377         return HDF_FAILURE;
378     }
379 
380     if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
381         HDF_LOGE("bind socket failed, err = %{public}d", errno);
382         close(sockfd);
383         return HDF_FAILURE;
384     }
385 
386     return sockfd;
387 }
388 
DevMgrReadUeventMessage(int sockFd,char * buffer,size_t length)389 static ssize_t DevMgrReadUeventMessage(int sockFd, char *buffer, size_t length)
390 {
391     struct sockaddr_nl addr;
392     (void)memset_s(&addr, sizeof(addr), 0, sizeof(addr));
393 
394     struct iovec iov;
395     iov.iov_base = buffer;
396     iov.iov_len = length;
397 
398     char credMsg[CMSG_SPACE(sizeof(struct ucred))] = {0};
399     struct msghdr msghdr = {0};
400     msghdr.msg_name = &addr;
401     msghdr.msg_namelen = sizeof(addr);
402     msghdr.msg_iov = &iov;
403     msghdr.msg_iovlen = 1;
404     msghdr.msg_control = credMsg;
405     msghdr.msg_controllen = sizeof(credMsg);
406 
407     ssize_t n = recvmsg(sockFd, &msghdr, 0);
408     if (n <= 0) {
409         return HDF_FAILURE;
410     }
411 
412     struct cmsghdr *hdr = CMSG_FIRSTHDR(&msghdr);
413     if (hdr == NULL || hdr->cmsg_type != SCM_CREDENTIALS) {
414         HDF_LOGI("Unexpected control message, ignored");
415         // drop this message
416         *buffer = '\0';
417         return HDF_FAILURE;
418     }
419 
420     return n;
421 }
422 
DevMgrUeventMsgCheckValid(const char * msg,ssize_t msgLen)423 static bool DevMgrUeventMsgCheckValid(const char *msg, ssize_t msgLen)
424 {
425     (void)msgLen;
426     if (strncmp(msg, "libudev", strlen("libudev")) == 0) {
427         return false;
428     }
429     return true;
430 }
431 
DevMgrUeventMatchRule(struct DListHead * keyList,struct DListHead * ruleKeyList)432 static bool DevMgrUeventMatchRule(struct DListHead *keyList, struct DListHead *ruleKeyList)
433 {
434     struct DevMgrMatchKey *key = NULL;
435     struct DevMgrMatchKey *keyMsg = NULL;
436 
437     DLIST_FOR_EACH_ENTRY(key, ruleKeyList, struct DevMgrMatchKey, entry) {
438         bool match = false;
439         DLIST_FOR_EACH_ENTRY(keyMsg, keyList, struct DevMgrMatchKey, entry) {
440             if (strcmp(key->key, keyMsg->key) == 0) {
441                 if (strcmp(key->value, keyMsg->value) == 0) {
442                     match = true;
443                     break;
444                 } else {
445                     return false;
446                 }
447             }
448         }
449         if (!match) {
450             return false;
451         }
452     }
453 
454     return true;
455 }
456 
DevMgrUeventProcessPnPEvent(const struct DevMgrUeventRuleCfg * ruleCfg)457 static void DevMgrUeventProcessPnPEvent(const struct DevMgrUeventRuleCfg *ruleCfg)
458 {
459     struct IDevmgrService *instance = DevmgrServiceGetInstance();
460 
461     if (instance == NULL) {
462         HDF_LOGE("Getting DevmgrService instance failed");
463         return;
464     }
465 
466     if (ruleCfg->action == DEVMGR_ACTION_LOAD) {
467         instance->LoadDevice(instance, ruleCfg->serviceName);
468     } else {
469         instance->UnloadDevice(instance, ruleCfg->serviceName);
470     }
471 }
472 
DevMgrUeventMatchRules(struct DListHead * keyList,struct DListHead * ruleList)473 static bool DevMgrUeventMatchRules(struct DListHead *keyList, struct DListHead *ruleList)
474 {
475     struct DevMgrUeventRuleCfg *ruleCfg = NULL;
476 
477     DLIST_FOR_EACH_ENTRY(ruleCfg, ruleList, struct DevMgrUeventRuleCfg, entry) {
478         if (DevMgrUeventMatchRule(keyList, &ruleCfg->matchKeyList)) {
479             HDF_LOGI("%{public}s %{public}s %{public}d", __func__, ruleCfg->serviceName, ruleCfg->action);
480             DevMgrUeventProcessPnPEvent(ruleCfg);
481             return true;
482         }
483     }
484 
485     return false;
486 }
487 
DevMgrParseUevent(char * msg,ssize_t msgLen)488 static int32_t DevMgrParseUevent(char *msg, ssize_t msgLen)
489 {
490     if (!DevMgrUeventMsgCheckValid(msg, msgLen)) {
491         return HDF_FAILURE;
492     }
493 
494     struct DListHead keyList;
495     DListHeadInit(&keyList);
496     struct DevMgrMatchKey *key = NULL;
497 
498     for (char *ptr = msg; ptr < (msg + msgLen);) {
499         if (*ptr == '0') {
500             ptr++;
501             continue;
502         }
503 
504         if (key == NULL) {
505             key = (struct DevMgrMatchKey *)OsalMemCalloc(sizeof(*key));
506             if (key == NULL) {
507                 DevMgrUeventReleaseKeyList(&keyList);
508                 return HDF_FAILURE;
509             }
510             DListHeadInit(&key->entry);
511         }
512 
513         uint32_t subStrLen = (uint32_t)strlen(ptr) + 1;
514         HDF_LOGD("%{public}s %{public}d [%{private}s]", __func__, subStrLen, ptr);
515         if (DevMgrUeventParseKeyValue(ptr, key, UEVENT_DELIMITER) == HDF_SUCCESS) {
516             DListInsertHead(&key->entry, &keyList);
517             key = NULL;
518         }
519         ptr += subStrLen;
520     }
521 
522     HDF_LOGD("%{public}s {%{public}s} %{public}zd", __func__, msg, msgLen);
523     DevMgrUeventMatchRules(&keyList, DevMgrUeventRuleCfgList());
524     DevMgrUeventReleaseKeyList(&keyList);
525 
526     return HDF_SUCCESS;
527 }
528 
529 #define DEVMGR_UEVENT_MSG_SIZE  2048
530 #define DEVMGR_UEVENT_WAIT_TIME 1000
DevMgrUeventThread(void * arg)531 static int32_t DevMgrUeventThread(void *arg)
532 {
533     (void)arg;
534     int32_t sfd = DevMgrUeventSocketInit();
535     if (sfd < 0) {
536         HDF_LOGE("DevMgrUeventSocketInit get sfd error");
537         return HDF_FAILURE;
538     }
539 
540     char msg[DEVMGR_UEVENT_MSG_SIZE + 1] = {0};
541     ssize_t msgLen;
542     struct pollfd fd;
543     (void)memset_s(&fd, sizeof(fd), 0, sizeof(fd));
544     fd.fd = sfd;
545     fd.events = POLLIN | POLLERR;
546     while (true) {
547         if (poll(&fd, 1, -1) <= 0) {
548             HDF_LOGE("%{public}s poll fail %{public}d", __func__, errno);
549             OsalMSleep(DEVMGR_UEVENT_WAIT_TIME);
550             continue;
551         }
552         if (((uint32_t)fd.revents & (POLLIN | POLLERR)) != 0) {
553             int backErrno = errno;
554             msgLen = DevMgrReadUeventMessage(sfd, msg, DEVMGR_UEVENT_MSG_SIZE);
555             if (((uint32_t)fd.revents & POLLERR) != 0) {
556                 HDF_LOGE("%{public}s poll error", __func__);
557             }
558             if (msgLen <= 0) {
559                 HDF_LOGE("%{public}s recv errno: %{public}d", __func__, backErrno);
560                 continue;
561             }
562             DevMgrParseUevent(msg, msgLen);
563             (void)memset_s(&msg, sizeof(msg), 0, sizeof(msg));
564         }
565     }
566 
567     DevMgrUeventReleaseRuleCfgList();
568     close(sfd);
569     return HDF_SUCCESS;
570 }
571 
572 #define DEVMGR_UEVENT_STACK_SIZE 100000
573 
DevMgrUeventReceiveStart(void)574 int32_t DevMgrUeventReceiveStart(void)
575 {
576     HDF_LOGI("DevMgrUeventReceiveStart");
577     if (DevMgrUeventParseConfig() == HDF_FAILURE) {
578         return HDF_FAILURE;
579     }
580 
581     struct OsalThreadParam threadCfg;
582     (void)memset_s(&threadCfg, sizeof(threadCfg), 0, sizeof(threadCfg));
583     threadCfg.name = "DevMgrUevent";
584     threadCfg.priority = OSAL_THREAD_PRI_HIGH;
585     threadCfg.stackSize = DEVMGR_UEVENT_STACK_SIZE;
586 
587     OSAL_DECLARE_THREAD(thread);
588     (void)OsalThreadCreate(&thread, (OsalThreadEntry)DevMgrUeventThread, NULL);
589     (void)OsalThreadStart(&thread, &threadCfg);
590 
591     return HDF_SUCCESS;
592 }
593