1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <hardware_legacy/uevent.h>
18 
19 #include <malloc.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <poll.h>
23 #include <pthread.h>
24 
25 #include <sys/socket.h>
26 #include <sys/un.h>
27 #include <sys/queue.h>
28 #include <linux/netlink.h>
29 
30 
31 LIST_HEAD(uevent_handler_head, uevent_handler) uevent_handler_list;
32 pthread_mutex_t uevent_handler_list_lock = PTHREAD_MUTEX_INITIALIZER;
33 
34 struct uevent_handler {
35     void (*handler)(void *data, const char *msg, int msg_len);
36     void *handler_data;
37     LIST_ENTRY(uevent_handler) list;
38 };
39 
40 static int fd = -1;
41 
42 /* Returns 0 on failure, 1 on success */
uevent_init()43 int uevent_init()
44 {
45     struct sockaddr_nl addr;
46     int sz = 64*1024;
47     int s;
48 
49     memset(&addr, 0, sizeof(addr));
50     addr.nl_family = AF_NETLINK;
51     addr.nl_pid = getpid();
52     addr.nl_groups = 0xffffffff;
53 
54     s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
55     if(s < 0)
56         return 0;
57 
58     setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
59 
60     if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
61         close(s);
62         return 0;
63     }
64 
65     fd = s;
66     return (fd > 0);
67 }
68 
uevent_get_fd()69 int uevent_get_fd()
70 {
71     return fd;
72 }
73 
uevent_next_event(char * buffer,int buffer_length)74 int uevent_next_event(char* buffer, int buffer_length)
75 {
76     while (1) {
77         struct pollfd fds;
78         int nr;
79 
80         fds.fd = fd;
81         fds.events = POLLIN;
82         fds.revents = 0;
83         nr = poll(&fds, 1, -1);
84 
85         if(nr > 0 && (fds.revents & POLLIN)) {
86             int count = recv(fd, buffer, buffer_length, 0);
87             if (count > 0) {
88                 struct uevent_handler *h;
89                 pthread_mutex_lock(&uevent_handler_list_lock);
90                 LIST_FOREACH(h, &uevent_handler_list, list)
91                     h->handler(h->handler_data, buffer, buffer_length);
92                 pthread_mutex_unlock(&uevent_handler_list_lock);
93 
94                 return count;
95             }
96         }
97     }
98 
99     // won't get here
100     return 0;
101 }
102 
uevent_add_native_handler(void (* handler)(void * data,const char * msg,int msg_len),void * handler_data)103 int uevent_add_native_handler(void (*handler)(void *data, const char *msg, int msg_len),
104                              void *handler_data)
105 {
106     struct uevent_handler *h;
107 
108     h = malloc(sizeof(struct uevent_handler));
109     if (h == NULL)
110         return -1;
111     h->handler = handler;
112     h->handler_data = handler_data;
113 
114     pthread_mutex_lock(&uevent_handler_list_lock);
115     LIST_INSERT_HEAD(&uevent_handler_list, h, list);
116     pthread_mutex_unlock(&uevent_handler_list_lock);
117 
118     return 0;
119 }
120 
uevent_remove_native_handler(void (* handler)(void * data,const char * msg,int msg_len))121 int uevent_remove_native_handler(void (*handler)(void *data, const char *msg, int msg_len))
122 {
123     struct uevent_handler *h;
124     int err = -1;
125 
126     pthread_mutex_lock(&uevent_handler_list_lock);
127     LIST_FOREACH(h, &uevent_handler_list, list) {
128         if (h->handler == handler) {
129             LIST_REMOVE(h, list);
130             err = 0;
131             break;
132        }
133     }
134     pthread_mutex_unlock(&uevent_handler_list_lock);
135 
136     return err;
137 }
138