Merge branch 'master' of github.com:sylware/cinitramfs
[cinitramfs.git] / uevents.c
blobcfe47059c2c26697fd02d2f18b0afe68dc7627fd
1 /*******************************************************************************
2 this code is protected by the GNU affero GPLv3
3 author:Sylvain BERTRAND <sylvain.bertrand AT gmail dot com>
4 *******************************************************************************/
5 #include <ulinux/compiler_types.h>
6 #include <ulinux/sysc.h>
7 #include <ulinux/types.h>
8 #include <ulinux/error.h>
9 #include <ulinux/socket/socket.h>
10 #include <ulinux/socket/msg.h>
11 #include <ulinux/socket/netlink.h>
12 #include <ulinux/epoll.h>
13 #include <ulinux/utils/mem.h>
15 #include "out.h"
16 #include "ulinux_namespace.h"
17 #include "globals.h"
18 #include "uevent.h"
19 static i ep_fd;
20 static i so;
22 void uevents_cleanup(void)
24 l r;
25 loop{
26 r=close(ep_fd);
27 if(r!=-EINTR) break;
29 if(ISERR(r)){
30 OUT("ERROR(%ld):unable to close epoll fd\n",r);
31 exit_group(-1);
34 loop{
35 r=close(so);
36 if(r!=-EINTR) break;
38 if(ISERR(r)){
39 OUT("ERROR(%ld):unable to close netlink socket\n",r);
40 exit_group(-1);
44 void uevents_setup(void)
46 i recv_buf_sz;
47 i r;
48 struct sockaddr_nl addr={AF_NETLINK,0,0,1};
49 struct epoll_event ep_evt;
51 OUT(PRE "setting up uevent...");
52 ep_fd=(i)epoll_create1(0);
53 if(ISERR(ep_fd)){
54 OUT("ERROR(%d):unable to create epoll fd\n",ep_fd);
55 exit_group(-1);
58 /*--------------------------------------------------------------------------*/
60 /* blocking socket */
61 so=(i)socket(PF_NETLINK,SOCK_RAW,NETLINK_KOBJECT_UEVENT);
62 if(ISERR(so)){
63 OUT("ERROR(%d):unable to create uevent netlink socket\n",so);
64 exit_group(-1);
67 /*--------------------------------------------------------------------------*/
69 recv_buf_sz=128*1024;/* 128k for kernel buffering */
70 r=setsockopt(so,SOL_SOCKET,SO_RCVBUFFORCE,&recv_buf_sz,sizeof(recv_buf_sz));
71 if(ISERR(r)){
72 OUT("ERROR(%ld):unable to force the size of the socket buffer\n",r);
73 exit_group(-1);
76 /*--------------------------------------------------------------------------*/
78 /* uevent groups-->only one: 1 */
79 r=bind(so,&addr,sizeof(addr));
80 if(ISERR(r)){
81 OUT("ERROR(%ld):unable to bind address to uevent netlink socket\n",r);
82 exit_group(-1);
85 /*--------------------------------------------------------------------------*/
87 memset(&ep_evt,0,sizeof(ep_evt));
88 ep_evt.events=EPOLLIN;
89 ep_evt.data.fd=so;
90 r=epoll_ctl(ep_fd,EPOLL_CTL_ADD,so,&ep_evt);
91 if(ISERR(r)){
92 OUT("ERROR(%ld):unable to register uevent netlink socket to epoll\n",r);
93 exit_group(-1);
95 OUT("done\n");
98 static u8 uevent_msg(void)
100 u8 buf[8192];/*presume 8kB is enough for one message*/
101 struct io_vec uev_io_vec;
102 struct msg_hdr msg;
103 l r;
105 memset(buf,0,sizeof(buf));
107 uev_io_vec.base=buf;
108 uev_io_vec.len=sizeof(buf);
110 memset(&msg,0,sizeof(msg));
111 msg.iov=&uev_io_vec;
112 msg.iov_len=1;
114 loop{
115 r=recvmsg(so,&msg,0);
116 if(r!=-EINTR) break;
118 if(ISERR(r)){
119 OUT("ERROR(%ld):unable to receive the uevent\n",r);
120 exit_group(-1);
122 if(msg.flgs&MSG_TRUNC){
123 OUT("ERROR:the uevent was truncated(flags=0x%x)\n",msg.flgs);
124 exit_group(-1);
126 return uevent_process(&buf[0],(i)r);
129 u8 uevents_process(void)
131 u8 r;
133 r=ROOT_NOT_FOUND;
134 OUT(PRE "processing uevents...\n");
135 loop{
136 l r1;
137 static struct epoll_event evts;/*uevent netlink event*/
138 loop{
139 memset(&evts,0,sizeof(evts));
140 r1=epoll_wait(ep_fd,&evts,1,UEVENTS_TIMEOUT);
142 if(r1!=-EINTR) break;
144 if(ISERR(r1)){
145 OUT(PRE "ERROR(%ld):error epolling uevent netlink socket\n",r1);
146 exit_group(-1);
148 if(!r1) break;/*assume no more uevents and unable to find root*/
149 if(evts.events&EPOLLIN){
150 r=uevent_msg();
151 if(r==ROOT_FOUND) break;
152 }else{
153 OUT(PRE "ERROR:unmanaged epolling event on uevent netlink socket(events=%u)\n",
154 evts.events);
155 exit_group(-1);
158 OUT(PRE "uevents processing terminated\n");
159 return r;