2 #include <sys/socket.h>
3 #include <linux/netlink.h>
15 fd
= open_uevent_socket();
19 fcntl(fd
, F_SETFD
, FD_CLOEXEC
);
20 fcntl(fd
, F_SETFL
, O_NONBLOCK
);
22 coldboot(fd
, "/sys/class");
23 coldboot(fd
, "/sys/block");
24 coldboot(fd
, "/sys/devices");
29 int open_uevent_socket(void)
31 struct sockaddr_nl addr
;
35 memset(&addr
, 0, sizeof(addr
));
36 addr
.nl_family
= AF_NETLINK
;
37 addr
.nl_pid
= getpid();
38 addr
.nl_groups
= 0xffffffff;
40 s
= socket(PF_NETLINK
, SOCK_DGRAM
, NETLINK_KOBJECT_UEVENT
);
44 setsockopt(s
, SOL_SOCKET
, SO_RCVBUFFORCE
, &sz
, sizeof(sz
));
46 if(bind(s
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0) {
54 void coldboot(int event_fd
, const char *path
)
56 DIR *d
= opendir(path
);
58 do_coldboot(event_fd
, d
);
63 void do_coldboot(int event_fd
, DIR *d
)
70 fd
= openat(dfd
, "uevent", O_WRONLY
);
72 write(fd
, "add\n", 4);
74 handle_device_fd(event_fd
);
77 while((de
= readdir(d
))) {
80 if(de
->d_type
!= DT_DIR
|| de
->d_name
[0] == '.')
83 fd
= openat(dfd
, de
->d_name
, O_RDONLY
| O_DIRECTORY
);
91 do_coldboot(event_fd
, d2
);
97 #define UEVENT_MSG_LEN 1024
98 void handle_device_fd(int fd
)
100 char msg
[UEVENT_MSG_LEN
+2];
103 while((n
= recv(fd
, msg
, UEVENT_MSG_LEN
, 0)) > 0) {
104 struct uevent uevent
;
106 if(n
== UEVENT_MSG_LEN
) /* overflow -- discard */
112 parse_event(msg
, &uevent
);
114 handle_device_event(&uevent
);
115 //handle_firmware_event(&uevent);
119 void parse_event(const char *msg
, struct uevent
*uevent
)
123 uevent
->subsystem
= "";
124 uevent
->firmware
= "";
128 /* currently ignoring SEQNUM */
130 if(!strncmp(msg
, "ACTION=", 7)) {
132 uevent
->action
= msg
;
133 } else if(!strncmp(msg
, "DEVPATH=", 8)) {
136 } else if(!strncmp(msg
, "SUBSYSTEM=", 10)) {
138 uevent
->subsystem
= msg
;
139 } else if(!strncmp(msg
, "FIRMWARE=", 9)) {
141 uevent
->firmware
= msg
;
142 } else if(!strncmp(msg
, "MAJOR=", 6)) {
144 uevent
->major
= atoi(msg
);
145 } else if(!strncmp(msg
, "MINOR=", 6)) {
147 uevent
->minor
= atoi(msg
);
150 /* advance to after the next \0 */
155 /*INFO("event { '%s', '%s', '%s', '%s', %d, %d }\n",
156 uevent->action, uevent->path, uevent->subsystem,
157 uevent->firmware, uevent->major, uevent->minor);*/
160 void handle_device_event(struct uevent
*uevent
)
166 /* if it's not a /dev device, nothing to do */
167 if((uevent
->major
< 0) || (uevent
->minor
< 0))
170 /* do we have a name? */
171 name
= strrchr(uevent
->path
, '/');
176 /* too-long names would overrun our buffer */
177 if(strlen(name
) > 64)
180 /* are we block or char? where should we live? */
181 if(!strncmp(uevent
->subsystem
, "block", 5)) {
183 base
= "/dev/block/";
187 /* this should probably be configurable somehow */
188 if(!strncmp(uevent
->subsystem
, "graphics", 8)) {
189 base
= "/dev/graphics/";
191 } else if (!strncmp(uevent
->subsystem
, "oncrpc", 6)) {
192 base
= "/dev/oncrpc/";
194 } else if (!strncmp(uevent
->subsystem
, "adsp", 4)) {
197 } else if (!strncmp(uevent
->subsystem
, "msm_camera", 10)) {
198 base
= "/dev/msm_camera/";
200 } else if(!strncmp(uevent
->subsystem
, "input", 5)) {
201 base
= "/dev/input/";
203 } else if(!strncmp(uevent
->subsystem
, "mtd", 3)) {
206 } else if(!strncmp(uevent
->subsystem
, "sound", 5)) {
209 } else if(!strncmp(uevent
->subsystem
, "misc", 4) &&
210 !strncmp(name
, "log_", 4)) {
218 snprintf(devpath
, sizeof(devpath
), "%s%s", base
, name
);
220 if(!strcmp(uevent
->action
, "add")) {
221 make_device(devpath
, block
, uevent
->major
, uevent
->minor
);
225 if(!strcmp(uevent
->action
, "remove")) {
231 void make_device(const char *path
, int block
, int major
, int minor
)
238 if(major
> 255 || minor
> 255)
241 mode
= get_device_perm(path
, &uid
, &gid
) | (block
? S_IFBLK
: S_IFCHR
);
242 dev
= (major
<< 8) | minor
;
243 mknod(path
, mode
, dev
);
244 chown(path
, uid
, gid
);
247 mode_t
get_device_perm(const char *path
, unsigned *uid
, unsigned *gid
)