Merge branch 'master' of github.com:sylware/cinitramfs
[cinitramfs.git] / modules.c
blobe849ba428752ea61144fe879792c8c68a65e3160
1 /*******************************************************************************
2 this code is protected by the GNU affero GPLv3
3 author:Sylvain BERTRAND <sylvain.bertrand AT gmail dot com>
4 *******************************************************************************/
5 #include <libkmod.h>
7 #include <ulinux/compiler_types.h>
8 #include <ulinux/types.h>
9 #include <ulinux/sysc.h>
11 #include <ulinux/mmap.h>
12 #include <ulinux/error.h>
13 #include <ulinux/file.h>
14 #include <ulinux/fs.h>
15 #include <ulinux/dirent.h>
16 #include <ulinux/utils/mem.h>
17 #include <ulinux/utils/ascii/string/string.h>
19 #include "out.h"
20 #include "ulinux_namespace.h"
21 #include "static_modules.h"
23 static struct kmod_ctx *kmod_ctx;
25 static u8 is_current(u8 *n)
27 if(n[0]=='.'&&n[1]==0) return 1;
28 return 0;
31 static u8 is_parent(u8 *n)
33 if(n[0]=='.'&&n[1]=='.'&&n[2]==0) return 1;
34 return 0;
37 /*that for some kmod stuff*/
38 #define NULL 0
39 static void driver_modules_probe(u8 *modalias)
41 i r;
42 i log_prio;
43 struct kmod_list *list;
44 struct kmod_list *list_entry;
46 list=0;
47 /*shutdown libkmod output since we expect a lot of error/warning messages*/
48 log_prio=kmod_get_log_priority(kmod_ctx);
49 kmod_set_log_priority(kmod_ctx,0);
50 r=kmod_module_new_from_lookup(kmod_ctx,(const char*)modalias,&list);
51 kmod_set_log_priority(kmod_ctx,log_prio);
52 if(r<0) return;/*we may not have any alias for this hardware, skipping*/
54 log_prio=kmod_get_log_priority(kmod_ctx);
55 /*same than above*/
56 kmod_set_log_priority(kmod_ctx,0);
57 kmod_list_foreach(list_entry,list){
58 struct kmod_module *m;
60 m=kmod_module_get_module(list_entry);
61 /*try to probe the driver module, may not be there, keep going in any case*/
62 kmod_module_probe_insert_module(m,KMOD_PROBE_IGNORE_COMMAND,0,0,0,0);
63 kmod_module_unref(m);
65 kmod_set_log_priority(kmod_ctx,log_prio);
66 kmod_module_unref_list(list);
69 #define MODALIAS_SZ_MAX PAGE_SZ/*sysfs attributes are of page sz*/
70 static void modalias_process(i parent_fd)
72 i fd;
73 l r;
74 u8 modalias[MODALIAS_SZ_MAX];
76 loop{
77 fd=(i)ul_openat(parent_fd,"modalias",RDONLY|NONBLOCK);
78 if(fd!=-EINTR) break;
80 if(ISERR(fd)){
81 OUT("WARNING(%d):unable to open modalias, skipping\n",fd);
82 return;
85 /*the size of a page size reported by the sysfs filesystem is not revelant
86 of its content size*/
88 loop{
89 r=read(fd,modalias,MODALIAS_SZ_MAX);
90 if(r!=-EINTR&&r!=-EAGAIN) break;
92 if(ISERR(r)){
93 OUT("ERROR(%ld):unable to read modalias file\n",r);
94 goto close_fd;
97 modalias[r-1]=0;/*replace the modalias \n terminating char with 0*/
99 driver_modules_probe(modalias);
101 close_fd:
102 loop{
103 r=close(fd);
104 if(r!=-EINTR) break;
108 #define MODALIAS_FOUND 1
109 #define MODALIAS_MISSING 0
110 static u8 modalias_search(u8 *dirents,l ds_sz)
112 l d_u8_idx=0;
113 u8 r=MODALIAS_MISSING;
115 loop{
116 struct dirent64 *d;
117 s8 cmp;
119 if(d_u8_idx>=ds_sz) break;
121 d=(struct dirent64*)(dirents+d_u8_idx);
123 cmp=strcmp("modalias",d->name);
124 if(cmp==0){
125 r=MODALIAS_FOUND;
126 break;
129 d_u8_idx+=d->rec_len;
131 return r;
134 /*forward declaration*/
135 static void sys_devices_parse(i parent_fd);
136 static void real_subdirs_recurse(i parent_fd,u8 *dirents,l ds_sz)
138 l d_u8_idx=0;
140 loop{
141 struct dirent64 *d;
143 if(d_u8_idx>=ds_sz) break;
145 d=(struct dirent64*)(dirents+d_u8_idx);
147 if(d->type==DT_DIR&&!is_current(d->name)&&!is_parent(d->name)){
148 i subdir_fd;
150 loop{
151 subdir_fd=(i)ul_openat(parent_fd,d->name,RDONLY|NONBLOCK);
152 if(subdir_fd!=-EINTR) break;
154 if(ISERR(subdir_fd))
155 OUT("WARNING(%d):unable to open subdir:%s:skipping\n",subdir_fd,
156 d->name);
157 else{
158 sys_devices_parse(subdir_fd);
159 loop{
160 l r;
162 r=close(subdir_fd);
163 if(r!=-EINTR) break;
167 d_u8_idx+=d->rec_len;
171 #define DIRENTS_BUF_SZ 8192
173 The dentry type is supported by sysfs. Top-down parsing, we load the tree-upper
174 driver modules first.
176 static void sys_devices_parse(i parent_fd)
178 u8 dirents[DIRENTS_BUF_SZ];
179 l ds_sz;
180 u8 have_modalias;
182 ds_sz=getdents64(parent_fd,dirents,DIRENTS_BUF_SZ);
183 if(ISERR(ds_sz)){
184 OUT("ERROR(%ld):getdents error\n",ds_sz);
185 exit_group(-1);
188 if(!ds_sz) return;/*no dirents*/
190 have_modalias=modalias_search(dirents,ds_sz);
192 if(have_modalias==MODALIAS_FOUND) modalias_process(parent_fd);
194 real_subdirs_recurse(parent_fd,dirents,ds_sz);
197 void modules_probe_name(u8 *name)
199 i r;
200 struct kmod_module *m;
202 r=kmod_module_new_from_name(kmod_ctx,(const char*)name,&m);
204 if(r<0){
205 OUT("ERROR(%d):unable to create a module description for %s, skipping\n",
206 name);
207 return;
210 r=kmod_module_probe_insert_module(m,KMOD_PROBE_IGNORE_COMMAND,0,0,0,0);
211 if(r!=0){
212 OUT("ERROR(%d):unable to probe module %s, skipping\n",r,name);
213 goto unref_module;
216 unref_module:
217 kmod_module_unref(m);
220 /*probe upper layer disk modules and user extra modules*/
221 void modules_probe_static(void)
223 u8 **m_name;
225 m_name=&static_modules[0];
226 loop{
227 if(*m_name==0) break;
229 modules_probe_name(*m_name);
231 ++m_name;
235 void modules_setup(void)
237 kmod_ctx=kmod_new(0,0);
238 if(!kmod_ctx){
239 OUT("ERROR:unable to init libkmod\n");
240 exit_group(-1);
244 void modules_cleanup(void)
246 kmod_unref(kmod_ctx);
247 kmod_ctx=0;
250 void modules_probe_drivers(void)
252 i sys_devices_fd;
254 loop{
255 sys_devices_fd=(i)open("/sys/devices",RDONLY|NONBLOCK);
256 if(sys_devices_fd!=-EINTR) break;
258 if(ISERR(sys_devices_fd)){
259 OUT("ERROR(%d):unable to open /sys/devices dir\n",sys_devices_fd);
260 exit_group(-1);
263 sys_devices_parse(sys_devices_fd);
264 close(sys_devices_fd);