List of commits:
Subject Hash Author Date (UTC)
first extraction and cleanup 67a09ceb6fc5b3536801096e1002347e2f115ddc Sylvain BERTRAND 2017-07-22 02:00:46
Commit 67a09ceb6fc5b3536801096e1002347e2f115ddc - first extraction and cleanup
Author: Sylvain BERTRAND
Author date (UTC): 2017-07-22 02:00
Committer name: Sylvain BERTRAND
Committer date (UTC): 2017-07-22 02:00
Parent(s):
Signer:
Signing key:
Signing status: N
Tree: b9fd4fe6f7d07298882dd29ec6312001381955fa
File Lines added Lines deleted
LICENSE 1 0
README 17 0
libkmod.sym 96 0
make 289 0
make.kmod.sh 75 0
make.libkmod.sh 82 0
src/config.h 20 0
src/libkmod-config.c 1219 0
src/libkmod-elf.c 1187 0
src/libkmod-file.c 393 0
src/libkmod-index.c 1083 0
src/libkmod-index.h 53 0
src/libkmod-internal.h 252 0
src/libkmod-list.c 326 0
src/libkmod-module.c 2828 0
src/libkmod-namespace.h 41 0
src/libkmod-signature.c 157 0
src/libkmod.c 960 0
src/libkmod.h 264 0
src/shared/array.c 116 0
src/shared/array.h 28 0
src/shared/hash.c 346 0
src/shared/hash.h 28 0
src/shared/linux-syscalls.h 12 0
src/shared/macro.h 47 0
src/shared/scratchbuf.c 66 0
src/shared/scratchbuf.h 34 0
src/shared/strbuf.c 138 0
src/shared/strbuf.h 37 0
src/shared/util.c 571 0
src/shared/util.h 61 0
src/tools/depmod.c 2815 0
src/tools/insmod.c 172 0
src/tools/kmod.c 198 0
src/tools/kmod.h 98 0
src/tools/log.c 156 0
src/tools/log.h 39 0
src/tools/lsmod.c 105 0
src/tools/modinfo.c 473 0
src/tools/modprobe.c 924 0
src/tools/rmmod.c 204 0
src/tools/static-nodes.c 286 0
File LICENSE added (mode: 100644) (index 0000000..e602274)
1 See linux kmod license.
File README added (mode: 100644) (index 0000000..f838b13)
1 This is more than a code extraction of libkmod and kmod from linux kmod as I
2 did rewrite some of the code to remove most dependencies on _GNU_SOURCE. Many
3 things were tidy up and simplified too.
4
5 The main purpose is to get a symbol collision secure static linking of
6 libkmod.a.
7
8 ... and no autotools, libtool, cmake, meson, scons, ninja, perl, python... in
9 the SDK.... YEAY!
10
11 The "configuration" is set in stone, but this is only the first commit.
12
13 The headers need some tightening though.
14
15 --
16 Sylvain BERTRAND
17 sylvain.bertrand@gmail.com
File libkmod.sym added (mode: 100644) (index 0000000..95f1c1f)
1 LIBKMOD_5 {
2 global:
3 kmod_get_log_priority;
4 kmod_get_userdata;
5 kmod_new;
6 kmod_ref;
7 kmod_set_log_fn;
8 kmod_set_log_priority;
9 kmod_set_userdata;
10 kmod_unref;
11 kmod_list_next;
12 kmod_list_prev;
13 kmod_list_last;
14
15 kmod_load_resources;
16 kmod_unload_resources;
17 kmod_validate_resources;
18 kmod_config_get_blacklists;
19 kmod_config_get_install_commands;
20 kmod_config_get_remove_commands;
21 kmod_config_get_aliases;
22 kmod_config_get_options;
23 kmod_config_get_softdeps;
24 kmod_config_iter_get_key;
25 kmod_config_iter_get_value;
26 kmod_config_iter_next;
27 kmod_config_iter_free_iter;
28 kmod_dump_index;
29
30 kmod_module_new_from_name;
31 kmod_module_new_from_path;
32 kmod_module_new_from_lookup;
33 kmod_module_new_from_loaded;
34 kmod_module_ref;
35 kmod_module_unref;
36 kmod_module_unref_list;
37 kmod_module_get_module;
38 kmod_module_remove_module;
39 kmod_module_insert_module;
40 kmod_module_probe_insert_module;
41
42 kmod_module_get_dependencies;
43 kmod_module_get_softdeps;
44 kmod_module_get_filtered_blacklist;
45
46 kmod_module_get_name;
47 kmod_module_get_path;
48
49 kmod_module_initstate_str;
50 kmod_module_get_initstate;
51 kmod_module_get_refcnt;
52 kmod_module_get_sections;
53 kmod_module_section_free_list;
54 kmod_module_section_get_name;
55 kmod_module_section_get_address;
56 kmod_module_get_holders;
57 kmod_module_get_size;
58
59 kmod_module_get_options;
60 kmod_module_get_install_commands;
61 kmod_module_get_remove_commands;
62
63 kmod_module_get_info;
64 kmod_module_info_get_key;
65 kmod_module_info_get_value;
66 kmod_module_info_free_list;
67 kmod_module_get_versions;
68 kmod_module_version_get_symbol;
69 kmod_module_version_get_crc;
70 kmod_module_versions_free_list;
71 kmod_module_get_symbols;
72 kmod_module_symbol_get_symbol;
73 kmod_module_symbol_get_crc;
74 kmod_module_symbols_free_list;
75
76 kmod_module_get_dependency_symbols;
77 kmod_module_dependency_symbol_get_symbol;
78 kmod_module_dependency_symbol_get_crc;
79 kmod_module_dependency_symbol_get_bind;
80 kmod_module_dependency_symbols_free_list;
81 local:
82 *;
83 };
84
85 LIBKMOD_6 {
86 global:
87 kmod_module_apply_filter;
88 kmod_get_dirname;
89 } LIBKMOD_5;
90
91 LIBKMOD_22 {
92 global:
93 __kmod_list_append;
94 __kmod_list_remove;
95 __kmod_list_remove_data;
96 } LIBKMOD_6;
File make added (mode: 100755) (index 0000000..6ca62dd)
1 #!/bin/sh
2
3 #this script is brutal and verbose, has no tricks and is quite linear, then
4 #quite easy to deal with
5 #for the moment, it's hardcoded for a gcc toolchain... BAD! Since now
6 #gcc is a c++ piece of shit
7
8 # stolen from ffmpeg configure like a pig
9 set -e
10
11 # prevent locale nonsense from breaking basic text processing
12 LC_ALL=C
13 export LC_ALL
14
15 # libtool versioning?? Is age ok??
16 libkmod_api=2
17 libkmod_rev=3
18 libkmod_age=2
19 libkmod_so_version=${libkmod_api}.${libkmod_rev}.${libkmod_age}
20 fake_root=fake_root
21 #-------------------------------------------------------------------------------
22
23 # it's benign here, but keep in mind it does define the order of static linking
24 # which is important for proper symbol selection
25 libkmod_src_files='
26 src/libkmod.c
27 src/libkmod-list.c
28 src/libkmod-config.c
29 src/libkmod-index.c
30 src/libkmod-module.c
31 src/libkmod-file.c
32 src/libkmod-elf.c
33 src/libkmod-signature.c
34 src/shared/util.c
35 src/shared/strbuf.c
36 '
37
38 # it's benign here, but keep in mind it does define the order of static linking
39 # which is important for proper symbol selection
40 kmod_src_files='
41 src/tools/kmod.c
42 src/tools/lsmod.c
43 src/tools/rmmod.c
44 src/tools/insmod.c
45 src/tools/modinfo.c
46 src/tools/modprobe.c
47 src/tools/depmod.c
48 src/tools/static-nodes.c
49 src/tools/log.c
50 src/shared/util.c
51 src/shared/strbuf.c
52 src/shared/hash.c
53 src/shared/array.c
54 src/shared/scratchbuf.c
55 '
56 #-------------------------------------------------------------------------------
57
58 sep_start()
59 {
60 printf '###############################################################################\n'
61 }
62
63 sep_end()
64 {
65 printf '###############################################################################\n\n'
66 }
67
68 subsep_start()
69 {
70 printf '*******************************************************************************\n'
71 }
72
73 subsep_end()
74 {
75 printf '*******************************************************************************\n'
76 }
77
78 ################################################################################
79
80 if test -f make; then
81 src_path=.
82 else
83 src_path=$(cd $(dirname "$0"); pwd)
84 echo "$src_path" | grep -q '[[:blank:]]' &&
85 die "out of tree builds are impossible with whitespace in source path."
86 fi
87
88 ################################################################################
89
90 is_in()
91 {
92 value=$1
93 shift
94 for var in $*; do
95 [ $var = $value ] && return 0
96 done
97 return 1
98 }
99
100 die_unknown()
101 {
102 echo "Unknown option \"$1\"."
103 echo "See $0 --help for available options."
104 exit 1
105 }
106
107 set_default()
108 {
109 for opt; do
110 eval : \${$opt:=\$${opt}_default}
111 done
112 }
113
114 spaces_concat()
115 {
116 printf "$1" | tr -s '[:space:]' ' '
117 }
118
119 CMDLINE_SET='
120 bin_cc
121 bin_ccld
122 libkmod_cc
123 libkmod_ar
124 dbin_cc
125 dbin_ccld
126 slibkmod_cc
127 slibkmod_ccld
128 prefix
129 bindir
130 libdir
131 includedir
132 sysconfdir
133 '
134
135 ################################################################################
136
137 #command line set defaults
138 #-------------------------------------------------------------------------------
139 bin_cc_default="gcc -Wall -Wextra -Wno-unused-parameter \
140 -Wno-format-truncation \
141 -std=gnu99 -O2 -c"
142
143 bin_ccld_default="gcc -static"
144
145 libkmod_cc_default="gcc -Wall -Wextra -Wno-unused-parameter \
146 -std=gnu99 -O2 -fPIC -c"
147
148 libkmod_ar_default="ar rcs"
149
150 dbin_cc_default="gcc -Wall -Wextra -Wno-unused-parameter \
151 -Wno-format-truncation \
152 -std=gnu99 -O2 -c"
153
154 dbin_ccld_default="gcc -Wl,--as-needed"
155
156 slibkmod_cc_default="gcc -Wall -Wextra -Wno-unused-parameter \
157 -std=gnu99 -O2 -fPIC -c"
158
159 slibkmod_ccld_default="gcc -shared \
160 -Wl,--version-script=$src_path/libkmod.sym \
161 -Wl,-soname,libkmod.so.$libkmod_api \
162 -Wl,--as-needed"
163 #-------------------------------------------------------------------------------
164
165 prefix_default=/usr/local
166 bindir_default='$prefix/bin'
167 libdir_default='$prefix/lib'
168 includedir_default='$prefix/include'
169 sysconfdir_default='$prefix/etc'
170 set_default $CMDLINE_SET
171
172 libkmod_only=no
173 disable_static=no
174 disable_dynamic=no
175
176 ################################################################################
177
178
179 ################################################################################
180
181 show_help(){
182 cat <<EOF
183 Usage: make [options]
184
185 default to build libkmod and kmod
186
187 Options: [defaults in brackets after descriptions]
188
189 Help options:
190 --help print this message
191
192 Standard options:
193 --libkmod-only build only libkmod
194 --disable-static disable the build of static lib and static binary
195 --disable-dynamic disable the build of shared lib and dynamic binary
196
197 --prefix=PREFIX architecture independent prefix [$prefix_default]
198 --eprefix=EPREFIX architecture dependent exec prefix [$eprefix_default]
199 --libdir=DIR object code libraries [$libdir_default]
200 --includedir=DIR C header files [$includedir_default]
201 --sysconfdir=DIR read-only single-machine data [$sysconfdir_default]
202
203 Advanced options:
204 --bin-cc=CC use C compiler command line CC for static target kmod [$(spaces_concat "$bin_cc_default")]
205 --bin-ccld=CCLD use linker command line CCLD for static target kmod [$(spaces_concat "$bin_ccld_default")]
206
207 --dbin-cc=CC use C compiler command line CC for dynamic target kmod [$(spaces_concat "$dbin_cc_default")]
208 --dbin-ccld=CCLD use linker command line CCLD for dynamic target kmod [$(spaces_concat "$dbin_ccld_default")]
209
210 --libkmod-cc=CC use C compiler command line CC for static target libkmod [$(spaces_concat "$libkmod_cc_default")]
211 --libkmod-ar=AR use archive command line AR for static target libkmod [$(spaces_concat "$libkmod_ar_default")]
212
213 --slibkmod-cc=CC use C compiler command line CC for shared target libkmod [$(spaces_concat "$slibkmod_cc_default")]
214 --slibkmod-ccld=CCLD use linker command line CCLD for shared target libkmod [$(spaces_concat "$slibkmod_ccld_default")]
215 EOF
216 exit 0
217 }
218
219 ################################################################################
220
221 for opt do
222 optval="${opt#*=}"
223 case "$opt" in
224 --help|-h) show_help
225 ;;
226 --libkmod-only)
227 libkmod_only=yes
228 ;;
229 --disable-static)
230 disable_static=yes
231 ;;
232 --disable-dynamic)
233 disable_dynamic=yes
234 ;;
235 *)
236 optname=${opt%%=*}
237 optname=${optname#--}
238 optname=$(echo "$optname" | sed 's/-/_/g')
239 if is_in $optname $CMDLINE_SET; then
240 eval $optname='$optval'
241 else
242 die_unknown $opt
243 fi
244 ;;
245 esac
246 done
247
248 ################################################################################
249
250 sep_start;echo "source path is $src_path";sep_end
251
252 path_expand()
253 {
254 e_v=$1
255 #we set a maximum expansion depth of 3
256 for d in 1 2 3
257 do
258 e_v=$(eval echo "$e_v")
259 done
260 #get rid of ugly double // in path
261 echo "$e_v" | sed -e 's%//%/%g'
262 }
263
264 sep_start;echo 'expanding final paths:'
265 e_prefix=$(path_expand "$prefix")
266 e_bindir=$(path_expand "$bindir")
267 e_libdir=$(path_expand "$libdir")
268 e_includedir=$(path_expand "$includedir")
269 e_sysconfdir=$(path_expand "$sysconfdir")
270 echo "prefix=$e_prefix"
271 echo "bin=$e_bindir"
272 echo "libdir=$e_libdir"
273 echo "includedir=$e_includedir"
274 echo "sysconfdir=$e_sysconfdir"
275 sep_end
276
277 ################################################################################
278
279 mkdir -p -- ./src
280 printf "#ifndef LIBKMOD_PATHS_H\n#define LIBKMOD_PATHS_H\n#define SYSCONFDIR \"%b\"\n#endif" "$e_sysconfdir" >./src/libkmod-paths.h
281
282 ################################################################################
283
284 . $src_path/make.libkmod.sh
285 if test x$libkmod_only != xyes; then
286 . $src_path/make.kmod.sh
287 fi
288
289 ################################################################################
File make.kmod.sh added (mode: 100644) (index 0000000..44e692a)
1 if test x$disable_dynamic = xno; then
2 ################################################################################
3 sep_start;echo 'dkmod:compile src files'
4 for kmod_src_file in $kmod_src_files
5 do
6 # build an object name which is prefixed with 'd', 'D'ynamic
7 dkmod_o_file=${kmod_src_file%.c}
8 dkmod_o_file_name=$(basename $dkmod_o_file)
9 dkmod_o_file=$(dirname $dkmod_o_file)/d${dkmod_o_file_name}.o
10
11 echo "DBIN_CC $kmod_src_file-->$dkmod_o_file"
12 mkdir -p -- $(dirname $dkmod_o_file)
13
14 $dbin_cc -o $dkmod_o_file \
15 -I./src \
16 -I$src_path/src/tools \
17 -I$src_path/src \
18 $src_path/$kmod_src_file
19
20 dkmod_o_files="$dkmod_o_file $dkmod_o_files"
21 done
22 sep_end
23
24 #-------------------------------------------------------------------------------
25
26 mkdir -p -- $fake_root${e_bindir}d
27
28 #-------------------------------------------------------------------------------
29
30 sep_start;echo 'dkmod:link the object files to produce the dynamic binary'
31 echo "DBIN_CCLD kmod"
32 $dbin_ccld -o $fake_root${e_bindir}d/kmod \
33 $dkmod_o_files \
34 $fake_root$e_libdir/libkmod.so.$libkmod_so_version
35 sep_end
36
37 ################################################################################
38 fi
39
40
41 if test x$disable_static = xno; then
42 ################################################################################
43 sep_start;echo 'kmod:compile src files'
44 for kmod_src_file in $kmod_src_files
45 do
46 kmod_o_file=${kmod_src_file%.c}
47 kmod_o_file=${kmod_o_file}.o
48
49 echo "BIN_CC $kmod_src_file-->$kmod_o_file"
50 mkdir -p -- $(dirname $kmod_o_file)
51
52 $bin_cc -o $kmod_o_file \
53 -I./src/ \
54 -I$src_path/src/tools \
55 -I$src_path/src \
56 $src_path/$kmod_src_file
57
58 kmod_o_files="$kmod_o_file $kmod_o_files"
59 done
60 sep_end
61
62 #-------------------------------------------------------------------------------
63
64 mkdir -p -- $fake_root$e_bindir
65
66 #-------------------------------------------------------------------------------
67
68 sep_start;echo 'kmod:link the object files to produce the static binary'
69 echo "BIN_CCLD kmod"
70 $bin_ccld -o $fake_root$e_bindir/kmod \
71 $kmod_o_files \
72 $fake_root$e_libdir/libkmod.a
73 sep_end
74 ################################################################################
75 fi
File make.libkmod.sh added (mode: 100644) (index 0000000..18374ad)
1 if test x$disable_dynamic = xno; then
2 ################################################################################
3 sep_start;echo 'slibkmod:compile src files'
4 for libkmod_src_file in $libkmod_src_files
5 do
6 # build an object name which is prefixed with 's', 'S'hared lib
7 slibkmod_o_file=${libkmod_src_file%.c}
8 slibkmod_o_file_name=$(basename $slibkmod_o_file)
9 slibkmod_o_file=$(dirname $slibkmod_o_file)/s${slibkmod_o_file_name}.o
10
11 echo "SLIBKMOD_CC $libkmod_src_file-->$slibkmod_o_file"
12 mkdir -p -- $(dirname $slibkmod_o_file)
13
14 $slibkmod_cc -o $slibkmod_o_file \
15 -DNAMESPACE_ON \
16 -I./src \
17 -I$src_path/src \
18 $src_path/$libkmod_src_file
19
20 slibkmod_o_files="$slibkmod_o_file $slibkmod_o_files"
21 done
22 sep_end
23
24 #-------------------------------------------------------------------------------
25
26 sep_start;echo 'slibkmod:link the object files to produce the shared library'
27 echo "SLIBKMOD_CCLD libkmod.so.$libkmod_so_version"
28 mkdir -p -- $fake_root$e_libdir
29
30 $slibkmod_ccld -o $fake_root$e_libdir/libkmod.so.$libkmod_so_version \
31 $slibkmod_o_files
32
33 ln -sf libkmod.so.$libkmod_so_version \
34 $fake_root$e_libdir/libkmod.so.$libkmod_api
35 ln -sf libkmod.so.$libkmod_api \
36 $fake_root$e_libdir/libkmod.so
37 sep_end
38 ################################################################################
39 fi
40
41
42 if test x$disable_static = xno; then
43 ################################################################################
44 sep_start;echo 'libkmod:compile src files'
45 for libkmod_src_file in $libkmod_src_files
46 do
47 # build an object name which is prefixed with 'a', 'A'rchive, lib.'a'
48 libkmod_o_file=${libkmod_src_file%.c}
49 libkmod_o_file_name=$(basename $libkmod_o_file)
50 libkmod_o_file=$(dirname $libkmod_o_file)/a${libkmod_o_file_name}.o
51
52 echo "LIBKMOD_CC $libkmod_src_file-->$libkmod_o_file"
53 mkdir -p -- $(dirname $libkmod_o_file)
54
55 $libkmod_cc -o $libkmod_o_file \
56 -DNAMESPACE_ON \
57 -I./src \
58 -I$src_path/src \
59 $src_path/$libkmod_src_file
60
61 libkmod_o_files="$libkmod_o_file $libkmod_o_files"
62 done
63 sep_end
64
65 #-------------------------------------------------------------------------------
66
67 sep_start;echo 'libkmod:archive the object files to produce the static library'
68 echo "LIBKMOD_AR libkmod.a"
69 mkdir -p -- $fake_root$e_libdir
70
71 rm -f $fake_root$e_libdir/libkmod.a
72
73 $libkmod_ar $fake_root$e_libdir/libkmod.a \
74 $libkmod_o_files
75 sep_end
76 ################################################################################
77 fi
78
79 sep_start;echo 'libkmod:fake installing headers'
80 mkdir -p -- $fake_root$e_includedir
81 cp -f $src_path/src/libkmod.h $fake_root$e_includedir
82 sep_end
File src/config.h added (mode: 100644) (index 0000000..590b7c7)
1 /* Debug messages. */
2 /* #undef ENABLE_DEBUG */
3
4 /* Experimental features. */
5 /* #undef ENABLE_EXPERIMENTAL */
6
7 /* System logging. */
8 #define ENABLE_LOGGING 1
9
10 /* Enable Xz for modules. */
11 /* #undef ENABLE_XZ */
12
13 /* Enable zlib for modules. */
14 /* #undef ENABLE_ZLIB */
15
16 /* Features in this build */
17 #define KMOD_FEATURES "-XZ -ZLIB -EXPERIMENTAL"
18
19 /* Version number of package */
20 #define VERSION "24"
File src/libkmod-config.c added (mode: 100644) (index 0000000..d4f53d6)
1 /*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
5 * Copyright (C) 2013 Intel Corporation. All rights reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <ctype.h>
22 #include <dirent.h>
23 #include <errno.h>
24 #include <stdarg.h>
25 #include <stddef.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <inttypes.h>
31 #include <limits.h>
32 #include <stdbool.h>
33 #include <syslog.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36
37 #include <libgen.h>
38
39 #include "config.h"
40
41 #include "libkmod.h"
42 #include "libkmod-namespace.h"
43 #include "libkmod-paths.h"
44 #include "shared/macro.h"
45 #include "shared/util.h"
46 #define LIBKMOD_CONFIG_C
47 #include "libkmod-internal.h"
48 #undef LIBKMOD_CONFIG_C
49
50 struct kmod_alias {
51 char *name;
52 char modname[];
53 };
54
55 struct kmod_options {
56 char *options;
57 char modname[];
58 };
59
60 struct kmod_command {
61 char *command;
62 char modname[];
63 };
64
65 struct kmod_softdep {
66 char *name;
67 const char **pre;
68 const char **post;
69 unsigned int n_pre;
70 unsigned int n_post;
71 };
72
73 const char *kmod_blacklist_get_modname(const struct kmod_list *l)
74 {
75 return l->data;
76 }
77
78 const char *kmod_alias_get_name(const struct kmod_list *l) {
79 const struct kmod_alias *alias = l->data;
80 return alias->name;
81 }
82
83 const char *kmod_alias_get_modname(const struct kmod_list *l) {
84 const struct kmod_alias *alias = l->data;
85 return alias->modname;
86 }
87
88 const char *kmod_option_get_options(const struct kmod_list *l) {
89 const struct kmod_options *alias = l->data;
90 return alias->options;
91 }
92
93 const char *kmod_option_get_modname(const struct kmod_list *l) {
94 const struct kmod_options *alias = l->data;
95 return alias->modname;
96 }
97
98 const char *kmod_command_get_command(const struct kmod_list *l) {
99 const struct kmod_command *alias = l->data;
100 return alias->command;
101 }
102
103 const char *kmod_command_get_modname(const struct kmod_list *l) {
104 const struct kmod_command *alias = l->data;
105 return alias->modname;
106 }
107
108 const char *kmod_softdep_get_name(const struct kmod_list *l) {
109 const struct kmod_softdep *dep = l->data;
110 return dep->name;
111 }
112
113 const char * const *kmod_softdep_get_pre(const struct kmod_list *l, unsigned int *count) {
114 const struct kmod_softdep *dep = l->data;
115 *count = dep->n_pre;
116 return dep->pre;
117 }
118
119 const char * const *kmod_softdep_get_post(const struct kmod_list *l, unsigned int *count) {
120 const struct kmod_softdep *dep = l->data;
121 *count = dep->n_post;
122 return dep->post;
123 }
124
125 static int kmod_config_add_command(struct kmod_config *config,
126 const char *modname,
127 const char *command,
128 const char *command_name,
129 struct kmod_list **list)
130 {
131 struct kmod_command *cmd = NULL;
132 struct kmod_list *l;
133 size_t modnamelen = strlen(modname) + 1;
134 size_t commandlen = strlen(command) + 1;
135
136 DBG(config->ctx, "modname='%s' cmd='%s %s'\n", modname, command_name,
137 command);
138
139 cmd = malloc(sizeof(*cmd) + modnamelen + commandlen);
140 if (!cmd)
141 return -ENOMEM;
142
143 cmd->command = sizeof(*cmd) + modnamelen + (char *)cmd;
144 memcpy(cmd->modname, modname, modnamelen);
145 memcpy(cmd->command, command, commandlen);
146
147 l = __kmod_list_append(*list, cmd);
148 if (!l) {
149 if (cmd)
150 free(cmd);
151 return -ENOMEM;
152 }
153
154 *list = l;
155 return 0;
156 }
157
158 static void kmod_config_free_command(struct kmod_config *config,
159 struct kmod_list *l,
160 struct kmod_list **list)
161 {
162 struct kmod_command *cmd = l->data;
163
164 free(cmd);
165 *list = __kmod_list_remove(l);
166 }
167
168 static int kmod_config_add_options(struct kmod_config *config,
169 const char *modname, const char *options)
170 {
171 struct kmod_options *opt = NULL;
172 struct kmod_list *list;
173 size_t modnamelen = strlen(modname) + 1;
174 size_t optionslen = strlen(options) + 1;
175
176 DBG(config->ctx, "modname='%s' options='%s'\n", modname, options);
177
178 opt = malloc(sizeof(*opt) + modnamelen + optionslen);
179 if (!opt)
180 return -ENOMEM;
181
182 opt->options = sizeof(*opt) + modnamelen + (char *)opt;
183
184 memcpy(opt->modname, modname, modnamelen);
185 memcpy(opt->options, options, optionslen);
186 strchr_replace(opt->options, '\t', ' ');
187
188 list = __kmod_list_append(config->options, opt);
189 if (!list)
190 return -ENOMEM;
191
192 opt = NULL;
193 config->options = list;
194 return 0;
195 }
196
197 static void kmod_config_free_options(struct kmod_config *config,
198 struct kmod_list *l)
199 {
200 struct kmod_options *opt = l->data;
201
202 free(opt);
203
204 config->options = __kmod_list_remove(l);
205 }
206
207 static int kmod_config_add_alias(struct kmod_config *config,
208 const char *name, const char *modname)
209 {
210 struct kmod_alias *alias;
211 struct kmod_list *list;
212 size_t namelen = strlen(name) + 1, modnamelen = strlen(modname) + 1;
213
214 DBG(config->ctx, "name=%s modname=%s\n", name, modname);
215
216 alias = malloc(sizeof(*alias) + namelen + modnamelen);
217 if (!alias)
218 return -ENOMEM;
219
220 alias->name = sizeof(*alias) + modnamelen + (char *)alias;
221
222 memcpy(alias->modname, modname, modnamelen);
223 memcpy(alias->name, name, namelen);
224
225 list = __kmod_list_append(config->aliases, alias);
226 if (!list) {
227 if (alias)
228 free(alias);
229 return -ENOMEM;
230 }
231
232 config->aliases = list;
233 return 0;
234 }
235
236 static void kmod_config_free_alias(struct kmod_config *config,
237 struct kmod_list *l)
238 {
239 struct kmod_alias *alias = l->data;
240
241 free(alias);
242
243 config->aliases = __kmod_list_remove(l);
244 }
245
246 static int kmod_config_add_blacklist(struct kmod_config *config,
247 const char *modname)
248 {
249 char *p = NULL;
250 struct kmod_list *list;
251
252 DBG(config->ctx, "modname=%s\n", modname);
253
254 p = strdup(modname);
255 if (!p)
256 return -ENOMEM;
257
258 list = __kmod_list_append(config->blacklists, p);
259 if (!list) {
260 if (p)
261 free(p);
262 return -ENOMEM;
263 }
264
265 config->blacklists = list;
266 return 0;
267 }
268
269 static void kmod_config_free_blacklist(struct kmod_config *config,
270 struct kmod_list *l)
271 {
272 free(l->data);
273 config->blacklists = __kmod_list_remove(l);
274 }
275
276 static int kmod_config_add_softdep(struct kmod_config *config,
277 const char *modname,
278 const char *line)
279 {
280 struct kmod_list *list;
281 struct kmod_softdep *dep;
282 const char *s, *p;
283 char *itr;
284 unsigned int n_pre = 0, n_post = 0;
285 size_t modnamelen = strlen(modname) + 1;
286 size_t buflen = 0;
287 bool was_space = false;
288 enum { S_NONE, S_PRE, S_POST } mode = S_NONE;
289
290 DBG(config->ctx, "modname=%s\n", modname);
291
292 /* analyze and count */
293 for (p = s = line; ; s++) {
294 size_t plen;
295
296 if (*s != '\0') {
297 if (!isspace(*s)) {
298 was_space = false;
299 continue;
300 }
301
302 if (was_space) {
303 p = s + 1;
304 continue;
305 }
306 was_space = true;
307
308 if (p >= s)
309 continue;
310 }
311 plen = s - p;
312
313 if (plen == sizeof("pre:") - 1 &&
314 memcmp(p, "pre:", sizeof("pre:") - 1) == 0)
315 mode = S_PRE;
316 else if (plen == sizeof("post:") - 1 &&
317 memcmp(p, "post:", sizeof("post:") - 1) == 0)
318 mode = S_POST;
319 else if (*s != '\0' || (*s == '\0' && !was_space)) {
320 if (mode == S_PRE) {
321 buflen += plen + 1;
322 n_pre++;
323 } else if (mode == S_POST) {
324 buflen += plen + 1;
325 n_post++;
326 }
327 }
328 p = s + 1;
329 if (*s == '\0')
330 break;
331 }
332
333 DBG(config->ctx, "%u pre, %u post\n", n_pre, n_post);
334
335 dep = malloc(sizeof(struct kmod_softdep) + modnamelen +
336 n_pre * sizeof(const char *) +
337 n_post * sizeof(const char *) +
338 buflen);
339 if (dep == NULL) {
340 ERR(config->ctx, "out-of-memory modname=%s\n", modname);
341 return -ENOMEM;
342 }
343 dep->n_pre = n_pre;
344 dep->n_post = n_post;
345 dep->pre = (const char **)((char *)dep + sizeof(struct kmod_softdep));
346 dep->post = dep->pre + n_pre;
347 dep->name = (char *)(dep->post + n_post);
348
349 memcpy(dep->name, modname, modnamelen);
350
351 /* copy strings */
352 itr = dep->name + modnamelen;
353 n_pre = 0;
354 n_post = 0;
355 mode = S_NONE;
356 for (p = s = line; ; s++) {
357 size_t plen;
358
359 if (*s != '\0') {
360 if (!isspace(*s)) {
361 was_space = false;
362 continue;
363 }
364
365 if (was_space) {
366 p = s + 1;
367 continue;
368 }
369 was_space = true;
370
371 if (p >= s)
372 continue;
373 }
374 plen = s - p;
375
376 if (plen == sizeof("pre:") - 1 &&
377 memcmp(p, "pre:", sizeof("pre:") - 1) == 0)
378 mode = S_PRE;
379 else if (plen == sizeof("post:") - 1 &&
380 memcmp(p, "post:", sizeof("post:") - 1) == 0)
381 mode = S_POST;
382 else if (*s != '\0' || (*s == '\0' && !was_space)) {
383 if (mode == S_PRE) {
384 dep->pre[n_pre] = itr;
385 memcpy(itr, p, plen);
386 itr[plen] = '\0';
387 itr += plen + 1;
388 n_pre++;
389 } else if (mode == S_POST) {
390 dep->post[n_post] = itr;
391 memcpy(itr, p, plen);
392 itr[plen] = '\0';
393 itr += plen + 1;
394 n_post++;
395 }
396 }
397 p = s + 1;
398 if (*s == '\0')
399 break;
400 }
401
402 list = __kmod_list_append(config->softdeps, dep);
403 if (list == NULL) {
404 free(dep);
405 return -ENOMEM;
406 }
407 config->softdeps = list;
408
409 return 0;
410 }
411
412 static char *softdep_to_char(struct kmod_softdep *dep) {
413 const size_t sz_preprefix = sizeof("pre: ") - 1;
414 const size_t sz_postprefix = sizeof("post: ") - 1;
415 size_t sz = 1; /* at least '\0' */
416 size_t sz_pre, sz_post;
417 const char *start, *end;
418 char *s, *itr;
419
420 /*
421 * Rely on the fact that dep->pre[] and dep->post[] are strv's that
422 * point to a contiguous buffer
423 */
424 if (dep->n_pre > 0) {
425 start = dep->pre[0];
426 end = dep->pre[dep->n_pre - 1]
427 + strlen(dep->pre[dep->n_pre - 1]);
428 sz_pre = end - start;
429 sz += sz_pre + sz_preprefix;
430 } else
431 sz_pre = 0;
432
433 if (dep->n_post > 0) {
434 start = dep->post[0];
435 end = dep->post[dep->n_post - 1]
436 + strlen(dep->post[dep->n_post - 1]);
437 sz_post = end - start;
438 sz += sz_post + sz_postprefix;
439 } else
440 sz_post = 0;
441
442 itr = s = malloc(sz);
443 if (s == NULL)
444 return NULL;
445
446 if (sz_pre) {
447 char *p;
448
449 memcpy(itr, "pre: ", sz_preprefix);
450 itr += sz_preprefix;
451
452 /* include last '\0' */
453 memcpy(itr, dep->pre[0], sz_pre + 1);
454 for (p = itr; p < itr + sz_pre; p++) {
455 if (*p == '\0')
456 *p = ' ';
457 }
458 itr = p;
459 }
460
461 if (sz_post) {
462 char *p;
463
464 memcpy(itr, "post: ", sz_postprefix);
465 itr += sz_postprefix;
466
467 /* include last '\0' */
468 memcpy(itr, dep->post[0], sz_post + 1);
469 for (p = itr; p < itr + sz_post; p++) {
470 if (*p == '\0')
471 *p = ' ';
472 }
473 itr = p;
474 }
475
476 *itr = '\0';
477
478 return s;
479 }
480
481 static void kmod_config_free_softdep(struct kmod_config *config,
482 struct kmod_list *l)
483 {
484 free(l->data);
485 config->softdeps = __kmod_list_remove(l);
486 }
487
488 static void kcmdline_parse_result(struct kmod_config *config, char *modname,
489 char *param, char *value)
490 {
491 if (modname == NULL || param == NULL)
492 return;
493
494 DBG(config->ctx, "%s %s\n", modname, param);
495
496 if (streq(modname, "modprobe") && !strncmp(param, "blacklist=", 10)) {
497 for (;;) {
498 char *t = strsep(&value, ",");
499 if (t == NULL)
500 break;
501
502 kmod_config_add_blacklist(config, t);
503 }
504 } else {
505 if (underscores(modname) < 0) {
506 ERR(config->ctx, "Ignoring bad option on kernel command line while parsing module name: '%s'\n",
507 modname);
508 }
509 kmod_config_add_options(config, modname, param);
510 }
511 }
512
513 static int kmod_config_parse_kcmdline(struct kmod_config *config)
514 {
515 char buf[KCMD_LINE_SIZE];
516 int fd, err;
517 char *p, *modname, *param = NULL, *value = NULL;
518 bool is_quoted = false, is_module = true;
519
520 fd = open("/proc/cmdline", O_RDONLY|O_CLOEXEC);
521 if (fd < 0) {
522 err = -errno;
523 DBG(config->ctx, "could not open '/proc/cmdline' for reading: %m\n");
524 return err;
525 }
526
527 err = read_str_safe(fd, buf, sizeof(buf));
528 close(fd);
529 if (err < 0) {
530 ERR(config->ctx, "could not read from '/proc/cmdline': %s\n",
531 strerror(-err));
532 return err;
533 }
534
535 for (p = buf, modname = buf; *p != '\0' && *p != '\n'; p++) {
536 if (*p == '"') {
537 is_quoted = !is_quoted;
538
539 if (is_quoted) {
540 /* don't consider a module until closing quotes */
541 is_module = false;
542 } else if (param != NULL && value != NULL) {
543 /*
544 * If we are indeed expecting a value and
545 * closing quotes, then this can be considered
546 * a valid option for a module
547 */
548 is_module = true;
549 }
550
551 continue;
552 }
553 if (is_quoted)
554 continue;
555
556 switch (*p) {
557 case ' ':
558 *p = '\0';
559 if (is_module)
560 kcmdline_parse_result(config, modname, param, value);
561 param = value = NULL;
562 modname = p + 1;
563 is_module = true;
564 break;
565 case '.':
566 if (param == NULL) {
567 *p = '\0';
568 param = p + 1;
569 }
570 break;
571 case '=':
572 if (param != NULL)
573 value = p + 1;
574 else
575 is_module = false;
576 break;
577 }
578 }
579
580 *p = '\0';
581 if (is_module)
582 kcmdline_parse_result(config, modname, param, value);
583
584 return 0;
585 }
586
587 /*
588 * Take an fd and own it. It will be closed on return. filename is used only
589 * for debug messages
590 */
591 static int kmod_config_parse(struct kmod_config *config, int fd,
592 const char *filename)
593 {
594 struct kmod_ctx *ctx = config->ctx;
595 char *line;
596 FILE *fp;
597 unsigned int linenum = 0;
598 int err;
599
600 fp = fdopen(fd, "r");
601 if (fp == NULL) {
602 err = -errno;
603 ERR(config->ctx, "fd %d: %m\n", fd);
604 close(fd);
605 return err;
606 }
607
608 while ((line = freadline_wrapped(fp, &linenum)) != NULL) {
609 char *cmd, *saveptr;
610
611 if (line[0] == '\0' || line[0] == '#')
612 goto done_next;
613
614 cmd = strtok_r(line, "\t ", &saveptr);
615 if (cmd == NULL)
616 goto done_next;
617
618 if (streq(cmd, "alias")) {
619 char *alias = strtok_r(NULL, "\t ", &saveptr);
620 char *modname = strtok_r(NULL, "\t ", &saveptr);
621
622 if (underscores(alias) < 0 || underscores(modname) < 0)
623 goto syntax_error;
624
625 kmod_config_add_alias(config, alias, modname);
626 } else if (streq(cmd, "blacklist")) {
627 char *modname = strtok_r(NULL, "\t ", &saveptr);
628
629 if (underscores(modname) < 0)
630 goto syntax_error;
631
632 kmod_config_add_blacklist(config, modname);
633 } else if (streq(cmd, "options")) {
634 char *modname = strtok_r(NULL, "\t ", &saveptr);
635 char *options = strtok_r(NULL, "\0", &saveptr);
636
637 if (underscores(modname) < 0 || options == NULL)
638 goto syntax_error;
639
640 kmod_config_add_options(config, modname, options);
641 } else if (streq(cmd, "install")) {
642 char *modname = strtok_r(NULL, "\t ", &saveptr);
643 char *installcmd = strtok_r(NULL, "\0", &saveptr);
644
645 if (underscores(modname) < 0 || installcmd == NULL)
646 goto syntax_error;
647
648 kmod_config_add_command(config, modname, installcmd,
649 cmd, &config->install_commands);
650 } else if (streq(cmd, "remove")) {
651 char *modname = strtok_r(NULL, "\t ", &saveptr);
652 char *removecmd = strtok_r(NULL, "\0", &saveptr);
653
654 if (underscores(modname) < 0 || removecmd == NULL)
655 goto syntax_error;
656
657 kmod_config_add_command(config, modname, removecmd,
658 cmd, &config->remove_commands);
659 } else if (streq(cmd, "softdep")) {
660 char *modname = strtok_r(NULL, "\t ", &saveptr);
661 char *softdeps = strtok_r(NULL, "\0", &saveptr);
662
663 if (underscores(modname) < 0 || softdeps == NULL)
664 goto syntax_error;
665
666 kmod_config_add_softdep(config, modname, softdeps);
667 } else if (streq(cmd, "include")
668 || streq(cmd, "config")) {
669 ERR(ctx, "%s: command %s is deprecated and not parsed anymore\n",
670 filename, cmd);
671 } else {
672 syntax_error:
673 ERR(ctx, "%s line %u: ignoring bad line starting with '%s'\n",
674 filename, linenum, cmd);
675 }
676
677 done_next:
678 free(line);
679 }
680
681 fclose(fp);
682
683 return 0;
684 }
685
686 void kmod_config_free(struct kmod_config *config)
687 {
688 while (config->aliases)
689 kmod_config_free_alias(config, config->aliases);
690
691 while (config->blacklists)
692 kmod_config_free_blacklist(config, config->blacklists);
693
694 while (config->options)
695 kmod_config_free_options(config, config->options);
696
697 while (config->install_commands) {
698 kmod_config_free_command(config, config->install_commands,
699 &config->install_commands);
700 }
701
702 while (config->remove_commands) {
703 kmod_config_free_command(config, config->remove_commands,
704 &config->remove_commands);
705 }
706
707 while (config->softdeps)
708 kmod_config_free_softdep(config, config->softdeps);
709
710 for (; config->paths != NULL;
711 config->paths = __kmod_list_remove(config->paths))
712 free(config->paths->data);
713
714 free(config);
715 }
716
717 static bool conf_files_filter_out(struct kmod_ctx *ctx, DIR *d,
718 const char *path, const char *fn)
719 {
720 size_t len = strlen(fn);
721 struct stat st;
722
723 if (fn[0] == '.')
724 return true;
725
726 if (len < 6 || (!streq(&fn[len - 5], ".conf")
727 && !streq(&fn[len - 6], ".alias")))
728 return true;
729
730 fstatat(dirfd(d), fn, &st, 0);
731
732 if (S_ISDIR(st.st_mode)) {
733 ERR(ctx, "Directories inside directories are not supported: "
734 "%s/%s\n", path, fn);
735 return true;
736 }
737
738 return false;
739 }
740
741 struct conf_file {
742 const char *path;
743 bool is_single;
744 char name[];
745 };
746
747 static int conf_files_insert_sorted(struct kmod_ctx *ctx,
748 struct kmod_list **list,
749 const char *path, const char *name)
750 {
751 struct kmod_list *lpos, *tmp;
752 struct conf_file *cf;
753 size_t namelen;
754 int cmp = -1;
755 bool is_single = false;
756 char *path_cpy=strdup(path);
757
758 if (!path_cpy)
759 return -ENOMEM;
760
761 if (name == NULL) {
762 name = basename(path_cpy);
763 is_single = true;
764 }
765
766 kmod_list_foreach(lpos, *list) {
767 cf = lpos->data;
768
769 if ((cmp = strcmp(name, cf->name)) <= 0)
770 break;
771 }
772
773 if (cmp == 0) {
774 DBG(ctx, "Ignoring duplicate config file: %s/%s\n", path,
775 name);
776 free(path_cpy);
777 return -EEXIST;
778 }
779
780 namelen = strlen(name);
781 cf = malloc(sizeof(*cf) + namelen + 1);
782 if (cf == NULL) {
783 free(path_cpy);
784 return -ENOMEM;
785 }
786
787 memcpy(cf->name, name, namelen + 1);
788 cf->path = path;
789 cf->is_single = is_single;
790
791 if (lpos == NULL)
792 tmp = __kmod_list_append(*list, cf);
793 else if (lpos == *list)
794 tmp = kmod_list_prepend(*list, cf);
795 else
796 tmp = kmod_list_insert_before(lpos, cf);
797
798 if (tmp == NULL) {
799 free(cf);
800 free(path_cpy);
801 return -ENOMEM;
802 }
803
804 if (lpos == NULL || lpos == *list)
805 *list = tmp;
806 free(path_cpy);
807 return 0;
808 }
809
810 /*
811 * Insert configuration files in @list, ignoring duplicates
812 */
813 static int conf_files_list(struct kmod_ctx *ctx, struct kmod_list **list,
814 const char *path,
815 unsigned long long *path_stamp)
816 {
817 DIR *d;
818 int err;
819 struct stat st;
820 struct dirent *dent;
821
822 if (stat(path, &st) != 0) {
823 err = -errno;
824 DBG(ctx, "could not stat '%s': %m\n", path);
825 return err;
826 }
827
828 *path_stamp = stat_mstamp(&st);
829
830 if (!S_ISDIR(st.st_mode)) {
831 conf_files_insert_sorted(ctx, list, path, NULL);
832 return 0;
833 }
834
835 d = opendir(path);
836 if (d == NULL) {
837 ERR(ctx, "opendir(%s): %m\n", path);
838 return -EINVAL;
839 }
840
841 for (dent = readdir(d); dent != NULL; dent = readdir(d)) {
842 if (conf_files_filter_out(ctx, d, path, dent->d_name))
843 continue;
844
845 conf_files_insert_sorted(ctx, list, path, dent->d_name);
846 }
847
848 closedir(d);
849 return 0;
850 }
851
852 int kmod_config_new(struct kmod_ctx *ctx, struct kmod_config **p_config,
853 const char * const *config_paths)
854 {
855 struct kmod_config *config;
856 struct kmod_list *list = NULL;
857 struct kmod_list *path_list = NULL;
858 size_t i;
859
860 conf_files_insert_sorted(ctx, &list, kmod_get_dirname(ctx), "modules.softdep");
861
862 for (i = 0; config_paths[i] != NULL; i++) {
863 const char *path = config_paths[i];
864 unsigned long long path_stamp = 0;
865 size_t pathlen;
866 struct kmod_list *tmp;
867 struct kmod_config_path *cf;
868
869 if (conf_files_list(ctx, &list, path, &path_stamp) < 0)
870 continue;
871
872 pathlen = strlen(path) + 1;
873 cf = malloc(sizeof(*cf) + pathlen);
874 if (cf == NULL)
875 goto oom;
876
877 cf->stamp = path_stamp;
878 memcpy(cf->path, path, pathlen);
879
880 tmp = __kmod_list_append(path_list, cf);
881 if (tmp == NULL)
882 goto oom;
883 path_list = tmp;
884 }
885
886 *p_config = config = calloc(1, sizeof(struct kmod_config));
887 if (config == NULL)
888 goto oom;
889
890 config->paths = path_list;
891 config->ctx = ctx;
892
893 for (; list != NULL; list = __kmod_list_remove(list)) {
894 char buf[PATH_MAX];
895 const char *fn = buf;
896 struct conf_file *cf = list->data;
897 int fd;
898
899 if (cf->is_single) {
900 fn = cf->path;
901 } else if (snprintf(buf, sizeof(buf), "%s/%s",
902 cf->path, cf->name) >= (int)sizeof(buf)) {
903 ERR(ctx, "Error parsing %s/%s: path too long\n",
904 cf->path, cf->name);
905 free(cf);
906 continue;
907 }
908
909 fd = open(fn, O_RDONLY|O_CLOEXEC);
910 DBG(ctx, "parsing file '%s' fd=%d\n", fn, fd);
911
912 if (fd >= 0)
913 kmod_config_parse(config, fd, fn);
914
915 free(cf);
916 }
917
918 kmod_config_parse_kcmdline(config);
919
920 return 0;
921
922 oom:
923 for (; list != NULL; list = __kmod_list_remove(list))
924 free(list->data);
925
926 for (; path_list != NULL; path_list = __kmod_list_remove(path_list))
927 free(path_list->data);
928
929 return -ENOMEM;
930 }
931
932 /**********************************************************************
933 * struct kmod_config_iter functions
934 **********************************************************************/
935
936 enum config_type {
937 CONFIG_TYPE_BLACKLIST = 0,
938 CONFIG_TYPE_INSTALL,
939 CONFIG_TYPE_REMOVE,
940 CONFIG_TYPE_ALIAS,
941 CONFIG_TYPE_OPTION,
942 CONFIG_TYPE_SOFTDEP,
943 };
944
945 struct kmod_config_iter {
946 enum config_type type;
947 bool intermediate;
948 const struct kmod_list *list;
949 const struct kmod_list *curr;
950 void *data;
951 const char *(*get_key)(const struct kmod_list *l);
952 const char *(*get_value)(const struct kmod_list *l);
953 };
954
955 static const char *softdep_get_plain_softdep(const struct kmod_list *l)
956 {
957 char *s = softdep_to_char(l->data);
958 return s;
959 }
960
961 static struct kmod_config_iter *kmod_config_iter_new(const struct kmod_ctx* ctx,
962 enum config_type type)
963 {
964 struct kmod_config_iter *iter = calloc(1, sizeof(*iter));
965 const struct kmod_config *config = kmod_get_config(ctx);
966
967 if (iter == NULL)
968 return NULL;
969
970 iter->type = type;
971
972 switch (type) {
973 case CONFIG_TYPE_BLACKLIST:
974 iter->list = config->blacklists;
975 iter->get_key = kmod_blacklist_get_modname;
976 break;
977 case CONFIG_TYPE_INSTALL:
978 iter->list = config->install_commands;
979 iter->get_key = kmod_command_get_modname;
980 iter->get_value = kmod_command_get_command;
981 break;
982 case CONFIG_TYPE_REMOVE:
983 iter->list = config->remove_commands;
984 iter->get_key = kmod_command_get_modname;
985 iter->get_value = kmod_command_get_command;
986 break;
987 case CONFIG_TYPE_ALIAS:
988 iter->list = config->aliases;
989 iter->get_key = kmod_alias_get_name;
990 iter->get_value = kmod_alias_get_modname;
991 break;
992 case CONFIG_TYPE_OPTION:
993 iter->list = config->options;
994 iter->get_key = kmod_option_get_modname;
995 iter->get_value = kmod_option_get_options;
996 break;
997 case CONFIG_TYPE_SOFTDEP:
998 iter->list = config->softdeps;
999 iter->get_key = kmod_softdep_get_name;
1000 iter->get_value = softdep_get_plain_softdep;
1001 iter->intermediate = true;
1002 break;
1003 }
1004
1005 return iter;
1006 }
1007
1008 /**
1009 * SECTION:libkmod-config
1010 * @short_description: retrieve current libkmod configuration
1011 */
1012
1013 /**
1014 * kmod_config_get_blacklists:
1015 * @ctx: kmod library context
1016 *
1017 * Retrieve an iterator to deal with the blacklist maintained inside the
1018 * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and
1019 * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must
1020 * be made to initialize the iterator and check if it's valid.
1021 *
1022 * Returns: a new iterator over the blacklists or NULL on failure. Free it
1023 * with kmod_config_iter_free_iter().
1024 */
1025 struct kmod_config_iter *kmod_config_get_blacklists(const struct kmod_ctx *ctx)
1026 {
1027 if (ctx == NULL)
1028 return NULL;;
1029
1030 return kmod_config_iter_new(ctx, CONFIG_TYPE_BLACKLIST);
1031 }
1032
1033 /**
1034 * kmod_config_get_install_commands:
1035 * @ctx: kmod library context
1036 *
1037 * Retrieve an iterator to deal with the install commands maintained inside the
1038 * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and
1039 * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must
1040 * be made to initialize the iterator and check if it's valid.
1041 *
1042 * Returns: a new iterator over the install commands or NULL on failure. Free
1043 * it with kmod_config_iter_free_iter().
1044 */
1045 struct kmod_config_iter *kmod_config_get_install_commands(const struct kmod_ctx *ctx)
1046 {
1047 if (ctx == NULL)
1048 return NULL;;
1049
1050 return kmod_config_iter_new(ctx, CONFIG_TYPE_INSTALL);
1051 }
1052
1053 /**
1054 * kmod_config_get_remove_commands:
1055 * @ctx: kmod library context
1056 *
1057 * Retrieve an iterator to deal with the remove commands maintained inside the
1058 * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and
1059 * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must
1060 * be made to initialize the iterator and check if it's valid.
1061 *
1062 * Returns: a new iterator over the remove commands or NULL on failure. Free
1063 * it with kmod_config_iter_free_iter().
1064 */
1065 struct kmod_config_iter *kmod_config_get_remove_commands(const struct kmod_ctx *ctx)
1066 {
1067 if (ctx == NULL)
1068 return NULL;;
1069
1070 return kmod_config_iter_new(ctx, CONFIG_TYPE_REMOVE);
1071 }
1072
1073 /**
1074 * kmod_config_get_aliases:
1075 * @ctx: kmod library context
1076 *
1077 * Retrieve an iterator to deal with the aliases maintained inside the
1078 * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and
1079 * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must
1080 * be made to initialize the iterator and check if it's valid.
1081 *
1082 * Returns: a new iterator over the aliases or NULL on failure. Free it with
1083 * kmod_config_iter_free_iter().
1084 */
1085 struct kmod_config_iter *kmod_config_get_aliases(const struct kmod_ctx *ctx)
1086 {
1087 if (ctx == NULL)
1088 return NULL;;
1089
1090 return kmod_config_iter_new(ctx, CONFIG_TYPE_ALIAS);
1091 }
1092
1093 /**
1094 * kmod_config_get_options:
1095 * @ctx: kmod library context
1096 *
1097 * Retrieve an iterator to deal with the options maintained inside the
1098 * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and
1099 * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must
1100 * be made to initialize the iterator and check if it's valid.
1101 *
1102 * Returns: a new iterator over the options or NULL on failure. Free it with
1103 * kmod_config_iter_free_iter().
1104 */
1105 struct kmod_config_iter *kmod_config_get_options(const struct kmod_ctx *ctx)
1106 {
1107 if (ctx == NULL)
1108 return NULL;;
1109
1110 return kmod_config_iter_new(ctx, CONFIG_TYPE_OPTION);
1111 }
1112
1113 /**
1114 * kmod_config_get_softdeps:
1115 * @ctx: kmod library context
1116 *
1117 * Retrieve an iterator to deal with the softdeps maintained inside the
1118 * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and
1119 * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must
1120 * be made to initialize the iterator and check if it's valid.
1121 *
1122 * Returns: a new iterator over the softdeps or NULL on failure. Free it with
1123 * kmod_config_iter_free_iter().
1124 */
1125 struct kmod_config_iter *kmod_config_get_softdeps(const struct kmod_ctx *ctx)
1126 {
1127 if (ctx == NULL)
1128 return NULL;;
1129
1130 return kmod_config_iter_new(ctx, CONFIG_TYPE_SOFTDEP);
1131 }
1132
1133 /**
1134 * kmod_config_iter_get_key:
1135 * @iter: iterator over a certain configuration
1136 *
1137 * When using a new allocated iterator, user must perform a call to
1138 * kmod_config_iter_next() to initialize iterator's position and check if it's
1139 * valid.
1140 *
1141 * Returns: the key of the current configuration pointed by @iter.
1142 */
1143 const char *kmod_config_iter_get_key(const struct kmod_config_iter *iter)
1144 {
1145 if (iter == NULL || iter->curr == NULL)
1146 return NULL;
1147
1148 return iter->get_key(iter->curr);
1149 }
1150
1151 /**
1152 * kmod_config_iter_get_value:
1153 * @iter: iterator over a certain configuration
1154 *
1155 * When using a new allocated iterator, user must perform a call to
1156 * kmod_config_iter_next() to initialize iterator's position and check if it's
1157 * valid.
1158 *
1159 * Returns: the value of the current configuration pointed by @iter.
1160 */
1161 const char *kmod_config_iter_get_value(const struct kmod_config_iter *iter)
1162 {
1163 const char *s;
1164
1165 if (iter == NULL || iter->curr == NULL)
1166 return NULL;
1167
1168 if (iter->get_value == NULL)
1169 return NULL;
1170
1171 if (iter->intermediate) {
1172 struct kmod_config_iter *i = (struct kmod_config_iter *)iter;
1173
1174 free(i->data);
1175 s = i->data = (void *) iter->get_value(iter->curr);
1176 } else
1177 s = iter->get_value(iter->curr);
1178
1179 return s;
1180 }
1181
1182 /**
1183 * kmod_config_iter_next:
1184 * @iter: iterator over a certain configuration
1185 *
1186 * Make @iter point to the next item of a certain configuration. It's an
1187 * automatically recycling iterator. When it reaches the end, false is
1188 * returned; then if user wants to iterate again, it's sufficient to call this
1189 * function once more.
1190 *
1191 * Returns: true if next position of @iter is valid or false if its end is
1192 * reached.
1193 */
1194 bool kmod_config_iter_next(struct kmod_config_iter *iter)
1195 {
1196 if (iter == NULL)
1197 return false;
1198
1199 if (iter->curr == NULL) {
1200 iter->curr = iter->list;
1201 return iter->curr != NULL;
1202 }
1203
1204 iter->curr = kmod_list_next(iter->list, iter->curr);
1205
1206 return iter->curr != NULL;
1207 }
1208
1209 /**
1210 * kmod_config_iter_free_iter:
1211 * @iter: iterator over a certain configuration
1212 *
1213 * Free resources used by the iterator.
1214 */
1215 void kmod_config_iter_free_iter(struct kmod_config_iter *iter)
1216 {
1217 free(iter->data);
1218 free(iter);
1219 }
File src/libkmod-elf.c added (mode: 100644) (index 0000000..5aec464)
1 /*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <assert.h>
21 #include <elf.h>
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <limits.h>
26 #include <stddef.h>
27 #include <stdio.h>
28
29 #include "config.h"
30
31 #include "libkmod.h"
32 #include "libkmod-namespace.h"
33 #include "libkmod-paths.h"
34 #include "shared/macro.h"
35 #include "shared/util.h"
36 #define LIBKMOD_ELF_C
37 #include "libkmod-internal.h"
38 #undef LIBKMOD_ELF_C
39
40 enum kmod_elf_class {
41 KMOD_ELF_32 = (1 << 1),
42 KMOD_ELF_64 = (1 << 2),
43 KMOD_ELF_LSB = (1 << 3),
44 KMOD_ELF_MSB = (1 << 4)
45 };
46
47 /* as defined in module-init-tools */
48 struct kmod_modversion32 {
49 uint32_t crc;
50 char name[64 - sizeof(uint32_t)];
51 };
52
53 struct kmod_modversion64 {
54 uint64_t crc;
55 char name[64 - sizeof(uint64_t)];
56 };
57
58 struct kmod_elf {
59 const uint8_t *memory;
60 uint8_t *changed;
61 uint64_t size;
62 enum kmod_elf_class class;
63 struct kmod_elf_header {
64 struct {
65 uint64_t offset;
66 uint16_t count;
67 uint16_t entry_size;
68 } section;
69 struct {
70 uint16_t section; /* index of the strings section */
71 uint64_t size;
72 uint64_t offset;
73 uint32_t nameoff; /* offset in strings itself */
74 } strings;
75 uint16_t machine;
76 } header;
77 };
78
79 //#define ENABLE_ELFDBG 1
80
81 #if defined(ENABLE_LOGGING) && defined(ENABLE_ELFDBG)
82 #define ELFDBG(elf, ...) \
83 _elf_dbg(elf, __FILE__, __LINE__, __func__, __VA_ARGS__);
84
85 static inline void _elf_dbg(const struct kmod_elf *elf, const char *fname, unsigned line, const char *func, const char *fmt, ...)
86 {
87 va_list args;
88
89 fprintf(stderr, "ELFDBG-%d%c: %s:%u %s() ",
90 (elf->class & KMOD_ELF_32) ? 32 : 64,
91 (elf->class & KMOD_ELF_MSB) ? 'M' : 'L',
92 fname, line, func);
93 va_start(args, fmt);
94 vfprintf(stderr, fmt, args);
95 va_end(args);
96 }
97 #else
98 #define ELFDBG(elf, ...)
99 #endif
100
101
102 static int elf_identify(const void *memory, uint64_t size)
103 {
104 const uint8_t *p = memory;
105 int class = 0;
106
107 if (size <= EI_NIDENT || memcmp(p, ELFMAG, SELFMAG) != 0)
108 return -ENOEXEC;
109
110 switch (p[EI_CLASS]) {
111 case ELFCLASS32:
112 if (size <= sizeof(Elf32_Ehdr))
113 return -EINVAL;
114 class |= KMOD_ELF_32;
115 break;
116 case ELFCLASS64:
117 if (size <= sizeof(Elf64_Ehdr))
118 return -EINVAL;
119 class |= KMOD_ELF_64;
120 break;
121 default:
122 return -EINVAL;
123 }
124
125 switch (p[EI_DATA]) {
126 case ELFDATA2LSB:
127 class |= KMOD_ELF_LSB;
128 break;
129 case ELFDATA2MSB:
130 class |= KMOD_ELF_MSB;
131 break;
132 default:
133 return -EINVAL;
134 }
135
136 return class;
137 }
138
139 static inline uint64_t elf_get_uint(const struct kmod_elf *elf, uint64_t offset, uint16_t size)
140 {
141 const uint8_t *p;
142 uint64_t ret = 0;
143 size_t i;
144
145 assert(size <= sizeof(uint64_t));
146 assert(offset + size <= elf->size);
147 if (offset + size > elf->size) {
148 ELFDBG(elf, "out of bounds: %"PRIu64" + %"PRIu16" = %"PRIu64"> %"PRIu64" (ELF size)\n",
149 offset, size, offset + size, elf->size);
150 return (uint64_t)-1;
151 }
152
153 p = elf->memory + offset;
154 if (elf->class & KMOD_ELF_MSB) {
155 for (i = 0; i < size; i++)
156 ret = (ret << 8) | p[i];
157 } else {
158 for (i = 1; i <= size; i++)
159 ret = (ret << 8) | p[size - i];
160 }
161
162 ELFDBG(elf, "size=%"PRIu16" offset=%"PRIu64" value=%"PRIu64"\n",
163 size, offset, ret);
164
165 return ret;
166 }
167
168 static inline int elf_set_uint(struct kmod_elf *elf, uint64_t offset, uint64_t size, uint64_t value)
169 {
170 uint8_t *p;
171 size_t i;
172
173 ELFDBG(elf, "size=%"PRIu16" offset=%"PRIu64" value=%"PRIu64" write memory=%p\n",
174 size, offset, value, elf->changed);
175
176 assert(size <= sizeof(uint64_t));
177 assert(offset + size <= elf->size);
178 if (offset + size > elf->size) {
179 ELFDBG(elf, "out of bounds: %"PRIu64" + %"PRIu16" = %"PRIu64"> %"PRIu64" (ELF size)\n",
180 offset, size, offset + size, elf->size);
181 return -1;
182 }
183
184 if (elf->changed == NULL) {
185 elf->changed = malloc(elf->size);
186 if (elf->changed == NULL)
187 return -errno;
188 memcpy(elf->changed, elf->memory, elf->size);
189 elf->memory = elf->changed;
190 ELFDBG(elf, "copied memory to allow writing.\n");
191 }
192
193 p = elf->changed + offset;
194 if (elf->class & KMOD_ELF_MSB) {
195 for (i = 1; i <= size; i++) {
196 p[size - i] = value & 0xff;
197 value = (value & 0xffffffffffffff00) >> 8;
198 }
199 } else {
200 for (i = 0; i < size; i++) {
201 p[i] = value & 0xff;
202 value = (value & 0xffffffffffffff00) >> 8;
203 }
204 }
205
206 return 0;
207 }
208
209 static inline const void *elf_get_mem(const struct kmod_elf *elf, uint64_t offset)
210 {
211 assert(offset < elf->size);
212 if (offset >= elf->size) {
213 ELFDBG(elf, "out-of-bounds: %"PRIu64" >= %"PRIu64" (ELF size)\n",
214 offset, elf->size);
215 return NULL;
216 }
217 return elf->memory + offset;
218 }
219
220 static inline const void *elf_get_section_header(const struct kmod_elf *elf, uint16_t idx)
221 {
222 assert(idx != SHN_UNDEF);
223 assert(idx < elf->header.section.count);
224 if (idx == SHN_UNDEF || idx >= elf->header.section.count) {
225 ELFDBG(elf, "invalid section number: %"PRIu16", last=%"PRIu16"\n",
226 idx, elf->header.section.count);
227 return NULL;
228 }
229 return elf_get_mem(elf, elf->header.section.offset +
230 (uint64_t)(idx * elf->header.section.entry_size));
231 }
232
233 static inline int elf_get_section_info(const struct kmod_elf *elf, uint16_t idx, uint64_t *offset, uint64_t *size, uint32_t *nameoff)
234 {
235 const uint8_t *p = elf_get_section_header(elf, idx);
236 uint64_t min_size, off = p - elf->memory;
237
238 if (p == NULL) {
239 ELFDBG(elf, "no section at %"PRIu16"\n", idx);
240 *offset = 0;
241 *size = 0;
242 *nameoff = 0;
243 return -EINVAL;
244 }
245
246 #define READV(field) \
247 elf_get_uint(elf, off + offsetof(typeof(*hdr), field), sizeof(hdr->field))
248
249 if (elf->class & KMOD_ELF_32) {
250 const Elf32_Shdr *hdr _unused_ = (const Elf32_Shdr *)p;
251 *size = READV(sh_size);
252 *offset = READV(sh_offset);
253 *nameoff = READV(sh_name);
254 } else {
255 const Elf64_Shdr *hdr _unused_ = (const Elf64_Shdr *)p;
256 *size = READV(sh_size);
257 *offset = READV(sh_offset);
258 *nameoff = READV(sh_name);
259 }
260 #undef READV
261
262 if (addu64_overflow(*offset, *size, &min_size)
263 || min_size > elf->size) {
264 ELFDBG(elf, "out-of-bounds: %"PRIu64" >= %"PRIu64" (ELF size)\n",
265 min_size, elf->size);
266 return -EINVAL;
267 }
268
269 ELFDBG(elf, "section=%"PRIu16" is: offset=%"PRIu64" size=%"PRIu64" nameoff=%"PRIu32"\n",
270 idx, *offset, *size, *nameoff);
271
272 return 0;
273 }
274
275 static const char *elf_get_strings_section(const struct kmod_elf *elf, uint64_t *size)
276 {
277 *size = elf->header.strings.size;
278 return elf_get_mem(elf, elf->header.strings.offset);
279 }
280
281 struct kmod_elf *kmod_elf_new(const void *memory, off_t size)
282 {
283 struct kmod_elf *elf;
284 uint64_t min_size;
285 size_t shdrs_size, shdr_size;
286 int class;
287
288 class = elf_identify(memory, size);
289 if (class < 0) {
290 errno = -class;
291 return NULL;
292 }
293
294 elf = malloc(sizeof(struct kmod_elf));
295 if (elf == NULL) {
296 return NULL;
297 }
298
299 elf->memory = memory;
300 elf->changed = NULL;
301 elf->size = size;
302 elf->class = class;
303
304 #define READV(field) \
305 elf_get_uint(elf, offsetof(typeof(*hdr), field), sizeof(hdr->field))
306
307 #define LOAD_HEADER \
308 elf->header.section.offset = READV(e_shoff); \
309 elf->header.section.count = READV(e_shnum); \
310 elf->header.section.entry_size = READV(e_shentsize); \
311 elf->header.strings.section = READV(e_shstrndx); \
312 elf->header.machine = READV(e_machine)
313 if (elf->class & KMOD_ELF_32) {
314 const Elf32_Ehdr *hdr _unused_ = elf_get_mem(elf, 0);
315 LOAD_HEADER;
316 shdr_size = sizeof(Elf32_Shdr);
317 } else {
318 const Elf64_Ehdr *hdr _unused_ = elf_get_mem(elf, 0);
319 LOAD_HEADER;
320 shdr_size = sizeof(Elf64_Shdr);
321 }
322 #undef LOAD_HEADER
323 #undef READV
324
325 ELFDBG(elf, "section: offset=%"PRIu64" count=%"PRIu16" entry_size=%"PRIu16" strings index=%"PRIu16"\n",
326 elf->header.section.offset,
327 elf->header.section.count,
328 elf->header.section.entry_size,
329 elf->header.strings.section);
330
331 if (elf->header.section.entry_size != shdr_size) {
332 ELFDBG(elf, "unexpected section entry size: %"PRIu16", expected %"PRIu16"\n",
333 elf->header.section.entry_size, shdr_size);
334 goto invalid;
335 }
336 shdrs_size = shdr_size * elf->header.section.count;
337 if (addu64_overflow(shdrs_size, elf->header.section.offset, &min_size)
338 || min_size > elf->size) {
339 ELFDBG(elf, "file is too short to hold sections\n");
340 goto invalid;
341 }
342
343 if (elf_get_section_info(elf, elf->header.strings.section,
344 &elf->header.strings.offset,
345 &elf->header.strings.size,
346 &elf->header.strings.nameoff) < 0) {
347 ELFDBG(elf, "could not get strings section\n");
348 goto invalid;
349 } else {
350 uint64_t slen;
351 const char *s = elf_get_strings_section(elf, &slen);
352 if (slen == 0 || s[slen - 1] != '\0') {
353 ELFDBG(elf, "strings section does not ends with \\0\n");
354 goto invalid;
355 }
356 }
357
358 return elf;
359
360 invalid:
361 free(elf);
362 errno = EINVAL;
363 return NULL;
364 }
365
366 void kmod_elf_unref(struct kmod_elf *elf)
367 {
368 free(elf->changed);
369 free(elf);
370 }
371
372 const void *kmod_elf_get_memory(const struct kmod_elf *elf)
373 {
374 return elf->memory;
375 }
376
377 static int elf_find_section(const struct kmod_elf *elf, const char *section)
378 {
379 uint64_t nameslen;
380 const char *names = elf_get_strings_section(elf, &nameslen);
381 uint16_t i;
382
383 for (i = 1; i < elf->header.section.count; i++) {
384 uint64_t off, size;
385 uint32_t nameoff;
386 const char *n;
387 int err = elf_get_section_info(elf, i, &off, &size, &nameoff);
388 if (err < 0)
389 continue;
390 if (nameoff >= nameslen)
391 continue;
392 n = names + nameoff;
393 if (!streq(section, n))
394 continue;
395
396 return i;
397 }
398
399 return -ENOENT;
400 }
401
402 int kmod_elf_get_section(const struct kmod_elf *elf, const char *section, const void **buf, uint64_t *buf_size)
403 {
404 uint64_t nameslen;
405 const char *names = elf_get_strings_section(elf, &nameslen);
406 uint16_t i;
407
408 *buf = NULL;
409 *buf_size = 0;
410
411 for (i = 1; i < elf->header.section.count; i++) {
412 uint64_t off, size;
413 uint32_t nameoff;
414 const char *n;
415 int err = elf_get_section_info(elf, i, &off, &size, &nameoff);
416 if (err < 0)
417 continue;
418 if (nameoff >= nameslen)
419 continue;
420 n = names + nameoff;
421 if (!streq(section, n))
422 continue;
423
424 *buf = elf_get_mem(elf, off);
425 *buf_size = size;
426 return 0;
427 }
428
429 return -ENOENT;
430 }
431
432 /* array will be allocated with strings in a single malloc, just free *array */
433 int kmod_elf_get_strings(const struct kmod_elf *elf, const char *section, char ***array)
434 {
435 size_t i, j, count;
436 uint64_t size;
437 const void *buf;
438 const char *strings;
439 char *s, **a;
440 int err;
441
442 *array = NULL;
443
444 err = kmod_elf_get_section(elf, section, &buf, &size);
445 if (err < 0)
446 return err;
447
448 strings = buf;
449 if (strings == NULL || size == 0)
450 return 0;
451
452 /* skip zero padding */
453 while (strings[0] == '\0' && size > 1) {
454 strings++;
455 size--;
456 }
457
458 if (size <= 1)
459 return 0;
460
461 for (i = 0, count = 0; i < size; ) {
462 if (strings[i] != '\0') {
463 i++;
464 continue;
465 }
466
467 while (strings[i] == '\0' && i < size)
468 i++;
469
470 count++;
471 }
472
473 if (strings[i - 1] != '\0')
474 count++;
475
476 *array = a = malloc(size + 1 + sizeof(char *) * (count + 1));
477 if (*array == NULL)
478 return -errno;
479
480 s = (char *)(a + count + 1);
481 memcpy(s, strings, size);
482
483 /* make sure the last string is NULL-terminated */
484 s[size] = '\0';
485 a[count] = NULL;
486 a[0] = s;
487
488 for (i = 0, j = 1; j < count && i < size; ) {
489 if (s[i] != '\0') {
490 i++;
491 continue;
492 }
493
494 while (strings[i] == '\0' && i < size)
495 i++;
496
497 a[j] = &s[i];
498 j++;
499 }
500
501 return count;
502 }
503
504 /* array will be allocated with strings in a single malloc, just free *array */
505 int kmod_elf_get_modversions(const struct kmod_elf *elf, struct kmod_modversion **array)
506 {
507 size_t off, offcrc, slen;
508 uint64_t size;
509 struct kmod_modversion *a;
510 const void *buf;
511 char *itr;
512 int i, count, err;
513 #define MODVERSION_SEC_SIZE (sizeof(struct kmod_modversion64))
514
515 if (elf->class & KMOD_ELF_32)
516 offcrc = sizeof(uint32_t);
517 else
518 offcrc = sizeof(uint64_t);
519
520 *array = NULL;
521
522 err = kmod_elf_get_section(elf, "__versions", &buf, &size);
523 if (err < 0)
524 return err;
525
526 if (buf == NULL || size == 0)
527 return 0;
528
529 if (size % MODVERSION_SEC_SIZE != 0)
530 return -EINVAL;
531
532 count = size / MODVERSION_SEC_SIZE;
533
534 off = (const uint8_t *)buf - elf->memory;
535 slen = 0;
536
537 for (i = 0; i < count; i++, off += MODVERSION_SEC_SIZE) {
538 const char *symbol = elf_get_mem(elf, off + offcrc);
539
540 if (symbol[0] == '.')
541 symbol++;
542
543 slen += strlen(symbol) + 1;
544 }
545
546 *array = a = malloc(sizeof(struct kmod_modversion) * count + slen);
547 if (*array == NULL)
548 return -errno;
549
550 itr = (char *)(a + count);
551 off = (const uint8_t *)buf - elf->memory;
552
553 for (i = 0; i < count; i++, off += MODVERSION_SEC_SIZE) {
554 uint64_t crc = elf_get_uint(elf, off, offcrc);
555 const char *symbol = elf_get_mem(elf, off + offcrc);
556 size_t symbollen;
557
558 if (symbol[0] == '.')
559 symbol++;
560
561 a[i].crc = crc;
562 a[i].bind = KMOD_SYMBOL_UNDEF;
563 a[i].symbol = itr;
564 symbollen = strlen(symbol) + 1;
565 memcpy(itr, symbol, symbollen);
566 itr += symbollen;
567 }
568
569 return count;
570 }
571
572 int kmod_elf_strip_section(struct kmod_elf *elf, const char *section)
573 {
574 uint64_t off, size;
575 const void *buf;
576 int idx = elf_find_section(elf, section);
577 uint64_t val;
578
579 if (idx < 0)
580 return idx;
581
582 buf = elf_get_section_header(elf, idx);
583 off = (const uint8_t *)buf - elf->memory;
584
585 if (elf->class & KMOD_ELF_32) {
586 off += offsetof(Elf32_Shdr, sh_flags);
587 size = sizeof(((Elf32_Shdr *)buf)->sh_flags);
588 } else {
589 off += offsetof(Elf64_Shdr, sh_flags);
590 size = sizeof(((Elf64_Shdr *)buf)->sh_flags);
591 }
592
593 val = elf_get_uint(elf, off, size);
594 val &= ~(uint64_t)SHF_ALLOC;
595
596 return elf_set_uint(elf, off, size, val);
597 }
598
599 int kmod_elf_strip_vermagic(struct kmod_elf *elf)
600 {
601 uint64_t i, size;
602 const void *buf;
603 const char *strings;
604 int err;
605
606 err = kmod_elf_get_section(elf, ".modinfo", &buf, &size);
607 if (err < 0)
608 return err;
609 strings = buf;
610 if (strings == NULL || size == 0)
611 return 0;
612
613 /* skip zero padding */
614 while (strings[0] == '\0' && size > 1) {
615 strings++;
616 size--;
617 }
618 if (size <= 1)
619 return 0;
620
621 for (i = 0; i < size; i++) {
622 const char *s;
623 size_t off, len;
624
625 if (strings[i] == '\0')
626 continue;
627 if (i + 1 >= size)
628 continue;
629
630 s = strings + i;
631 len = sizeof("vermagic=") - 1;
632 if (i + len >= size)
633 continue;
634 if (strncmp(s, "vermagic=", len) != 0) {
635 i += strlen(s);
636 continue;
637 }
638 off = (const uint8_t *)s - elf->memory;
639
640 if (elf->changed == NULL) {
641 elf->changed = malloc(elf->size);
642 if (elf->changed == NULL)
643 return -errno;
644 memcpy(elf->changed, elf->memory, elf->size);
645 elf->memory = elf->changed;
646 ELFDBG(elf, "copied memory to allow writing.\n");
647 }
648
649 len = strlen(s);
650 ELFDBG(elf, "clear .modinfo vermagic \"%s\" (%zd bytes)\n",
651 s, len);
652 memset(elf->changed + off, '\0', len);
653 return 0;
654 }
655
656 ELFDBG(elf, "no vermagic found in .modinfo\n");
657 return -ENOENT;
658 }
659
660
661 static int kmod_elf_get_symbols_symtab(const struct kmod_elf *elf, struct kmod_modversion **array)
662 {
663 uint64_t i, last, size;
664 const void *buf;
665 const char *strings;
666 char *itr;
667 struct kmod_modversion *a;
668 int count, err;
669
670 *array = NULL;
671
672 err = kmod_elf_get_section(elf, "__ksymtab_strings", &buf, &size);
673 if (err < 0)
674 return err;
675 strings = buf;
676 if (strings == NULL || size == 0)
677 return 0;
678
679 /* skip zero padding */
680 while (strings[0] == '\0' && size > 1) {
681 strings++;
682 size--;
683 }
684 if (size <= 1)
685 return 0;
686
687 last = 0;
688 for (i = 0, count = 0; i < size; i++) {
689 if (strings[i] == '\0') {
690 if (last == i) {
691 last = i + 1;
692 continue;
693 }
694 count++;
695 last = i + 1;
696 }
697 }
698 if (strings[i - 1] != '\0')
699 count++;
700
701 *array = a = malloc(size + 1 + sizeof(struct kmod_modversion) * count);
702 if (*array == NULL)
703 return -errno;
704
705 itr = (char *)(a + count);
706 last = 0;
707 for (i = 0, count = 0; i < size; i++) {
708 if (strings[i] == '\0') {
709 size_t slen = i - last;
710 if (last == i) {
711 last = i + 1;
712 continue;
713 }
714 a[count].crc = 0;
715 a[count].bind = KMOD_SYMBOL_GLOBAL;
716 a[count].symbol = itr;
717 memcpy(itr, strings + last, slen);
718 itr[slen] = '\0';
719 itr += slen + 1;
720 count++;
721 last = i + 1;
722 }
723 }
724 if (strings[i - 1] != '\0') {
725 size_t slen = i - last;
726 a[count].crc = 0;
727 a[count].bind = KMOD_SYMBOL_GLOBAL;
728 a[count].symbol = itr;
729 memcpy(itr, strings + last, slen);
730 itr[slen] = '\0';
731 count++;
732 }
733
734 return count;
735 }
736
737 static inline uint8_t kmod_symbol_bind_from_elf(uint8_t elf_value)
738 {
739 switch (elf_value) {
740 case STB_LOCAL:
741 return KMOD_SYMBOL_LOCAL;
742 case STB_GLOBAL:
743 return KMOD_SYMBOL_GLOBAL;
744 case STB_WEAK:
745 return KMOD_SYMBOL_WEAK;
746 default:
747 return KMOD_SYMBOL_NONE;
748 }
749 }
750
751 /* array will be allocated with strings in a single malloc, just free *array */
752 int kmod_elf_get_symbols(const struct kmod_elf *elf, struct kmod_modversion **array)
753 {
754 static const char crc_str[] = "__crc_";
755 static const size_t crc_strlen = sizeof(crc_str) - 1;
756 uint64_t strtablen, symtablen, str_off, sym_off;
757 const void *strtab, *symtab;
758 struct kmod_modversion *a;
759 char *itr;
760 size_t slen, symlen;
761 int i, count, symcount, err;
762
763 err = kmod_elf_get_section(elf, ".strtab", &strtab, &strtablen);
764 if (err < 0) {
765 ELFDBG(elf, "no .strtab found.\n");
766 goto fallback;
767 }
768
769 err = kmod_elf_get_section(elf, ".symtab", &symtab, &symtablen);
770 if (err < 0) {
771 ELFDBG(elf, "no .symtab found.\n");
772 goto fallback;
773 }
774
775 if (elf->class & KMOD_ELF_32)
776 symlen = sizeof(Elf32_Sym);
777 else
778 symlen = sizeof(Elf64_Sym);
779
780 if (symtablen % symlen != 0) {
781 ELFDBG(elf, "unexpected .symtab of length %"PRIu64", not multiple of %"PRIu64" as expected.\n", symtablen, symlen);
782 goto fallback;
783 }
784
785 symcount = symtablen / symlen;
786 count = 0;
787 slen = 0;
788 str_off = (const uint8_t *)strtab - elf->memory;
789 sym_off = (const uint8_t *)symtab - elf->memory + symlen;
790 for (i = 1; i < symcount; i++, sym_off += symlen) {
791 const char *name;
792 uint32_t name_off;
793
794 #define READV(field) \
795 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
796 sizeof(s->field))
797 if (elf->class & KMOD_ELF_32) {
798 Elf32_Sym *s;
799 name_off = READV(st_name);
800 } else {
801 Elf64_Sym *s;
802 name_off = READV(st_name);
803 }
804 #undef READV
805 if (name_off >= strtablen) {
806 ELFDBG(elf, ".strtab is %"PRIu64" bytes, but .symtab entry %d wants to access offset %"PRIu32".\n", strtablen, i, name_off);
807 goto fallback;
808 }
809
810 name = elf_get_mem(elf, str_off + name_off);
811
812 if (strncmp(name, crc_str, crc_strlen) != 0)
813 continue;
814 slen += strlen(name + crc_strlen) + 1;
815 count++;
816 }
817
818 if (count == 0)
819 goto fallback;
820
821 *array = a = malloc(sizeof(struct kmod_modversion) * count + slen);
822 if (*array == NULL)
823 return -errno;
824
825 itr = (char *)(a + count);
826 count = 0;
827 str_off = (const uint8_t *)strtab - elf->memory;
828 sym_off = (const uint8_t *)symtab - elf->memory + symlen;
829 for (i = 1; i < symcount; i++, sym_off += symlen) {
830 const char *name;
831 uint32_t name_off;
832 uint64_t crc;
833 uint8_t info, bind;
834
835 #define READV(field) \
836 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
837 sizeof(s->field))
838 if (elf->class & KMOD_ELF_32) {
839 Elf32_Sym *s;
840 name_off = READV(st_name);
841 crc = READV(st_value);
842 info = READV(st_info);
843 } else {
844 Elf64_Sym *s;
845 name_off = READV(st_name);
846 crc = READV(st_value);
847 info = READV(st_info);
848 }
849 #undef READV
850 name = elf_get_mem(elf, str_off + name_off);
851 if (strncmp(name, crc_str, crc_strlen) != 0)
852 continue;
853 name += crc_strlen;
854
855 if (elf->class & KMOD_ELF_32)
856 bind = ELF32_ST_BIND(info);
857 else
858 bind = ELF64_ST_BIND(info);
859
860 a[count].crc = crc;
861 a[count].bind = kmod_symbol_bind_from_elf(bind);
862 a[count].symbol = itr;
863 slen = strlen(name);
864 memcpy(itr, name, slen);
865 itr[slen] = '\0';
866 itr += slen + 1;
867 count++;
868 }
869 return count;
870
871 fallback:
872 ELFDBG(elf, "Falling back to __ksymtab_strings!\n");
873 return kmod_elf_get_symbols_symtab(elf, array);
874 }
875
876 static int kmod_elf_crc_find(const struct kmod_elf *elf, const void *versions, uint64_t versionslen, const char *name, uint64_t *crc)
877 {
878 size_t verlen, crclen, off;
879 uint64_t i;
880
881 if (elf->class & KMOD_ELF_32) {
882 struct kmod_modversion32 *mv;
883 verlen = sizeof(*mv);
884 crclen = sizeof(mv->crc);
885 } else {
886 struct kmod_modversion64 *mv;
887 verlen = sizeof(*mv);
888 crclen = sizeof(mv->crc);
889 }
890
891 off = (const uint8_t *)versions - elf->memory;
892 for (i = 0; i < versionslen; i += verlen) {
893 const char *symbol = elf_get_mem(elf, off + i + crclen);
894 if (!streq(name, symbol))
895 continue;
896 *crc = elf_get_uint(elf, off + i, crclen);
897 return i / verlen;
898 }
899
900 ELFDBG(elf, "could not find crc for symbol '%s'\n", name);
901 *crc = 0;
902 return -1;
903 }
904
905 /* from module-init-tools:elfops_core.c */
906 #ifndef STT_REGISTER
907 #define STT_REGISTER 13 /* Global register reserved to app. */
908 #endif
909
910 /* array will be allocated with strings in a single malloc, just free *array */
911 int kmod_elf_get_dependency_symbols(const struct kmod_elf *elf, struct kmod_modversion **array)
912 {
913 uint64_t versionslen, strtablen, symtablen, str_off, sym_off, ver_off;
914 const void *versions, *strtab, *symtab;
915 struct kmod_modversion *a;
916 char *itr;
917 size_t slen, verlen, symlen, crclen;
918 int i, count, symcount, vercount, err;
919 bool handle_register_symbols;
920 uint8_t *visited_versions;
921 uint64_t *symcrcs;
922
923 err = kmod_elf_get_section(elf, "__versions", &versions, &versionslen);
924 if (err < 0) {
925 versions = NULL;
926 versionslen = 0;
927 verlen = 0;
928 crclen = 0;
929 } else {
930 if (elf->class & KMOD_ELF_32) {
931 struct kmod_modversion32 *mv;
932 verlen = sizeof(*mv);
933 crclen = sizeof(mv->crc);
934 } else {
935 struct kmod_modversion64 *mv;
936 verlen = sizeof(*mv);
937 crclen = sizeof(mv->crc);
938 }
939 if (versionslen % verlen != 0) {
940 ELFDBG(elf, "unexpected __versions of length %"PRIu64", not multiple of %zd as expected.\n", versionslen, verlen);
941 versions = NULL;
942 versionslen = 0;
943 }
944 }
945
946 err = kmod_elf_get_section(elf, ".strtab", &strtab, &strtablen);
947 if (err < 0) {
948 ELFDBG(elf, "no .strtab found.\n");
949 return -EINVAL;
950 }
951
952 err = kmod_elf_get_section(elf, ".symtab", &symtab, &symtablen);
953 if (err < 0) {
954 ELFDBG(elf, "no .symtab found.\n");
955 return -EINVAL;
956 }
957
958 if (elf->class & KMOD_ELF_32)
959 symlen = sizeof(Elf32_Sym);
960 else
961 symlen = sizeof(Elf64_Sym);
962
963 if (symtablen % symlen != 0) {
964 ELFDBG(elf, "unexpected .symtab of length %"PRIu64", not multiple of %"PRIu64" as expected.\n", symtablen, symlen);
965 return -EINVAL;
966 }
967
968 if (versionslen == 0) {
969 vercount = 0;
970 visited_versions = NULL;
971 } else {
972 vercount = versionslen / verlen;
973 visited_versions = calloc(vercount, sizeof(uint8_t));
974 if (visited_versions == NULL)
975 return -ENOMEM;
976 }
977
978 handle_register_symbols = (elf->header.machine == EM_SPARC ||
979 elf->header.machine == EM_SPARCV9);
980
981 symcount = symtablen / symlen;
982 count = 0;
983 slen = 0;
984 str_off = (const uint8_t *)strtab - elf->memory;
985 sym_off = (const uint8_t *)symtab - elf->memory + symlen;
986
987 symcrcs = calloc(symcount, sizeof(uint64_t));
988 if (symcrcs == NULL) {
989 free(visited_versions);
990 return -ENOMEM;
991 }
992
993 for (i = 1; i < symcount; i++, sym_off += symlen) {
994 const char *name;
995 uint64_t crc;
996 uint32_t name_off;
997 uint16_t secidx;
998 uint8_t info;
999 int idx;
1000
1001 #define READV(field) \
1002 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
1003 sizeof(s->field))
1004 if (elf->class & KMOD_ELF_32) {
1005 Elf32_Sym *s;
1006 name_off = READV(st_name);
1007 secidx = READV(st_shndx);
1008 info = READV(st_info);
1009 } else {
1010 Elf64_Sym *s;
1011 name_off = READV(st_name);
1012 secidx = READV(st_shndx);
1013 info = READV(st_info);
1014 }
1015 #undef READV
1016 if (secidx != SHN_UNDEF)
1017 continue;
1018
1019 if (handle_register_symbols) {
1020 uint8_t type;
1021 if (elf->class & KMOD_ELF_32)
1022 type = ELF32_ST_TYPE(info);
1023 else
1024 type = ELF64_ST_TYPE(info);
1025
1026 /* Not really undefined: sparc gcc 3.3 creates
1027 * U references when you have global asm
1028 * variables, to avoid anyone else misusing
1029 * them.
1030 */
1031 if (type == STT_REGISTER)
1032 continue;
1033 }
1034
1035 if (name_off >= strtablen) {
1036 ELFDBG(elf, ".strtab is %"PRIu64" bytes, but .symtab entry %d wants to access offset %"PRIu32".\n", strtablen, i, name_off);
1037 free(visited_versions);
1038 free(symcrcs);
1039 return -EINVAL;
1040 }
1041
1042 name = elf_get_mem(elf, str_off + name_off);
1043 if (name[0] == '\0') {
1044 ELFDBG(elf, "empty symbol name at index %"PRIu64"\n", i);
1045 continue;
1046 }
1047
1048 slen += strlen(name) + 1;
1049 count++;
1050
1051 idx = kmod_elf_crc_find(elf, versions, versionslen, name, &crc);
1052 if (idx >= 0 && visited_versions != NULL)
1053 visited_versions[idx] = 1;
1054 symcrcs[i] = crc;
1055 }
1056
1057 if (visited_versions != NULL) {
1058 /* module_layout/struct_module are not visited, but needed */
1059 ver_off = (const uint8_t *)versions - elf->memory;
1060 for (i = 0; i < vercount; i++) {
1061 if (visited_versions[i] == 0) {
1062 const char *name;
1063 name = elf_get_mem(elf, ver_off + i * verlen + crclen);
1064 slen += strlen(name) + 1;
1065
1066 count++;
1067 }
1068 }
1069 }
1070
1071 if (count == 0) {
1072 free(visited_versions);
1073 free(symcrcs);
1074 *array = NULL;
1075 return 0;
1076 }
1077
1078 *array = a = malloc(sizeof(struct kmod_modversion) * count + slen);
1079 if (*array == NULL) {
1080 free(visited_versions);
1081 free(symcrcs);
1082 return -errno;
1083 }
1084
1085 itr = (char *)(a + count);
1086 count = 0;
1087 str_off = (const uint8_t *)strtab - elf->memory;
1088 sym_off = (const uint8_t *)symtab - elf->memory + symlen;
1089 for (i = 1; i < symcount; i++, sym_off += symlen) {
1090 const char *name;
1091 uint64_t crc;
1092 uint32_t name_off;
1093 uint16_t secidx;
1094 uint8_t info, bind;
1095
1096 #define READV(field) \
1097 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
1098 sizeof(s->field))
1099 if (elf->class & KMOD_ELF_32) {
1100 Elf32_Sym *s;
1101 name_off = READV(st_name);
1102 secidx = READV(st_shndx);
1103 info = READV(st_info);
1104 } else {
1105 Elf64_Sym *s;
1106 name_off = READV(st_name);
1107 secidx = READV(st_shndx);
1108 info = READV(st_info);
1109 }
1110 #undef READV
1111 if (secidx != SHN_UNDEF)
1112 continue;
1113
1114 if (handle_register_symbols) {
1115 uint8_t type;
1116 if (elf->class & KMOD_ELF_32)
1117 type = ELF32_ST_TYPE(info);
1118 else
1119 type = ELF64_ST_TYPE(info);
1120
1121 /* Not really undefined: sparc gcc 3.3 creates
1122 * U references when you have global asm
1123 * variables, to avoid anyone else misusing
1124 * them.
1125 */
1126 if (type == STT_REGISTER)
1127 continue;
1128 }
1129
1130 name = elf_get_mem(elf, str_off + name_off);
1131 if (name[0] == '\0') {
1132 ELFDBG(elf, "empty symbol name at index %"PRIu64"\n", i);
1133 continue;
1134 }
1135
1136 if (elf->class & KMOD_ELF_32)
1137 bind = ELF32_ST_BIND(info);
1138 else
1139 bind = ELF64_ST_BIND(info);
1140 if (bind == STB_WEAK)
1141 bind = KMOD_SYMBOL_WEAK;
1142 else
1143 bind = KMOD_SYMBOL_UNDEF;
1144
1145 slen = strlen(name);
1146 crc = symcrcs[i];
1147
1148 a[count].crc = crc;
1149 a[count].bind = bind;
1150 a[count].symbol = itr;
1151 memcpy(itr, name, slen);
1152 itr[slen] = '\0';
1153 itr += slen + 1;
1154
1155 count++;
1156 }
1157
1158 free(symcrcs);
1159
1160 if (visited_versions == NULL)
1161 return count;
1162
1163 /* add unvisited (module_layout/struct_module) */
1164 ver_off = (const uint8_t *)versions - elf->memory;
1165 for (i = 0; i < vercount; i++) {
1166 const char *name;
1167 uint64_t crc;
1168
1169 if (visited_versions[i] != 0)
1170 continue;
1171
1172 name = elf_get_mem(elf, ver_off + i * verlen + crclen);
1173 slen = strlen(name);
1174 crc = elf_get_uint(elf, ver_off + i * verlen, crclen);
1175
1176 a[count].crc = crc;
1177 a[count].bind = KMOD_SYMBOL_UNDEF;
1178 a[count].symbol = itr;
1179 memcpy(itr, name, slen);
1180 itr[slen] = '\0';
1181 itr += slen + 1;
1182
1183 count++;
1184 }
1185 free(visited_versions);
1186 return count;
1187 }
File src/libkmod-file.c added (mode: 100644) (index 0000000..39e8c99)
1 /*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <errno.h>
21 #include <stdbool.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <limits.h>
26 #include <stddef.h>
27 #include <syslog.h>
28 #include <sys/mman.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32 #ifdef ENABLE_XZ
33 #include <lzma.h>
34 #endif
35 #ifdef ENABLE_ZLIB
36 #include <zlib.h>
37 #endif
38
39 #include "config.h"
40
41 #include "libkmod.h"
42 #include "libkmod-namespace.h"
43 #include "libkmod-paths.h"
44
45 #include "shared/macro.h"
46 #include "shared/util.h"
47
48 #define LIBKMOD_FILE_C
49 #include "libkmod-internal.h"
50 #undef LIBKMOD_FILE_C
51
52 struct kmod_file;
53 struct file_ops {
54 int (*load)(struct kmod_file *file);
55 void (*unload)(struct kmod_file *file);
56 };
57
58 struct kmod_file {
59 #ifdef ENABLE_XZ
60 bool xz_used;
61 #endif
62 #ifdef ENABLE_ZLIB
63 gzFile gzf;
64 #endif
65 int fd;
66 bool direct;
67 off_t size;
68 void *memory;
69 const struct file_ops *ops;
70 const struct kmod_ctx *ctx;
71 struct kmod_elf *elf;
72 };
73
74 #ifdef ENABLE_XZ
75 static void xz_uncompress_belch(struct kmod_file *file, lzma_ret ret)
76 {
77 switch (ret) {
78 case LZMA_MEM_ERROR:
79 ERR(file->ctx, "xz: %s\n", strerror(ENOMEM));
80 break;
81 case LZMA_FORMAT_ERROR:
82 ERR(file->ctx, "xz: File format not recognized\n");
83 break;
84 case LZMA_OPTIONS_ERROR:
85 ERR(file->ctx, "xz: Unsupported compression options\n");
86 break;
87 case LZMA_DATA_ERROR:
88 ERR(file->ctx, "xz: File is corrupt\n");
89 break;
90 case LZMA_BUF_ERROR:
91 ERR(file->ctx, "xz: Unexpected end of input\n");
92 break;
93 default:
94 ERR(file->ctx, "xz: Internal error (bug)\n");
95 break;
96 }
97 }
98
99 static int xz_uncompress(lzma_stream *strm, struct kmod_file *file)
100 {
101 uint8_t in_buf[BUFSIZ], out_buf[BUFSIZ];
102 lzma_action action = LZMA_RUN;
103 lzma_ret ret;
104 void *p = NULL;
105 size_t total = 0;
106
107 strm->avail_in = 0;
108 strm->next_out = out_buf;
109 strm->avail_out = sizeof(out_buf);
110
111 while (true) {
112 if (strm->avail_in == 0) {
113 ssize_t rdret = read(file->fd, in_buf, sizeof(in_buf));
114 if (rdret < 0) {
115 ret = -errno;
116 goto out;
117 }
118 strm->next_in = in_buf;
119 strm->avail_in = rdret;
120 if (rdret == 0)
121 action = LZMA_FINISH;
122 }
123 ret = lzma_code(strm, action);
124 if (strm->avail_out == 0 || ret != LZMA_OK) {
125 size_t write_size = BUFSIZ - strm->avail_out;
126 char *tmp = realloc(p, total + write_size);
127 if (tmp == NULL) {
128 ret = -errno;
129 goto out;
130 }
131 memcpy(tmp + total, out_buf, write_size);
132 total += write_size;
133 p = tmp;
134 strm->next_out = out_buf;
135 strm->avail_out = BUFSIZ;
136 }
137 if (ret == LZMA_STREAM_END)
138 break;
139 if (ret != LZMA_OK) {
140 xz_uncompress_belch(file, ret);
141 ret = -EINVAL;
142 goto out;
143 }
144 }
145 file->xz_used = true;
146 file->memory = p;
147 file->size = total;
148 return 0;
149 out:
150 free(p);
151 return ret;
152 }
153
154 static int load_xz(struct kmod_file *file)
155 {
156 lzma_stream strm = LZMA_STREAM_INIT;
157 lzma_ret lzret;
158 int ret;
159
160 lzret = lzma_stream_decoder(&strm, UINT64_MAX, LZMA_CONCATENATED);
161 if (lzret == LZMA_MEM_ERROR) {
162 ERR(file->ctx, "xz: %s\n", strerror(ENOMEM));
163 return -ENOMEM;
164 } else if (lzret != LZMA_OK) {
165 ERR(file->ctx, "xz: Internal error (bug)\n");
166 return -EINVAL;
167 }
168 ret = xz_uncompress(&strm, file);
169 lzma_end(&strm);
170 return ret;
171 }
172
173 static void unload_xz(struct kmod_file *file)
174 {
175 if (!file->xz_used)
176 return;
177 free(file->memory);
178 }
179
180 static const char magic_xz[] = {0xfd, '7', 'z', 'X', 'Z', 0};
181 #endif
182
183 #ifdef ENABLE_ZLIB
184 #define READ_STEP (4 * 1024 * 1024)
185 static int load_zlib(struct kmod_file *file)
186 {
187 int err = 0;
188 off_t did = 0, total = 0;
189 unsigned char *p = NULL;
190
191 errno = 0;
192 file->gzf = gzdopen(file->fd, "rb");
193 if (file->gzf == NULL)
194 return -errno;
195 file->fd = -1; /* now owned by gzf due gzdopen() */
196
197 for (;;) {
198 int r;
199
200 if (did == total) {
201 void *tmp = realloc(p, total + READ_STEP);
202 if (tmp == NULL) {
203 err = -errno;
204 goto error;
205 }
206 total += READ_STEP;
207 p = tmp;
208 }
209
210 r = gzread(file->gzf, p + did, total - did);
211 if (r == 0)
212 break;
213 else if (r < 0) {
214 int gzerr;
215 const char *gz_errmsg = gzerror(file->gzf, &gzerr);
216
217 ERR(file->ctx, "gzip: %s\n", gz_errmsg);
218
219 /* gzip might not set errno here */
220 err = gzerr == Z_ERRNO ? -errno : -EINVAL;
221 goto error;
222 }
223 did += r;
224 }
225
226 file->memory = p;
227 file->size = did;
228 return 0;
229
230 error:
231 gzclose(file->gzf);
232 if (p)
233 free(p);
234 return err;
235 }
236
237 static void unload_zlib(struct kmod_file *file)
238 {
239 if (file->gzf == NULL)
240 return;
241 free(file->memory);
242 gzclose(file->gzf); /* closes file->fd */
243 }
244
245 static const char magic_zlib[] = {0x1f, 0x8b};
246 #endif
247
248 static const struct comp_type {
249 size_t magic_size;
250 const char *magic_bytes;
251 const struct file_ops ops;
252 } comp_types[] = {
253 #ifdef ENABLE_XZ
254 {sizeof(magic_xz), magic_xz, {load_xz, unload_xz}},
255 #endif
256 #ifdef ENABLE_ZLIB
257 {sizeof(magic_zlib), magic_zlib, {load_zlib, unload_zlib}},
258 #endif
259 {0, NULL, {NULL, NULL}}
260 };
261
262 static int load_reg(struct kmod_file *file)
263 {
264 struct stat st;
265
266 if (fstat(file->fd, &st) < 0)
267 return -errno;
268
269 file->size = st.st_size;
270 file->memory = mmap(NULL, file->size, PROT_READ, MAP_PRIVATE,
271 file->fd, 0);
272 if (file->memory == MAP_FAILED)
273 return -errno;
274 file->direct = true;
275 return 0;
276 }
277
278 static void unload_reg(struct kmod_file *file)
279 {
280 munmap(file->memory, file->size);
281 }
282
283 static const struct file_ops reg_ops = {
284 load_reg, unload_reg
285 };
286
287 struct kmod_elf *kmod_file_get_elf(struct kmod_file *file)
288 {
289 if (file->elf)
290 return file->elf;
291
292 file->elf = kmod_elf_new(file->memory, file->size);
293 return file->elf;
294 }
295
296 struct kmod_file *kmod_file_open(const struct kmod_ctx *ctx,
297 const char *filename)
298 {
299 struct kmod_file *file = calloc(1, sizeof(struct kmod_file));
300 const struct comp_type *itr;
301 size_t magic_size_max = 0;
302 int err;
303
304 if (file == NULL)
305 return NULL;
306
307 file->fd = open(filename, O_RDONLY|O_CLOEXEC);
308 if (file->fd < 0) {
309 err = -errno;
310 goto error;
311 }
312
313 for (itr = comp_types; itr->ops.load != NULL; itr++) {
314 if (magic_size_max < itr->magic_size)
315 magic_size_max = itr->magic_size;
316 }
317
318 file->direct = false;
319 if (magic_size_max > 0) {
320 char *buf = malloc(magic_size_max + 1);
321 ssize_t sz;
322
323 if (buf == NULL) {
324 err = -errno;
325 goto error;
326 }
327 sz = read_str_safe(file->fd, buf, magic_size_max + 1);
328 lseek(file->fd, 0, SEEK_SET);
329 if (sz != (ssize_t)magic_size_max) {
330 if (sz < 0)
331 err = sz;
332 else
333 err = -EINVAL;
334 free(buf);
335 goto error;
336 }
337
338 for (itr = comp_types; itr->ops.load != NULL; itr++) {
339 if (memcmp(buf, itr->magic_bytes, itr->magic_size) == 0)
340 break;
341 }
342 if (itr->ops.load != NULL)
343 file->ops = &itr->ops;
344 free(buf);
345 }
346
347 if (file->ops == NULL)
348 file->ops = &reg_ops;
349
350 err = file->ops->load(file);
351 file->ctx = ctx;
352 error:
353 if (err < 0) {
354 if (file->fd >= 0)
355 close(file->fd);
356 free(file);
357 errno = -err;
358 return NULL;
359 }
360
361 return file;
362 }
363
364 void *kmod_file_get_contents(const struct kmod_file *file)
365 {
366 return file->memory;
367 }
368
369 off_t kmod_file_get_size(const struct kmod_file *file)
370 {
371 return file->size;
372 }
373
374 bool kmod_file_get_direct(const struct kmod_file *file)
375 {
376 return file->direct;
377 }
378
379 int kmod_file_get_fd(const struct kmod_file *file)
380 {
381 return file->fd;
382 }
383
384 void kmod_file_unref(struct kmod_file *file)
385 {
386 if (file->elf)
387 kmod_elf_unref(file->elf);
388
389 file->ops->unload(file);
390 if (file->fd >= 0)
391 close(file->fd);
392 free(file);
393 }
File src/libkmod-index.c added (mode: 100644) (index 0000000..7516e62)
1 /*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <arpa/inet.h>
21 #include <assert.h>
22 #include <errno.h>
23 #include <fnmatch.h>
24 #include <inttypes.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <limits.h>
29 #include <syslog.h>
30 #include <sys/stat.h>
31
32 #include "config.h"
33
34 #include "libkmod.h"
35 #include "libkmod-namespace.h"
36 #include "libkmod-paths.h"
37 #include "shared/macro.h"
38 #include "shared/strbuf.h"
39 #include "shared/util.h"
40 #include "libkmod-internal.h"
41 #define LIBKMOD_INDEX_C
42 #include "libkmod-index.h"
43 #undef LIBKMOD_INDEX_C
44
45 /* libkmod-index.c: module index file implementation
46 *
47 * Integers are stored as 32 bit unsigned in "network" order, i.e. MSB first.
48 * All files start with a magic number.
49 *
50 * Magic spells "BOOTFAST". Second one used on newer versioned binary files.
51 * #define INDEX_MAGIC_OLD 0xB007FA57
52 *
53 * We use a version string to keep track of changes to the binary format
54 * This is stored in the form: INDEX_MAJOR (hi) INDEX_MINOR (lo) just in
55 * case we ever decide to have minor changes that are not incompatible.
56 */
57 #define INDEX_MAGIC 0xB007F457
58 #define INDEX_VERSION_MAJOR 0x0002
59 #define INDEX_VERSION_MINOR 0x0001
60 #define INDEX_VERSION ((INDEX_VERSION_MAJOR<<16)|INDEX_VERSION_MINOR)
61
62 /* The index file maps keys to values. Both keys and values are ASCII strings.
63 * Each key can have multiple values. Values are sorted by an integer priority.
64 *
65 * The reader also implements a wildcard search (including range expressions)
66 * where the keys in the index are treated as patterns.
67 * This feature is required for module aliases.
68 */
69 #define INDEX_CHILDMAX 128
70
71 /* Disk format:
72 *
73 * uint32_t magic = INDEX_MAGIC;
74 * uint32_t version = INDEX_VERSION;
75 * uint32_t root_offset;
76 *
77 * (node_offset & INDEX_NODE_MASK) specifies the file offset of nodes:
78 *
79 * char[] prefix; // nul terminated
80 *
81 * char first;
82 * char last;
83 * uint32_t children[last - first + 1];
84 *
85 * uint32_t value_count;
86 * struct {
87 * uint32_t priority;
88 * char[] value; // nul terminated
89 * } values[value_count];
90 *
91 * (node_offset & INDEX_NODE_FLAGS) indicates which fields are present.
92 * Empty prefixes are omitted, leaf nodes omit the three child-related fields.
93 *
94 * This could be optimised further by adding a sparse child format
95 * (indicated using a new flag).
96 *
97 *
98 * Implementation is based on a radix tree, or "trie".
99 * Each arc from parent to child is labelled with a character.
100 * Each path from the root represents a string.
101 *
102 * == Example strings ==
103 *
104 * ask
105 * ate
106 * on
107 * once
108 * one
109 *
110 * == Key ==
111 * + Normal node
112 * * Marked node, representing a key and it's values.
113 *
114 * +
115 * |-a-+-s-+-k-*
116 * | |
117 * | `-t-+-e-*
118 * |
119 * `-o-+-n-*-c-+-e-*
120 * |
121 * `-e-*
122 *
123 * Naive implementations tend to be very space inefficient; child pointers
124 * are stored in arrays indexed by character, but most child pointers are null.
125 *
126 * Our implementation uses a scheme described by Wikipedia as a Patrica trie,
127 *
128 * "easiest to understand as a space-optimized trie where
129 * each node with only one child is merged with its child"
130 *
131 * +
132 * |-a-+-sk-*
133 * | |
134 * | `-te-*
135 * |
136 * `-on-*-ce-*
137 * |
138 * `-e-*
139 *
140 * We still use arrays of child pointers indexed by a single character;
141 * the remaining characters of the label are stored as a "prefix" in the child.
142 *
143 * The paper describing the original Patrica trie works on individiual bits -
144 * each node has a maximum of two children, which increases space efficiency.
145 * However for this application it is simpler to use the ASCII character set.
146 * Since the index file is read-only, it can be compressed by omitting null
147 * child pointers at the start and end of arrays.
148 */
149
150 /* Format of node offsets within index file */
151 enum node_offset {
152 INDEX_NODE_FLAGS = 0xF0000000, /* Flags in high nibble */
153 INDEX_NODE_PREFIX = 0x80000000,
154 INDEX_NODE_VALUES = 0x40000000,
155 INDEX_NODE_CHILDS = 0x20000000,
156
157 INDEX_NODE_MASK = 0x0FFFFFFF, /* Offset value */
158 };
159
160 void index_values_free(struct index_value *values)
161 {
162 while (values) {
163 struct index_value *value = values;
164
165 values = value->next;
166 free(value);
167 }
168 }
169
170 static int add_value(struct index_value **values,
171 const char *value, unsigned len, unsigned int priority)
172 {
173 struct index_value *v;
174
175 /* find position to insert value */
176 while (*values && (*values)->priority < priority)
177 values = &(*values)->next;
178
179 v = malloc(sizeof(struct index_value) + len + 1);
180 if (!v)
181 return -1;
182 v->next = *values;
183 v->priority = priority;
184 v->len = len;
185 memcpy(v->value, value, len);
186 v->value[len] = '\0';
187 *values = v;
188
189 return 0;
190 }
191
192 static void read_error(void)
193 {
194 fatal("Module index: unexpected error: %s\n"
195 "Try re-running depmod\n", errno ? strerror(errno) : "EOF");
196 }
197
198 static int read_char(FILE *in)
199 {
200 int ch;
201
202 errno = 0;
203 ch = getc_unlocked(in);
204 if (ch == EOF)
205 read_error();
206 return ch;
207 }
208
209 static uint32_t read_long(FILE *in)
210 {
211 uint32_t l;
212
213 errno = 0;
214 if (fread(&l, sizeof(uint32_t), 1, in) != sizeof(uint32_t))
215 read_error();
216 return ntohl(l);
217 }
218
219 static unsigned buf_freadchars(struct strbuf *buf, FILE *in)
220 {
221 unsigned i = 0;
222 int ch;
223
224 while ((ch = read_char(in))) {
225 if (!strbuf_pushchar(buf, ch))
226 break;
227 i++;
228 }
229
230 return i;
231 }
232
233 /*
234 * Index file searching
235 */
236 struct index_node_f {
237 FILE *file;
238 char *prefix; /* path compression */
239 struct index_value *values;
240 unsigned char first; /* range of child nodes */
241 unsigned char last;
242 uint32_t children[0];
243 };
244
245 static struct index_node_f *index_read(FILE *in, uint32_t offset)
246 {
247 struct index_node_f *node;
248 char *prefix;
249 int i, child_count = 0;
250
251 if ((offset & INDEX_NODE_MASK) == 0)
252 return NULL;
253
254 if (fseek(in, offset & INDEX_NODE_MASK, SEEK_SET) < 0)
255 return NULL;
256
257 if (offset & INDEX_NODE_PREFIX) {
258 struct strbuf buf;
259 strbuf_init(&buf);
260 buf_freadchars(&buf, in);
261 prefix = strbuf_steal(&buf);
262 } else
263 prefix = NOFAIL(strdup(""));
264
265 if (offset & INDEX_NODE_CHILDS) {
266 char first = read_char(in);
267 char last = read_char(in);
268 child_count = last - first + 1;
269
270 node = NOFAIL(malloc(sizeof(struct index_node_f) +
271 sizeof(uint32_t) * child_count));
272
273 node->first = first;
274 node->last = last;
275
276 for (i = 0; i < child_count; i++)
277 node->children[i] = read_long(in);
278 } else {
279 node = NOFAIL(malloc(sizeof(struct index_node_f)));
280 node->first = INDEX_CHILDMAX;
281 node->last = 0;
282 }
283
284 node->values = NULL;
285 if (offset & INDEX_NODE_VALUES) {
286 int value_count;
287 struct strbuf buf;
288 const char *value;
289 unsigned int priority;
290
291 value_count = read_long(in);
292
293 strbuf_init(&buf);
294 while (value_count--) {
295 priority = read_long(in);
296 buf_freadchars(&buf, in);
297 value = strbuf_str(&buf);
298 add_value(&node->values, value, buf.used, priority);
299 strbuf_clear(&buf);
300 }
301 strbuf_release(&buf);
302 }
303
304 node->prefix = prefix;
305 node->file = in;
306 return node;
307 }
308
309 static void index_close(struct index_node_f *node)
310 {
311 free(node->prefix);
312 index_values_free(node->values);
313 free(node);
314 }
315
316 struct index_file {
317 FILE *file;
318 uint32_t root_offset;
319 };
320
321 struct index_file *index_file_open(const char *filename)
322 {
323 FILE *file;
324 uint32_t magic, version;
325 struct index_file *new;
326
327 file = fopen(filename, "re");
328 if (!file)
329 return NULL;
330 errno = EINVAL;
331
332 magic = read_long(file);
333 if (magic != INDEX_MAGIC) {
334 fclose(file);
335 return NULL;
336 }
337
338 version = read_long(file);
339 if (version >> 16 != INDEX_VERSION_MAJOR) {
340 fclose(file);
341 return NULL;
342 }
343
344 new = NOFAIL(malloc(sizeof(struct index_file)));
345 new->file = file;
346 new->root_offset = read_long(new->file);
347
348 errno = 0;
349 return new;
350 }
351
352 void index_file_close(struct index_file *idx)
353 {
354 fclose(idx->file);
355 free(idx);
356 }
357
358 static struct index_node_f *index_readroot(struct index_file *in)
359 {
360 return index_read(in->file, in->root_offset);
361 }
362
363 static struct index_node_f *index_readchild(const struct index_node_f *parent,
364 int ch)
365 {
366 if (parent->first <= ch && ch <= parent->last) {
367 return index_read(parent->file,
368 parent->children[ch - parent->first]);
369 }
370
371 return NULL;
372 }
373
374 static void index_dump_node(struct index_node_f *node, struct strbuf *buf,
375 int fd)
376 {
377 struct index_value *v;
378 int ch, pushed;
379
380 pushed = strbuf_pushchars(buf, node->prefix);
381
382 for (v = node->values; v != NULL; v = v->next) {
383 write_str_safe(fd, buf->bytes, buf->used);
384 write_str_safe(fd, " ", 1);
385 write_str_safe(fd, v->value, strlen(v->value));
386 write_str_safe(fd, "\n", 1);
387 }
388
389 for (ch = node->first; ch <= node->last; ch++) {
390 struct index_node_f *child = index_readchild(node, ch);
391
392 if (!child)
393 continue;
394
395 strbuf_pushchar(buf, ch);
396 index_dump_node(child, buf, fd);
397 strbuf_popchar(buf);
398 }
399
400 strbuf_popchars(buf, pushed);
401 index_close(node);
402 }
403
404 void index_dump(struct index_file *in, int fd, const char *prefix)
405 {
406 struct index_node_f *root;
407 struct strbuf buf;
408
409 root = index_readroot(in);
410 if (root == NULL)
411 return;
412
413 strbuf_init(&buf);
414 strbuf_pushchars(&buf, prefix);
415 index_dump_node(root, &buf, fd);
416 strbuf_release(&buf);
417 }
418
419 static char *index_search__node(struct index_node_f *node, const char *key, int i)
420 {
421 char *value;
422 struct index_node_f *child;
423 int ch;
424 int j;
425
426 while(node) {
427 for (j = 0; node->prefix[j]; j++) {
428 ch = node->prefix[j];
429
430 if (ch != key[i+j]) {
431 index_close(node);
432 return NULL;
433 }
434 }
435
436 i += j;
437
438 if (key[i] == '\0') {
439 value = node->values != NULL
440 ? strdup(node->values[0].value)
441 : NULL;
442
443 index_close(node);
444 return value;
445 }
446
447 child = index_readchild(node, key[i]);
448 index_close(node);
449 node = child;
450 i++;
451 }
452
453 return NULL;
454 }
455
456 /*
457 * Search the index for a key
458 *
459 * Returns the value of the first match
460 *
461 * The recursive functions free their node argument (using index_close).
462 */
463 char *index_search(struct index_file *in, const char *key)
464 {
465 // FIXME: return value by reference instead of strdup
466 struct index_node_f *root;
467 char *value;
468
469 root = index_readroot(in);
470 value = index_search__node(root, key, 0);
471
472 return value;
473 }
474
475
476
477 /* Level 4: add all the values from a matching node */
478 static void index_searchwild__allvalues(struct index_node_f *node,
479 struct index_value **out)
480 {
481 struct index_value *v;
482
483 for (v = node->values; v != NULL; v = v->next)
484 add_value(out, v->value, v->len, v->priority);
485
486 index_close(node);
487 }
488
489 /*
490 * Level 3: traverse a sub-keyspace which starts with a wildcard,
491 * looking for matches.
492 */
493 static void index_searchwild__all(struct index_node_f *node, int j,
494 struct strbuf *buf,
495 const char *subkey,
496 struct index_value **out)
497 {
498 int pushed = 0;
499 int ch;
500
501 while (node->prefix[j]) {
502 ch = node->prefix[j];
503
504 strbuf_pushchar(buf, ch);
505 pushed++;
506 j++;
507 }
508
509 for (ch = node->first; ch <= node->last; ch++) {
510 struct index_node_f *child = index_readchild(node, ch);
511
512 if (!child)
513 continue;
514
515 strbuf_pushchar(buf, ch);
516 index_searchwild__all(child, 0, buf, subkey, out);
517 strbuf_popchar(buf);
518 }
519
520 if (node->values) {
521 if (fnmatch(strbuf_str(buf), subkey, 0) == 0)
522 index_searchwild__allvalues(node, out);
523 else
524 index_close(node);
525 } else {
526 index_close(node);
527 }
528
529 strbuf_popchars(buf, pushed);
530 }
531
532 /* Level 2: descend the tree (until we hit a wildcard) */
533 static void index_searchwild__node(struct index_node_f *node,
534 struct strbuf *buf,
535 const char *key, int i,
536 struct index_value **out)
537 {
538 struct index_node_f *child;
539 int j;
540 int ch;
541
542 while(node) {
543 for (j = 0; node->prefix[j]; j++) {
544 ch = node->prefix[j];
545
546 if (ch == '*' || ch == '?' || ch == '[') {
547 index_searchwild__all(node, j, buf,
548 &key[i+j], out);
549 return;
550 }
551
552 if (ch != key[i+j]) {
553 index_close(node);
554 return;
555 }
556 }
557
558 i += j;
559
560 child = index_readchild(node, '*');
561 if (child) {
562 strbuf_pushchar(buf, '*');
563 index_searchwild__all(child, 0, buf, &key[i], out);
564 strbuf_popchar(buf);
565 }
566
567 child = index_readchild(node, '?');
568 if (child) {
569 strbuf_pushchar(buf, '?');
570 index_searchwild__all(child, 0, buf, &key[i], out);
571 strbuf_popchar(buf);
572 }
573
574 child = index_readchild(node, '[');
575 if (child) {
576 strbuf_pushchar(buf, '[');
577 index_searchwild__all(child, 0, buf, &key[i], out);
578 strbuf_popchar(buf);
579 }
580
581 if (key[i] == '\0') {
582 index_searchwild__allvalues(node, out);
583
584 return;
585 }
586
587 child = index_readchild(node, key[i]);
588 index_close(node);
589 node = child;
590 i++;
591 }
592 }
593
594 /*
595 * Search the index for a key. The index may contain wildcards.
596 *
597 * Returns a list of all the values of matching keys.
598 */
599 struct index_value *index_searchwild(struct index_file *in, const char *key)
600 {
601 struct index_node_f *root = index_readroot(in);
602 struct strbuf buf;
603 struct index_value *out = NULL;
604
605 strbuf_init(&buf);
606 index_searchwild__node(root, &buf, key, 0, &out);
607 strbuf_release(&buf);
608 return out;
609 }
610
611 /**************************************************************************/
612 /*
613 * Alternative implementation, using mmap to map all the file to memory when
614 * starting
615 */
616 #include <sys/mman.h>
617 #include <sys/stat.h>
618 #include <unistd.h>
619
620 static const char _idx_empty_str[] = "";
621
622 struct index_mm {
623 struct kmod_ctx *ctx;
624 void *mm;
625 uint32_t root_offset;
626 size_t size;
627 };
628
629 struct index_mm_value {
630 unsigned int priority;
631 unsigned int len;
632 const char *value;
633 };
634
635 struct index_mm_value_array {
636 struct index_mm_value *values;
637 unsigned int len;
638 };
639
640 struct index_mm_node {
641 struct index_mm *idx;
642 const char *prefix; /* mmape'd value */
643 struct index_mm_value_array values;
644 unsigned char first;
645 unsigned char last;
646 uint32_t children[];
647 };
648
649 static inline uint32_t read_long_mm(void **p)
650 {
651 uint8_t *addr = *(uint8_t **)p;
652 uint32_t v;
653
654 v = *(uint32_t *)addr;
655
656 *p = addr + sizeof(uint32_t);
657 return ntohl(v);
658 }
659
660 static inline uint8_t read_char_mm(void **p)
661 {
662 uint8_t *addr = *(uint8_t **)p;
663 uint8_t v = *addr;
664 *p = addr + sizeof(uint8_t);
665 return v;
666 }
667
668 static inline char *read_chars_mm(void **p, unsigned *rlen)
669 {
670 char *addr = *(char **)p;
671 size_t len = *rlen = strlen(addr);
672 *p = addr + len + 1;
673 return addr;
674 }
675
676 static struct index_mm_node *index_mm_read_node(struct index_mm *idx,
677 uint32_t offset) {
678 void *p = idx->mm;
679 struct index_mm_node *node;
680 const char *prefix;
681 int i, child_count, value_count, children_padding;
682 uint32_t children[INDEX_CHILDMAX];
683 char first, last;
684
685 if ((offset & INDEX_NODE_MASK) == 0)
686 return NULL;
687
688 p = (char *)p + (offset & INDEX_NODE_MASK);
689
690 if (offset & INDEX_NODE_PREFIX) {
691 unsigned len;
692 prefix = read_chars_mm(&p, &len);
693 } else
694 prefix = _idx_empty_str;
695
696 if (offset & INDEX_NODE_CHILDS) {
697 first = read_char_mm(&p);
698 last = read_char_mm(&p);
699 child_count = last - first + 1;
700 for (i = 0; i < child_count; i++)
701 children[i] = read_long_mm(&p);
702 } else {
703 first = INDEX_CHILDMAX;
704 last = 0;
705 child_count = 0;
706 }
707
708 children_padding = (sizeof(struct index_mm_node) +
709 (sizeof(uint32_t) * child_count)) % sizeof(void *);
710
711 if (offset & INDEX_NODE_VALUES)
712 value_count = read_long_mm(&p);
713 else
714 value_count = 0;
715
716 node = malloc(sizeof(struct index_mm_node)
717 + sizeof(uint32_t) * child_count + children_padding
718 + sizeof(struct index_mm_value) * value_count);
719 if (node == NULL)
720 return NULL;
721
722 node->idx = idx;
723 node->prefix = prefix;
724 if (value_count == 0)
725 node->values.values = NULL;
726 else {
727 node->values.values = (struct index_mm_value *)
728 ((char *)node + sizeof(struct index_mm_node) +
729 sizeof(uint32_t) * child_count + children_padding);
730 }
731 node->values.len = value_count;
732 node->first = first;
733 node->last = last;
734 memcpy(node->children, children, sizeof(uint32_t) * child_count);
735
736 for (i = 0; i < value_count; i++) {
737 struct index_mm_value *v = node->values.values + i;
738 v->priority = read_long_mm(&p);
739 v->value = read_chars_mm(&p, &v->len);
740 }
741
742 return node;
743 }
744
745 static void index_mm_free_node(struct index_mm_node *node)
746 {
747 free(node);
748 }
749
750 struct index_mm *index_mm_open(struct kmod_ctx *ctx, const char *filename,
751 unsigned long long *stamp)
752 {
753 int fd;
754 struct stat st;
755 struct index_mm *idx;
756 struct {
757 uint32_t magic;
758 uint32_t version;
759 uint32_t root_offset;
760 } hdr;
761 void *p;
762
763 DBG(ctx, "file=%s\n", filename);
764
765 idx = malloc(sizeof(*idx));
766 if (idx == NULL) {
767 ERR(ctx, "malloc: %m\n");
768 return NULL;
769 }
770
771 if ((fd = open(filename, O_RDONLY|O_CLOEXEC)) < 0) {
772 DBG(ctx, "open(%s, O_RDONLY|O_CLOEXEC): %m\n", filename);
773 goto fail_open;
774 }
775
776 if (fstat(fd, &st) < 0)
777 goto fail_nommap;
778 if ((size_t) st.st_size < sizeof(hdr))
779 goto fail_nommap;
780
781 if ((idx->mm = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0))
782 == MAP_FAILED) {
783 ERR(ctx, "mmap(NULL, %"PRIu64", PROT_READ, %d, MAP_PRIVATE, 0): %m\n",
784 st.st_size, fd);
785 goto fail_nommap;
786 }
787
788 p = idx->mm;
789 hdr.magic = read_long_mm(&p);
790 hdr.version = read_long_mm(&p);
791 hdr.root_offset = read_long_mm(&p);
792
793 if (hdr.magic != INDEX_MAGIC) {
794 ERR(ctx, "magic check fail: %x instead of %x\n", hdr.magic,
795 INDEX_MAGIC);
796 goto fail;
797 }
798
799 if (hdr.version >> 16 != INDEX_VERSION_MAJOR) {
800 ERR(ctx, "major version check fail: %u instead of %u\n",
801 hdr.version >> 16, INDEX_VERSION_MAJOR);
802 goto fail;
803 }
804
805 idx->root_offset = hdr.root_offset;
806 idx->size = st.st_size;
807 idx->ctx = ctx;
808 close(fd);
809
810 *stamp = stat_mstamp(&st);
811
812 return idx;
813
814 fail:
815 munmap(idx->mm, st.st_size);
816 fail_nommap:
817 close(fd);
818 fail_open:
819 free(idx);
820 return NULL;
821 }
822
823 void index_mm_close(struct index_mm *idx)
824 {
825 munmap(idx->mm, idx->size);
826 free(idx);
827 }
828
829 static struct index_mm_node *index_mm_readroot(struct index_mm *idx)
830 {
831 return index_mm_read_node(idx, idx->root_offset);
832 }
833
834 static struct index_mm_node *index_mm_readchild(const struct index_mm_node *parent,
835 int ch)
836 {
837 if (parent->first <= ch && ch <= parent->last) {
838 return index_mm_read_node(parent->idx,
839 parent->children[ch - parent->first]);
840 }
841
842 return NULL;
843 }
844
845 static void index_mm_dump_node(struct index_mm_node *node, struct strbuf *buf,
846 int fd)
847 {
848 struct index_mm_value *itr, *itr_end;
849 int ch, pushed;
850
851 pushed = strbuf_pushchars(buf, node->prefix);
852
853 itr = node->values.values;
854 itr_end = itr + node->values.len;
855 for (; itr < itr_end; itr++) {
856 write_str_safe(fd, buf->bytes, buf->used);
857 write_str_safe(fd, " ", 1);
858 write_str_safe(fd, itr->value, itr->len);
859 write_str_safe(fd, "\n", 1);
860 }
861
862 for (ch = node->first; ch <= node->last; ch++) {
863 struct index_mm_node *child = index_mm_readchild(node, ch);
864
865 if (child == NULL)
866 continue;
867
868 strbuf_pushchar(buf, ch);
869 index_mm_dump_node(child, buf, fd);
870 strbuf_popchar(buf);
871 }
872
873 strbuf_popchars(buf, pushed);
874 index_mm_free_node(node);
875 }
876
877 void index_mm_dump(struct index_mm *idx, int fd, const char *prefix)
878 {
879 struct index_mm_node *root;
880 struct strbuf buf;
881
882 root = index_mm_readroot(idx);
883 if (root == NULL)
884 return;
885
886 strbuf_init(&buf);
887 strbuf_pushchars(&buf, prefix);
888 index_mm_dump_node(root, &buf, fd);
889 strbuf_release(&buf);
890 }
891
892 static char *index_mm_search_node(struct index_mm_node *node, const char *key,
893 int i)
894 {
895 char *value;
896 struct index_mm_node *child;
897 int ch;
898 int j;
899
900 while(node) {
901 for (j = 0; node->prefix[j]; j++) {
902 ch = node->prefix[j];
903
904 if (ch != key[i+j]) {
905 index_mm_free_node(node);
906 return NULL;
907 }
908 }
909
910 i += j;
911
912 if (key[i] == '\0') {
913 value = node->values.len > 0
914 ? strdup(node->values.values[0].value)
915 : NULL;
916
917 index_mm_free_node(node);
918 return value;
919 }
920
921 child = index_mm_readchild(node, key[i]);
922 index_mm_free_node(node);
923 node = child;
924 i++;
925 }
926
927 return NULL;
928 }
929
930 /*
931 * Search the index for a key
932 *
933 * Returns the value of the first match
934 *
935 * The recursive functions free their node argument (using index_close).
936 */
937 char *index_mm_search(struct index_mm *idx, const char *key)
938 {
939 // FIXME: return value by reference instead of strdup
940 struct index_mm_node *root;
941 char *value;
942
943 root = index_mm_readroot(idx);
944 value = index_mm_search_node(root, key, 0);
945
946 return value;
947 }
948
949 /* Level 4: add all the values from a matching node */
950 static void index_mm_searchwild_allvalues(struct index_mm_node *node,
951 struct index_value **out)
952 {
953 struct index_mm_value *itr, *itr_end;
954
955 itr = node->values.values;
956 itr_end = itr + node->values.len;
957 for (; itr < itr_end; itr++)
958 add_value(out, itr->value, itr->len, itr->priority);
959
960 index_mm_free_node(node);
961 }
962
963 /*
964 * Level 3: traverse a sub-keyspace which starts with a wildcard,
965 * looking for matches.
966 */
967 static void index_mm_searchwild_all(struct index_mm_node *node, int j,
968 struct strbuf *buf,
969 const char *subkey,
970 struct index_value **out)
971 {
972 int pushed = 0;
973 int ch;
974
975 while (node->prefix[j]) {
976 ch = node->prefix[j];
977
978 strbuf_pushchar(buf, ch);
979 pushed++;
980 j++;
981 }
982
983 for (ch = node->first; ch <= node->last; ch++) {
984 struct index_mm_node *child = index_mm_readchild(node, ch);
985
986 if (!child)
987 continue;
988
989 strbuf_pushchar(buf, ch);
990 index_mm_searchwild_all(child, 0, buf, subkey, out);
991 strbuf_popchar(buf);
992 }
993
994 if (node->values.len > 0) {
995 if (fnmatch(strbuf_str(buf), subkey, 0) == 0)
996 index_mm_searchwild_allvalues(node, out);
997 else
998 index_mm_free_node(node);
999 } else {
1000 index_mm_free_node(node);
1001 }
1002
1003 strbuf_popchars(buf, pushed);
1004 }
1005
1006 /* Level 2: descend the tree (until we hit a wildcard) */
1007 static void index_mm_searchwild_node(struct index_mm_node *node,
1008 struct strbuf *buf,
1009 const char *key, int i,
1010 struct index_value **out)
1011 {
1012 struct index_mm_node *child;
1013 int j;
1014 int ch;
1015
1016 while(node) {
1017 for (j = 0; node->prefix[j]; j++) {
1018 ch = node->prefix[j];
1019
1020 if (ch == '*' || ch == '?' || ch == '[') {
1021 index_mm_searchwild_all(node, j, buf,
1022 &key[i+j], out);
1023 return;
1024 }
1025
1026 if (ch != key[i+j]) {
1027 index_mm_free_node(node);
1028 return;
1029 }
1030 }
1031
1032 i += j;
1033
1034 child = index_mm_readchild(node, '*');
1035 if (child) {
1036 strbuf_pushchar(buf, '*');
1037 index_mm_searchwild_all(child, 0, buf, &key[i], out);
1038 strbuf_popchar(buf);
1039 }
1040
1041 child = index_mm_readchild(node, '?');
1042 if (child) {
1043 strbuf_pushchar(buf, '?');
1044 index_mm_searchwild_all(child, 0, buf, &key[i], out);
1045 strbuf_popchar(buf);
1046 }
1047
1048 child = index_mm_readchild(node, '[');
1049 if (child) {
1050 strbuf_pushchar(buf, '[');
1051 index_mm_searchwild_all(child, 0, buf, &key[i], out);
1052 strbuf_popchar(buf);
1053 }
1054
1055 if (key[i] == '\0') {
1056 index_mm_searchwild_allvalues(node, out);
1057
1058 return;
1059 }
1060
1061 child = index_mm_readchild(node, key[i]);
1062 index_mm_free_node(node);
1063 node = child;
1064 i++;
1065 }
1066 }
1067
1068 /*
1069 * Search the index for a key. The index may contain wildcards.
1070 *
1071 * Returns a list of all the values of matching keys.
1072 */
1073 struct index_value *index_mm_searchwild(struct index_mm *idx, const char *key)
1074 {
1075 struct index_mm_node *root = index_mm_readroot(idx);
1076 struct strbuf buf;
1077 struct index_value *out = NULL;
1078
1079 strbuf_init(&buf);
1080 index_mm_searchwild_node(root, &buf, key, 0, &out);
1081 strbuf_release(&buf);
1082 return out;
1083 }
File src/libkmod-index.h added (mode: 100644) (index 0000000..8dc0d0a)
1 #ifndef LIBKMOD_INDEX_H
2 #define LIBKMOD_INDEX_H
3 /*
4 * libkmod - interface to kernel module operations
5 *
6 * Copyright (C) 2011-2013 ProFUSION embedded systems
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #ifdef LIBKMOD_INDEX_C
23 #define EXTERN
24 #else
25 #define EXTERN extern
26 #endif
27
28 struct index_value {
29 struct index_value *next;
30 unsigned int priority;
31 unsigned int len;
32 char value[0];
33 };
34
35 /* In-memory index (depmod only) */
36 struct index_file;
37 EXTERN struct index_file *index_file_open(const char *filename);
38 EXTERN void index_file_close(struct index_file *idx);
39 EXTERN char *index_search(struct index_file *idx, const char *key);
40 EXTERN void index_dump(struct index_file *in, int fd, const char *prefix);
41 EXTERN struct index_value *index_searchwild(struct index_file *idx, const char *key);
42
43 EXTERN void index_values_free(struct index_value *values);
44
45 /* Implementation using mmap */
46 struct index_mm;
47 EXTERN struct index_mm *index_mm_open(struct kmod_ctx *ctx, const char *filename, unsigned long long *stamp);
48 EXTERN void index_mm_close(struct index_mm *index);
49 EXTERN char *index_mm_search(struct index_mm *idx, const char *key);
50 EXTERN struct index_value *index_mm_searchwild(struct index_mm *idx, const char *key);
51 EXTERN void index_mm_dump(struct index_mm *idx, int fd, const char *prefix);
52 #undef EXTERN
53 #endif
File src/libkmod-internal.h added (mode: 100644) (index 0000000..609bc29)
1 #ifndef LIBKMOD_INTERNAL_H
2 #define LIBKMOD_INTERNAL_H
3
4 _unused_ static void kmod_log_null(struct kmod_ctx *ctx, const char *format, ...) {}
5
6 #define kmod_log_cond(ctx, prio, arg...) \
7 do { \
8 if (kmod_get_log_priority(ctx) >= prio) \
9 kmod_log(ctx, prio, __FILE__, __LINE__, __func__, ## arg);\
10 } while (0)
11
12 #ifdef ENABLE_LOGGING
13 # ifdef ENABLE_DEBUG
14 # define DBG(ctx, arg...) kmod_log_cond(ctx, LOG_DEBUG, ## arg)
15 # else
16 # define DBG(ctx, arg...) kmod_log_null(ctx, ## arg)
17 # endif
18 # define INFO(ctx, arg...) kmod_log_cond(ctx, LOG_INFO, ## arg)
19 # define ERR(ctx, arg...) kmod_log_cond(ctx, LOG_ERR, ## arg)
20 #else
21 # define DBG(ctx, arg...) kmod_log_null(ctx, ## arg)
22 # define INFO(ctx, arg...) kmod_log_null(ctx, ## arg)
23 # define ERR(ctx, arg...) kmod_log_null(ctx, ## arg)
24 #endif
25
26 #define KCMD_LINE_SIZE 4096
27
28
29
30
31 /*---------------------------------------------------------------------------*/
32 #ifdef LIBKMOD_C
33 #define EXTERN
34 #else
35 #define EXTERN extern
36 #endif
37 EXTERN void kmod_log(const struct kmod_ctx *ctx, int priority, const char *file, int line, const char *fn, const char *format, ...);
38 #undef EXTERN
39 /*---------------------------------------------------------------------------*/
40
41
42
43
44 /*---------------------------------------------------------------------------*/
45 #ifdef LIBKMOD_LIST_C
46 #define EXTERN
47 #else
48 #define EXTERN extern
49 #endif
50 struct list_node {
51 struct list_node *next, *prev;
52 };
53
54 struct kmod_list {
55 struct list_node node;
56 void *data;
57 };
58
59 /* this internal needs to be accessed by the kmod tools, it's exported */
60 EXTERN struct kmod_list *__kmod_list_append(struct kmod_list *list, const void *data);
61 EXTERN struct kmod_list *kmod_list_prepend(struct kmod_list *list, const void *data);
62 /* those internals need to be accessed by the kmod tools, they are exported */
63 EXTERN struct kmod_list *__kmod_list_remove(struct kmod_list *list);
64 EXTERN struct kmod_list *__kmod_list_remove_data(struct kmod_list *list, const void *data);
65 EXTERN struct kmod_list *kmod_list_remove_n_latest(struct kmod_list *list, unsigned int n);
66 EXTERN struct kmod_list *kmod_list_insert_after(struct kmod_list *list, const void *data);
67 EXTERN struct kmod_list *kmod_list_insert_before(struct kmod_list *list, const void *data);
68 EXTERN struct kmod_list *kmod_list_append_list(struct kmod_list *list1, struct kmod_list *list2);
69
70 #undef kmod_list_foreach
71 #define kmod_list_foreach(list_entry, first_entry) \
72 for (list_entry = ((first_entry) == NULL) ? NULL : (first_entry); \
73 list_entry != NULL; \
74 list_entry = (list_entry->node.next == &((first_entry)->node)) ? NULL : \
75 container_of(list_entry->node.next, struct kmod_list, node))
76
77 #undef kmod_list_foreach_reverse
78 #define kmod_list_foreach_reverse(list_entry, first_entry) \
79 for (list_entry = (((first_entry) == NULL) ? NULL : container_of(first_entry->node.prev, struct kmod_list, node)); \
80 list_entry != NULL; \
81 list_entry = ((list_entry == first_entry) ? NULL : \
82 container_of(list_entry->node.prev, struct kmod_list, node)))
83 #undef EXTERN
84 /*---------------------------------------------------------------------------*/
85
86
87
88
89 /*---------------------------------------------------------------------------*/
90 #ifdef LIBKMOD_C
91 #define EXTERN
92 #else
93 #define EXTERN extern
94 #endif
95 /* libkmod.c */
96 EXTERN int kmod_lookup_alias_from_config(struct kmod_ctx *ctx, const char *name, struct kmod_list **list);
97 EXTERN int kmod_lookup_alias_from_symbols_file(struct kmod_ctx *ctx, const char *name, struct kmod_list **list);
98 EXTERN int kmod_lookup_alias_from_aliases_file(struct kmod_ctx *ctx, const char *name, struct kmod_list **list);
99 EXTERN int kmod_lookup_alias_from_moddep_file(struct kmod_ctx *ctx, const char *name, struct kmod_list **list);
100 EXTERN int kmod_lookup_alias_from_builtin_file(struct kmod_ctx *ctx, const char *name, struct kmod_list **list);
101 EXTERN bool kmod_lookup_alias_is_builtin(struct kmod_ctx *ctx, const char *name);
102 EXTERN int kmod_lookup_alias_from_commands(struct kmod_ctx *ctx, const char *name, struct kmod_list **list);
103 EXTERN void kmod_set_modules_visited(struct kmod_ctx *ctx, bool visited);
104 EXTERN void kmod_set_modules_required(struct kmod_ctx *ctx, bool required);
105
106 EXTERN char *kmod_search_moddep(struct kmod_ctx *ctx, const char *name);
107
108 EXTERN struct kmod_module *kmod_pool_get_module(struct kmod_ctx *ctx, const char *key);
109 EXTERN void kmod_pool_add_module(struct kmod_ctx *ctx, struct kmod_module *mod, const char *key);
110 EXTERN void kmod_pool_del_module(struct kmod_ctx *ctx, struct kmod_module *mod, const char *key);
111 #undef EXTERN
112 /*---------------------------------------------------------------------------*/
113
114
115
116
117 /*---------------------------------------------------------------------------*/
118 #ifdef LIBKMOD_CONFIG_C
119 #define EXTERN
120 #else
121 #define EXTERN extern
122 #endif
123 const struct kmod_config *kmod_get_config(const struct kmod_ctx *ctx);
124
125 /* libkmod-config.c */
126 struct kmod_config_path {
127 unsigned long long stamp;
128 char path[];
129 };
130
131 struct kmod_config {
132 struct kmod_ctx *ctx;
133 struct kmod_list *aliases;
134 struct kmod_list *blacklists;
135 struct kmod_list *options;
136 struct kmod_list *remove_commands;
137 struct kmod_list *install_commands;
138 struct kmod_list *softdeps;
139
140 struct kmod_list *paths;
141 };
142
143 EXTERN int kmod_config_new(struct kmod_ctx *ctx, struct kmod_config **config, const char * const *config_paths);
144 EXTERN void kmod_config_free(struct kmod_config *config);
145 EXTERN const char *kmod_blacklist_get_modname(const struct kmod_list *l);
146 EXTERN const char *kmod_alias_get_name(const struct kmod_list *l);
147 EXTERN const char *kmod_alias_get_modname(const struct kmod_list *l);
148 EXTERN const char *kmod_option_get_options(const struct kmod_list *l);
149 EXTERN const char *kmod_option_get_modname(const struct kmod_list *l);
150 EXTERN const char *kmod_command_get_command(const struct kmod_list *l);
151 EXTERN const char *kmod_command_get_modname(const struct kmod_list *l);
152
153 EXTERN const char *kmod_softdep_get_name(const struct kmod_list *l);
154 EXTERN const char * const *kmod_softdep_get_pre(const struct kmod_list *l, unsigned int *count);
155 EXTERN const char * const *kmod_softdep_get_post(const struct kmod_list *l, unsigned int *count);
156 #undef EXTERN
157 /*---------------------------------------------------------------------------*/
158
159
160
161
162 /*---------------------------------------------------------------------------*/
163 #ifdef LIBKMOD_MODULE_C
164 #define EXTERN
165 #else
166 #define EXTERN extern
167 #endif
168 /* libkmod-module.c */
169 EXTERN int kmod_module_new_from_alias(struct kmod_ctx *ctx, const char *alias, const char *name, struct kmod_module **mod);
170 EXTERN int kmod_module_parse_depline(struct kmod_module *mod, char *line);
171 EXTERN void kmod_module_set_install_commands(struct kmod_module *mod, const char *cmd);
172 EXTERN void kmod_module_set_remove_commands(struct kmod_module *mod, const char *cmd);
173 EXTERN void kmod_module_set_visited(struct kmod_module *mod, bool visited);
174 EXTERN void kmod_module_set_builtin(struct kmod_module *mod, bool builtin);
175 EXTERN void kmod_module_set_required(struct kmod_module *mod, bool required);
176 EXTERN bool kmod_module_is_builtin(struct kmod_module *mod);
177 #undef EXTERN
178 /*---------------------------------------------------------------------------*/
179
180
181
182
183 /*---------------------------------------------------------------------------*/
184 #ifdef LIBKMOD_FILE_C
185 #define EXTERN
186 #else
187 #define EXTERN extern
188 #endif
189 EXTERN struct kmod_file *kmod_file_open(const struct kmod_ctx *ctx, const char *filename);
190 EXTERN struct kmod_elf *kmod_file_get_elf(struct kmod_file *file);
191 EXTERN void *kmod_file_get_contents(const struct kmod_file *file);
192 EXTERN off_t kmod_file_get_size(const struct kmod_file *file);
193 EXTERN bool kmod_file_get_direct(const struct kmod_file *file);
194 EXTERN int kmod_file_get_fd(const struct kmod_file *file);
195 EXTERN void kmod_file_unref(struct kmod_file *file);
196 #undef EXTERN
197 /*---------------------------------------------------------------------------*/
198
199
200
201
202 /*---------------------------------------------------------------------------*/
203 #ifdef LIBKMOD_ELF_C
204 #define EXTERN
205 #else
206 #define EXTERN extern
207 #endif
208 struct kmod_elf;
209 struct kmod_modversion {
210 uint64_t crc;
211 enum kmod_symbol_bind bind;
212 char *symbol;
213 };
214
215 EXTERN struct kmod_elf *kmod_elf_new(const void *memory, off_t size);
216 EXTERN void kmod_elf_unref(struct kmod_elf *elf);
217 EXTERN const void *kmod_elf_get_memory(const struct kmod_elf *elf);
218 EXTERN int kmod_elf_get_strings(const struct kmod_elf *elf, const char *section, char ***array);
219 EXTERN int kmod_elf_get_modversions(const struct kmod_elf *elf, struct kmod_modversion **array);
220 EXTERN int kmod_elf_get_symbols(const struct kmod_elf *elf, struct kmod_modversion **array);
221 EXTERN int kmod_elf_get_dependency_symbols(const struct kmod_elf *elf, struct kmod_modversion **array);
222 EXTERN int kmod_elf_strip_section(struct kmod_elf *elf, const char *section);
223 EXTERN int kmod_elf_strip_vermagic(struct kmod_elf *elf);
224
225 /*
226 * Debug mock lib need to find section ".gnu.linkonce.this_module" in order to
227 * get modname
228 */
229 EXTERN int kmod_elf_get_section(const struct kmod_elf *elf, const char *section, const void **buf, uint64_t *buf_size);
230 #undef EXTERN
231 /*---------------------------------------------------------------------------*/
232
233
234
235
236 /*---------------------------------------------------------------------------*/
237 #ifdef LIBKMOD_SIGNATURE_C
238 #define EXTERN
239 #else
240 #define EXTERN extern
241 #endif
242 struct kmod_signature_info {
243 const char *signer;
244 size_t signer_len;
245 const char *key_id;
246 size_t key_id_len;
247 const char *algo, *hash_algo, *id_type;
248 };
249 EXTERN bool kmod_module_signature_info(const struct kmod_file *file, struct kmod_signature_info *sig_info);
250 #undef EXTERN
251 /*---------------------------------------------------------------------------*/
252 #endif
File src/libkmod-list.c added (mode: 100644) (index 0000000..ec74edd)
1 /*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <stdlib.h>
21 #include <stddef.h>
22 #include <limits.h>
23 #include <stdio.h>
24 #include <errno.h>
25
26 #include "config.h"
27
28 #include "libkmod.h"
29 #include "libkmod-namespace.h"
30 #include "libkmod-paths.h"
31 #include "shared/macro.h"
32 #include "shared/util.h"
33 #define LIBKMOD_LIST_C
34 #include "libkmod-internal.h"
35 #undef LIBKMOD_LIST_C
36
37 /**
38 * SECTION:libkmod-list
39 * @short_description: general purpose list
40 */
41
42 static inline struct list_node *list_node_init(struct list_node *node)
43 {
44 node->next = node;
45 node->prev = node;
46
47 return node;
48 }
49
50 static inline void list_node_append(struct list_node *list,
51 struct list_node *node)
52 {
53 if (list == NULL) {
54 list_node_init(node);
55 return;
56 }
57
58 node->prev = list->prev;
59 list->prev->next = node;
60 list->prev = node;
61 node->next = list;
62 }
63
64 static inline struct list_node *list_node_remove(struct list_node *node)
65 {
66 if (node->prev == node || node->next == node)
67 return NULL;
68
69 node->prev->next = node->next;
70 node->next->prev = node->prev;
71
72 return node->next;
73 }
74
75 static inline void list_node_insert_after(struct list_node *list,
76 struct list_node *node)
77 {
78 if (list == NULL) {
79 list_node_init(node);
80 return;
81 }
82
83 node->prev = list;
84 node->next = list->next;
85 list->next->prev = node;
86 list->next = node;
87 }
88
89 static inline void list_node_insert_before(struct list_node *list,
90 struct list_node *node)
91 {
92 if (list == NULL) {
93 list_node_init(node);
94 return;
95 }
96
97 node->next = list;
98 node->prev = list->prev;
99 list->prev->next = node;
100 list->prev = node;
101 }
102
103 static inline void list_node_append_list(struct list_node *list1,
104 struct list_node *list2)
105 {
106 struct list_node *list1_last;
107
108 if (list1 == NULL) {
109 list_node_init(list2);
110 return;
111 }
112
113 list1->prev->next = list2;
114 list2->prev->next = list1;
115
116 /* cache the last, because we will lose the pointer */
117 list1_last = list1->prev;
118
119 list1->prev = list2->prev;
120 list2->prev = list1_last;
121 }
122
123 struct kmod_list *__kmod_list_append(struct kmod_list *list, const void *data)
124 {
125 struct kmod_list *new;
126
127 new = malloc(sizeof(*new));
128 if (new == NULL)
129 return NULL;
130
131 new->data = (void *)data;
132 list_node_append(list ? &list->node : NULL, &new->node);
133
134 return list ? list : new;
135 }
136
137 struct kmod_list *kmod_list_insert_after(struct kmod_list *list,
138 const void *data)
139 {
140 struct kmod_list *new;
141
142 if (list == NULL)
143 return __kmod_list_append(list, data);
144
145 new = malloc(sizeof(*new));
146 if (new == NULL)
147 return NULL;
148
149 new->data = (void *)data;
150 list_node_insert_after(&list->node, &new->node);
151
152 return list;
153 }
154
155 struct kmod_list *kmod_list_insert_before(struct kmod_list *list,
156 const void *data)
157 {
158 struct kmod_list *new;
159
160 if (list == NULL)
161 return __kmod_list_append(list, data);
162
163 new = malloc(sizeof(*new));
164 if (new == NULL)
165 return NULL;
166
167 new->data = (void *)data;
168 list_node_insert_before(&list->node, &new->node);
169
170 return new;
171 }
172
173 struct kmod_list *kmod_list_append_list(struct kmod_list *list1,
174 struct kmod_list *list2)
175 {
176 if (list1 == NULL)
177 return list2;
178
179 if (list2 == NULL)
180 return list1;
181
182 list_node_append_list(&list1->node, &list2->node);
183
184 return list1;
185 }
186
187 struct kmod_list *kmod_list_prepend(struct kmod_list *list, const void *data)
188 {
189 struct kmod_list *new;
190
191 new = malloc(sizeof(*new));
192 if (new == NULL)
193 return NULL;
194
195 new->data = (void *)data;
196 list_node_append(list ? &list->node : NULL, &new->node);
197
198 return new;
199 }
200
201 struct kmod_list *__kmod_list_remove(struct kmod_list *list)
202 {
203 struct list_node *node;
204
205 if (list == NULL)
206 return NULL;
207
208 node = list_node_remove(&list->node);
209 free(list);
210
211 if (node == NULL)
212 return NULL;
213
214 return container_of(node, struct kmod_list, node);
215 }
216
217 struct kmod_list *__kmod_list_remove_data(struct kmod_list *list,
218 const void *data)
219 {
220 struct kmod_list *itr;
221 struct list_node *node;
222
223 for (itr = list; itr != NULL; itr = kmod_list_next(list, itr)) {
224 if (itr->data == data)
225 break;
226 }
227
228 if (itr == NULL)
229 return list;
230
231 node = list_node_remove(&itr->node);
232 free(itr);
233
234 if (node == NULL)
235 return NULL;
236
237 return container_of(node, struct kmod_list, node);
238 }
239
240 /*
241 * n must be greater to or equal the number of elements (we don't check the
242 * condition)
243 */
244 struct kmod_list *kmod_list_remove_n_latest(struct kmod_list *list,
245 unsigned int n)
246 {
247 struct kmod_list *l = list;
248 unsigned int i;
249
250 for (i = 0; i < n; i++) {
251 l = kmod_list_last(l);
252 l = __kmod_list_remove(l);
253 }
254
255 return l;
256 }
257
258 /**
259 * kmod_list_prev:
260 * @list: the head of the list
261 * @curr: the current node in the list
262 *
263 * Get the previous node in @list relative to @curr as if @list was not a
264 * circular list. I.e.: the previous of the head is NULL. It can be used to
265 * iterate a list by checking for NULL return to know when all elements were
266 * iterated.
267 *
268 * Returns: node previous to @curr or NULL if either this node is the head of
269 * the list or the list is empty.
270 */
271 struct kmod_list *kmod_list_prev(const struct kmod_list *list,
272 const struct kmod_list *curr)
273 {
274 if (list == NULL || curr == NULL)
275 return NULL;
276
277 if (list == curr)
278 return NULL;
279
280 return container_of(curr->node.prev, struct kmod_list, node);
281 }
282
283 /**
284 * kmod_list_next:
285 * @list: the head of the list
286 * @curr: the current node in the list
287 *
288 * Get the next node in @list relative to @curr as if @list was not a circular
289 * list. I.e. calling this function in the last node of the list returns
290 * NULL.. It can be used to iterate a list by checking for NULL return to know
291 * when all elements were iterated.
292 *
293 * Returns: node next to @curr or NULL if either this node is the last of or
294 * list is empty.
295 */
296 struct kmod_list *kmod_list_next(const struct kmod_list *list,
297 const struct kmod_list *curr)
298 {
299 if (list == NULL || curr == NULL)
300 return NULL;
301
302 if (curr->node.next == &list->node)
303 return NULL;
304
305 return container_of(curr->node.next, struct kmod_list, node);
306 }
307
308 /**
309 * kmod_list_last:
310 * @list: the head of the list
311 *
312 * Get the last element of the @list. As @list is a circular list,
313 * this is a cheap operation O(1) with the last element being the
314 * previous element.
315 *
316 * If the list has a single element it will return the list itself (as
317 * expected, and this is what differentiates from kmod_list_prev()).
318 *
319 * Returns: last node at @list or NULL if the list is empty.
320 */
321 struct kmod_list *kmod_list_last(const struct kmod_list *list)
322 {
323 if (list == NULL)
324 return NULL;
325 return container_of(list->node.prev, struct kmod_list, node);
326 }
File src/libkmod-module.c added (mode: 100644) (index 0000000..a632059)
1 /*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <assert.h>
21 #include <ctype.h>
22 #include <dirent.h>
23 #include <errno.h>
24 #include <fnmatch.h>
25 #include <inttypes.h>
26 #include <limits.h>
27 #include <stdarg.h>
28 #include <stddef.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <syslog.h>
34 #include <sys/mman.h>
35 #include <sys/stat.h>
36 #include <sys/syscall.h>
37 #include <sys/types.h>
38 #include <sys/wait.h>
39 #include <linux/module.h>
40
41 #include "config.h"
42
43 #include "libkmod.h"
44 #include "libkmod-namespace.h"
45 #include "libkmod-paths.h"
46 #include "shared/linux-syscalls.h"
47 #include "shared/macro.h"
48 #include "shared/util.h"
49 #define LIBKMOD_MODULE_C
50 #include "libkmod-internal.h"
51 #undef LIBKMOD_MODULE_C
52
53 /**
54 * SECTION:libkmod-module
55 * @short_description: operate on kernel modules
56 */
57
58 enum kmod_module_builtin {
59 KMOD_MODULE_BUILTIN_UNKNOWN,
60 KMOD_MODULE_BUILTIN_NO,
61 KMOD_MODULE_BUILTIN_YES,
62 };
63
64 /**
65 * kmod_module:
66 *
67 * Opaque object representing a module.
68 */
69 struct kmod_module {
70 struct kmod_ctx *ctx;
71 char *hashkey;
72 char *name;
73 char *path;
74 struct kmod_list *dep;
75 char *options;
76 const char *install_commands; /* owned by kmod_config */
77 const char *remove_commands; /* owned by kmod_config */
78 char *alias; /* only set if this module was created from an alias */
79 struct kmod_file *file;
80 int n_dep;
81 int refcount;
82 struct {
83 bool dep : 1;
84 bool options : 1;
85 bool install_commands : 1;
86 bool remove_commands : 1;
87 } init;
88
89 /*
90 * mark if module is builtin, i.e. it's present on modules.builtin
91 * file. This is set as soon as it is needed or as soon as we know
92 * about it, i.e. the module was created from builtin lookup.
93 */
94 enum kmod_module_builtin builtin;
95
96 /*
97 * private field used by kmod_module_get_probe_list() to detect
98 * dependency loops
99 */
100 bool visited : 1;
101
102 /*
103 * set by kmod_module_get_probe_list: indicates for probe_insert()
104 * whether the module's command and softdep should be ignored
105 */
106 bool ignorecmd : 1;
107
108 /*
109 * set by kmod_module_get_probe_list: indicates whether this is the
110 * module the user asked for or its dependency, or whether this
111 * is a softdep only
112 */
113 bool required : 1;
114 };
115
116 static inline const char *path_join(const char *path, size_t prefixlen,
117 char buf[PATH_MAX])
118 {
119 size_t pathlen;
120
121 if (path[0] == '/')
122 return path;
123
124 pathlen = strlen(path);
125 if (prefixlen + pathlen + 1 >= PATH_MAX)
126 return NULL;
127
128 memcpy(buf + prefixlen, path, pathlen + 1);
129 return buf;
130 }
131
132 static inline bool module_is_inkernel(struct kmod_module *mod)
133 {
134 int state = kmod_module_get_initstate(mod);
135
136 if (state == KMOD_MODULE_LIVE ||
137 state == KMOD_MODULE_BUILTIN)
138 return true;
139
140 return false;
141 }
142
143 int kmod_module_parse_depline(struct kmod_module *mod, char *line)
144 {
145 struct kmod_ctx *ctx = mod->ctx;
146 struct kmod_list *list = NULL;
147 const char *dirname;
148 char buf[PATH_MAX];
149 char *p, *saveptr;
150 int err = 0, n = 0;
151 size_t dirnamelen;
152
153 if (mod->init.dep)
154 return mod->n_dep;
155 assert(mod->dep == NULL);
156 mod->init.dep = true;
157
158 p = strchr(line, ':');
159 if (p == NULL)
160 return 0;
161
162 *p = '\0';
163 dirname = kmod_get_dirname(mod->ctx);
164 dirnamelen = strlen(dirname);
165 if (dirnamelen + 2 >= PATH_MAX)
166 return 0;
167
168 memcpy(buf, dirname, dirnamelen);
169 buf[dirnamelen] = '/';
170 dirnamelen++;
171 buf[dirnamelen] = '\0';
172
173 if (mod->path == NULL) {
174 const char *str = path_join(line, dirnamelen, buf);
175 if (str == NULL)
176 return 0;
177 mod->path = strdup(str);
178 if (mod->path == NULL)
179 return 0;
180 }
181
182 p++;
183 for (p = strtok_r(p, " \t", &saveptr); p != NULL;
184 p = strtok_r(NULL, " \t", &saveptr)) {
185 struct kmod_module *depmod = NULL;
186 const char *path;
187
188 path = path_join(p, dirnamelen, buf);
189 if (path == NULL) {
190 ERR(ctx, "could not join path '%s' and '%s'.\n",
191 dirname, p);
192 goto fail;
193 }
194
195 err = kmod_module_new_from_path(ctx, path, &depmod);
196 if (err < 0) {
197 ERR(ctx, "ctx=%p path=%s error=%s\n",
198 ctx, path, strerror(-err));
199 goto fail;
200 }
201
202 DBG(ctx, "add dep: %s\n", path);
203
204 list = kmod_list_prepend(list, depmod);
205 n++;
206 }
207
208 DBG(ctx, "%d dependencies for %s\n", n, mod->name);
209
210 mod->dep = list;
211 mod->n_dep = n;
212 return n;
213
214 fail:
215 kmod_module_unref_list(list);
216 mod->init.dep = false;
217 return err;
218 }
219
220 void kmod_module_set_visited(struct kmod_module *mod, bool visited)
221 {
222 mod->visited = visited;
223 }
224
225 void kmod_module_set_builtin(struct kmod_module *mod, bool builtin)
226 {
227 mod->builtin =
228 builtin ? KMOD_MODULE_BUILTIN_YES : KMOD_MODULE_BUILTIN_NO;
229 }
230
231 void kmod_module_set_required(struct kmod_module *mod, bool required)
232 {
233 mod->required = required;
234 }
235
236 bool kmod_module_is_builtin(struct kmod_module *mod)
237 {
238 if (mod->builtin == KMOD_MODULE_BUILTIN_UNKNOWN) {
239 kmod_module_set_builtin(mod,
240 kmod_lookup_alias_is_builtin(mod->ctx, mod->name));
241 }
242
243 return mod->builtin == KMOD_MODULE_BUILTIN_YES;
244 }
245 /*
246 * Memory layout with alias:
247 *
248 * struct kmod_module {
249 * hashkey -----.
250 * alias -----. |
251 * name ----. | |
252 * } | | |
253 * name <----------' | |
254 * alias <-----------' |
255 * name\alias <--------'
256 *
257 * Memory layout without alias:
258 *
259 * struct kmod_module {
260 * hashkey ---.
261 * alias -----|----> NULL
262 * name ----. |
263 * } | |
264 * name <----------'-'
265 *
266 * @key is "name\alias" or "name" (in which case alias == NULL)
267 */
268 static int kmod_module_new(struct kmod_ctx *ctx, const char *key,
269 const char *name, size_t namelen,
270 const char *alias, size_t aliaslen,
271 struct kmod_module **mod)
272 {
273 struct kmod_module *m;
274 size_t keylen;
275
276 m = kmod_pool_get_module(ctx, key);
277 if (m != NULL) {
278 *mod = kmod_module_ref(m);
279 return 0;
280 }
281
282 if (alias == NULL)
283 keylen = namelen;
284 else
285 keylen = namelen + aliaslen + 1;
286
287 m = malloc(sizeof(*m) + (alias == NULL ? 1 : 2) * (keylen + 1));
288 if (m == NULL)
289 return -ENOMEM;
290
291 memset(m, 0, sizeof(*m));
292
293 m->ctx = kmod_ref(ctx);
294 m->name = (char *)m + sizeof(*m);
295 memcpy(m->name, key, keylen + 1);
296 if (alias == NULL) {
297 m->hashkey = m->name;
298 m->alias = NULL;
299 } else {
300 m->name[namelen] = '\0';
301 m->alias = m->name + namelen + 1;
302 m->hashkey = m->name + keylen + 1;
303 memcpy(m->hashkey, key, keylen + 1);
304 }
305
306 m->refcount = 1;
307 kmod_pool_add_module(ctx, m, m->hashkey);
308 *mod = m;
309
310 return 0;
311 }
312
313 /**
314 * kmod_module_new_from_name:
315 * @ctx: kmod library context
316 * @name: name of the module
317 * @mod: where to save the created struct kmod_module
318 *
319 * Create a new struct kmod_module using the module name. @name can not be an
320 * alias, file name or anything else; it must be a module name. There's no
321 * check if the module exists in the system.
322 *
323 * This function is also used internally by many others that return a new
324 * struct kmod_module or a new list of modules.
325 *
326 * The initial refcount is 1, and needs to be decremented to release the
327 * resources of the kmod_module. Since libkmod keeps track of all
328 * kmod_modules created, they are all released upon @ctx destruction too. Do
329 * not unref @ctx before all the desired operations with the returned
330 * kmod_module are done.
331 *
332 * Returns: 0 on success or < 0 otherwise. It fails if name is not a valid
333 * module name or if memory allocation failed.
334 */
335 int kmod_module_new_from_name(struct kmod_ctx *ctx,
336 const char *name,
337 struct kmod_module **mod)
338 {
339 size_t namelen;
340 char name_norm[PATH_MAX];
341
342 if (ctx == NULL || name == NULL || mod == NULL)
343 return -ENOENT;
344
345 modname_normalize(name, name_norm, &namelen);
346
347 return kmod_module_new(ctx, name_norm, name_norm, namelen, NULL, 0, mod);
348 }
349
350 int kmod_module_new_from_alias(struct kmod_ctx *ctx, const char *alias,
351 const char *name, struct kmod_module **mod)
352 {
353 int err;
354 char key[PATH_MAX];
355 size_t namelen = strlen(name);
356 size_t aliaslen = strlen(alias);
357
358 if (namelen + aliaslen + 2 > PATH_MAX)
359 return -ENAMETOOLONG;
360
361 memcpy(key, name, namelen);
362 memcpy(key + namelen + 1, alias, aliaslen + 1);
363 key[namelen] = '\\';
364
365 err = kmod_module_new(ctx, key, name, namelen, alias, aliaslen, mod);
366 if (err < 0)
367 return err;
368
369 return 0;
370 }
371
372 /**
373 * kmod_module_new_from_path:
374 * @ctx: kmod library context
375 * @path: path where to find the given module
376 * @mod: where to save the created struct kmod_module
377 *
378 * Create a new struct kmod_module using the module path. @path must be an
379 * existent file with in the filesystem and must be accessible to libkmod.
380 *
381 * The initial refcount is 1, and needs to be decremented to release the
382 * resources of the kmod_module. Since libkmod keeps track of all
383 * kmod_modules created, they are all released upon @ctx destruction too. Do
384 * not unref @ctx before all the desired operations with the returned
385 * kmod_module are done.
386 *
387 * If @path is relative, it's treated as relative to the current working
388 * directory. Otherwise, give an absolute path.
389 *
390 * Returns: 0 on success or < 0 otherwise. It fails if file does not exist, if
391 * it's not a valid file for a kmod_module or if memory allocation failed.
392 */
393 int kmod_module_new_from_path(struct kmod_ctx *ctx,
394 const char *path,
395 struct kmod_module **mod)
396 {
397 struct kmod_module *m;
398 int err;
399 struct stat st;
400 char name[PATH_MAX];
401 char *abspath;
402 size_t namelen;
403
404 if (ctx == NULL || path == NULL || mod == NULL)
405 return -ENOENT;
406
407 abspath = path_make_absolute_cwd(path);
408 if (abspath == NULL) {
409 DBG(ctx, "no absolute path for %s\n", path);
410 return -ENOMEM;
411 }
412
413 err = stat(abspath, &st);
414 if (err < 0) {
415 err = -errno;
416 DBG(ctx, "stat %s: %s\n", path, strerror(errno));
417 free(abspath);
418 return err;
419 }
420
421 if (path_to_modname(path, name, &namelen) == NULL) {
422 DBG(ctx, "could not get modname from path %s\n", path);
423 free(abspath);
424 return -ENOENT;
425 }
426
427 m = kmod_pool_get_module(ctx, name);
428 if (m != NULL) {
429 if (m->path == NULL)
430 m->path = abspath;
431 else if (streq(m->path, abspath))
432 free(abspath);
433 else {
434 ERR(ctx, "kmod_module '%s' already exists with different path: new-path='%s' old-path='%s'\n",
435 name, abspath, m->path);
436 free(abspath);
437 return -EEXIST;
438 }
439
440 *mod = kmod_module_ref(m);
441 return 0;
442 }
443
444 err = kmod_module_new(ctx, name, name, namelen, NULL, 0, &m);
445 if (err < 0) {
446 free(abspath);
447 return err;
448 }
449
450 m->path = abspath;
451 *mod = m;
452
453 return 0;
454 }
455
456 /**
457 * kmod_module_unref:
458 * @mod: kmod module
459 *
460 * Drop a reference of the kmod module. If the refcount reaches zero, its
461 * resources are released.
462 *
463 * Returns: NULL if @mod is NULL or if the module was released. Otherwise it
464 * returns the passed @mod with its refcount decremented.
465 */
466 struct kmod_module *kmod_module_unref(struct kmod_module *mod)
467 {
468 if (mod == NULL)
469 return NULL;
470
471 if (--mod->refcount > 0)
472 return mod;
473
474 DBG(mod->ctx, "kmod_module %p released\n", mod);
475
476 kmod_pool_del_module(mod->ctx, mod, mod->hashkey);
477 kmod_module_unref_list(mod->dep);
478
479 if (mod->file)
480 kmod_file_unref(mod->file);
481
482 kmod_unref(mod->ctx);
483 free(mod->options);
484 free(mod->path);
485 free(mod);
486 return NULL;
487 }
488
489 /**
490 * kmod_module_ref:
491 * @mod: kmod module
492 *
493 * Take a reference of the kmod module, incrementing its refcount.
494 *
495 * Returns: the passed @module with its refcount incremented.
496 */
497 struct kmod_module *kmod_module_ref(struct kmod_module *mod)
498 {
499 if (mod == NULL)
500 return NULL;
501
502 mod->refcount++;
503
504 return mod;
505 }
506
507 #define CHECK_ERR_AND_FINISH(_err, _label_err, _list, label_finish) \
508 do { \
509 if ((_err) < 0) \
510 goto _label_err; \
511 if (*(_list) != NULL) \
512 goto finish; \
513 } while (0)
514
515 /**
516 * kmod_module_new_from_lookup:
517 * @ctx: kmod library context
518 * @given_alias: alias to look for
519 * @list: an empty list where to save the list of modules matching
520 * @given_alias
521 *
522 * Create a new list of kmod modules using an alias or module name and lookup
523 * libkmod's configuration files and indexes in order to find the module.
524 * Once it's found in one of the places, it stops searching and create the
525 * list of modules that is saved in @list.
526 *
527 * The search order is: 1. aliases in configuration file; 2. module names in
528 * modules.dep index; 3. symbol aliases in modules.symbols index; 4. aliases
529 * in modules.alias index.
530 *
531 * The initial refcount is 1, and needs to be decremented to release the
532 * resources of the kmod_module. The returned @list must be released by
533 * calling kmod_module_unref_list(). Since libkmod keeps track of all
534 * kmod_modules created, they are all released upon @ctx destruction too. Do
535 * not unref @ctx before all the desired operations with the returned list are
536 * completed.
537 *
538 * Returns: 0 on success or < 0 otherwise. It fails if any of the lookup
539 * methods failed, which is basically due to memory allocation fail. If module
540 * is not found, it still returns 0, but @list is an empty list.
541 */
542 int kmod_module_new_from_lookup(struct kmod_ctx *ctx,
543 const char *given_alias,
544 struct kmod_list **list)
545 {
546 int err;
547 char alias[PATH_MAX];
548
549 if (ctx == NULL || given_alias == NULL)
550 return -ENOENT;
551
552 if (list == NULL || *list != NULL) {
553 ERR(ctx, "An empty list is needed to create lookup\n");
554 return -ENOSYS;
555 }
556
557 if (alias_normalize(given_alias, alias, NULL) < 0) {
558 DBG(ctx, "invalid alias: %s\n", given_alias);
559 return -EINVAL;
560 }
561
562 DBG(ctx, "input alias=%s, normalized=%s\n", given_alias, alias);
563
564 /* Aliases from config file override all the others */
565 err = kmod_lookup_alias_from_config(ctx, alias, list);
566 CHECK_ERR_AND_FINISH(err, fail, list, finish);
567
568 DBG(ctx, "lookup modules.dep %s\n", alias);
569 err = kmod_lookup_alias_from_moddep_file(ctx, alias, list);
570 CHECK_ERR_AND_FINISH(err, fail, list, finish);
571
572 DBG(ctx, "lookup modules.symbols %s\n", alias);
573 err = kmod_lookup_alias_from_symbols_file(ctx, alias, list);
574 CHECK_ERR_AND_FINISH(err, fail, list, finish);
575
576 DBG(ctx, "lookup install and remove commands %s\n", alias);
577 err = kmod_lookup_alias_from_commands(ctx, alias, list);
578 CHECK_ERR_AND_FINISH(err, fail, list, finish);
579
580 DBG(ctx, "lookup modules.aliases %s\n", alias);
581 err = kmod_lookup_alias_from_aliases_file(ctx, alias, list);
582 CHECK_ERR_AND_FINISH(err, fail, list, finish);
583
584 DBG(ctx, "lookup modules.builtin %s\n", alias);
585 err = kmod_lookup_alias_from_builtin_file(ctx, alias, list);
586 CHECK_ERR_AND_FINISH(err, fail, list, finish);
587
588 finish:
589 DBG(ctx, "lookup %s=%d, list=%p\n", alias, err, *list);
590 return err;
591 fail:
592 DBG(ctx, "Failed to lookup %s\n", alias);
593 kmod_module_unref_list(*list);
594 *list = NULL;
595 return err;
596 }
597 #undef CHECK_ERR_AND_FINISH
598
599 /**
600 * kmod_module_unref_list:
601 * @list: list of kmod modules
602 *
603 * Drop a reference of each kmod module in @list and releases the resources
604 * taken by the list itself.
605 *
606 * Returns: 0
607 */
608 int kmod_module_unref_list(struct kmod_list *list)
609 {
610 for (; list != NULL; list = __kmod_list_remove(list))
611 kmod_module_unref(list->data);
612
613 return 0;
614 }
615
616 /**
617 * kmod_module_get_filtered_blacklist:
618 * @ctx: kmod library context
619 * @input: list of kmod_module to be filtered with blacklist
620 * @output: where to save the new list
621 *
622 * This function should not be used. Use kmod_module_apply_filter instead.
623 *
624 * Given a list @input, this function filter it out with config's blacklist
625 * and save it in @output.
626 *
627 * Returns: 0 on success or < 0 otherwise. @output is saved with the updated
628 * list.
629 */
630 int kmod_module_get_filtered_blacklist(const struct kmod_ctx *ctx,
631 const struct kmod_list *input,
632 struct kmod_list **output)
633 {
634 return kmod_module_apply_filter(ctx, KMOD_FILTER_BLACKLIST, input, output);
635 }
636
637 static const struct kmod_list *module_get_dependencies_noref(const struct kmod_module *mod)
638 {
639 if (!mod->init.dep) {
640 /* lazy init */
641 char *line = kmod_search_moddep(mod->ctx, mod->name);
642
643 if (line == NULL)
644 return NULL;
645
646 kmod_module_parse_depline((struct kmod_module *)mod, line);
647 free(line);
648
649 if (!mod->init.dep)
650 return NULL;
651 }
652
653 return mod->dep;
654 }
655
656 /**
657 * kmod_module_get_dependencies:
658 * @mod: kmod module
659 *
660 * Search the modules.dep index to find the dependencies of the given @mod.
661 * The result is cached in @mod, so subsequent calls to this function will
662 * return the already searched list of modules.
663 *
664 * Returns: NULL on failure. Otherwise it returns a list of kmod modules
665 * that can be released by calling kmod_module_unref_list().
666 */
667 struct kmod_list *kmod_module_get_dependencies(const struct kmod_module *mod)
668 {
669 struct kmod_list *l, *l_new, *list_new = NULL;
670
671 if (mod == NULL)
672 return NULL;
673
674 module_get_dependencies_noref(mod);
675
676 kmod_list_foreach(l, mod->dep) {
677 l_new = __kmod_list_append(list_new, kmod_module_ref(l->data));
678 if (l_new == NULL) {
679 kmod_module_unref(l->data);
680 goto fail;
681 }
682
683 list_new = l_new;
684 }
685
686 return list_new;
687
688 fail:
689 ERR(mod->ctx, "out of memory\n");
690 kmod_module_unref_list(list_new);
691 return NULL;
692 }
693
694 /**
695 * kmod_module_get_module:
696 * @entry: an entry in a list of kmod modules.
697 *
698 * Get the kmod module of this @entry in the list, increasing its refcount.
699 * After it's used, unref it. Since the refcount is incremented upon return,
700 * you still have to call kmod_module_unref_list() to release the list of kmod
701 * modules.
702 *
703 * Returns: NULL on failure or the kmod_module contained in this list entry
704 * with its refcount incremented.
705 */
706 struct kmod_module *kmod_module_get_module(const struct kmod_list *entry)
707 {
708 if (entry == NULL)
709 return NULL;
710
711 return kmod_module_ref(entry->data);
712 }
713
714 /**
715 * kmod_module_get_name:
716 * @mod: kmod module
717 *
718 * Get the name of this kmod module. Name is always available, independently
719 * if it was created by kmod_module_new_from_name() or another function and
720 * it's always normalized (dashes are replaced with underscores).
721 *
722 * Returns: the name of this kmod module.
723 */
724 const char *kmod_module_get_name(const struct kmod_module *mod)
725 {
726 if (mod == NULL)
727 return NULL;
728
729 return mod->name;
730 }
731
732 /**
733 * kmod_module_get_path:
734 * @mod: kmod module
735 *
736 * Get the path of this kmod module. If this kmod module was not created by
737 * path, it can search the modules.dep index in order to find out the module
738 * under context's dirname.
739 *
740 * Returns: the path of this kmod module or NULL if such information is not
741 * available.
742 */
743 const char *kmod_module_get_path(const struct kmod_module *mod)
744 {
745 char *line;
746
747 if (mod == NULL)
748 return NULL;
749
750 DBG(mod->ctx, "name='%s' path='%s'\n", mod->name, mod->path);
751
752 if (mod->path != NULL)
753 return mod->path;
754 if (mod->init.dep)
755 return NULL;
756
757 /* lazy init */
758 line = kmod_search_moddep(mod->ctx, mod->name);
759 if (line == NULL)
760 return NULL;
761
762 kmod_module_parse_depline((struct kmod_module *) mod, line);
763 free(line);
764
765 return mod->path;
766 }
767
768
769 extern long delete_module(const char *name, unsigned int flags);
770
771 /**
772 * kmod_module_remove_module:
773 * @mod: kmod module
774 * @flags: flags to pass to Linux kernel when removing the module. The only valid flag is
775 * KMOD_REMOVE_FORCE: force remove module regardless if it's still in
776 * use by a kernel subsystem or other process;
777 * KMOD_REMOVE_NOWAIT is always enforced, causing us to pass O_NONBLOCK to
778 * delete_module(2).
779 *
780 * Remove a module from Linux kernel.
781 *
782 * Returns: 0 on success or < 0 on failure.
783 */
784 int kmod_module_remove_module(struct kmod_module *mod,
785 unsigned int flags)
786 {
787 int err;
788
789 if (mod == NULL)
790 return -ENOENT;
791
792 /* Filter out other flags and force ONONBLOCK */
793 flags &= KMOD_REMOVE_FORCE;
794 flags |= KMOD_REMOVE_NOWAIT;
795
796 err = delete_module(mod->name, flags);
797 if (err != 0) {
798 err = -errno;
799 ERR(mod->ctx, "could not remove '%s': %m\n", mod->name);
800 }
801
802 return err;
803 }
804
805 extern long init_module(const void *mem, unsigned long len, const char *args);
806
807 /**
808 * kmod_module_insert_module:
809 * @mod: kmod module
810 * @flags: flags are not passed to Linux Kernel, but instead they dictate the
811 * behavior of this function, valid flags are
812 * KMOD_INSERT_FORCE_VERMAGIC: ignore kernel version magic;
813 * KMOD_INSERT_FORCE_MODVERSION: ignore symbol version hashes.
814 * @options: module's options to pass to Linux Kernel.
815 *
816 * Insert a module in Linux kernel. It opens the file pointed by @mod,
817 * mmap'ing it and passing to kernel.
818 *
819 * Returns: 0 on success or < 0 on failure. If module is already loaded it
820 * returns -EEXIST.
821 */
822 int kmod_module_insert_module(struct kmod_module *mod,
823 unsigned int flags,
824 const char *options)
825 {
826 int err;
827 const void *mem;
828 off_t size;
829 struct kmod_elf *elf;
830 const char *path;
831 const char *args = options ? options : "";
832
833 if (mod == NULL)
834 return -ENOENT;
835
836 path = kmod_module_get_path(mod);
837 if (path == NULL) {
838 ERR(mod->ctx, "could not find module by name='%s'\n", mod->name);
839 return -ENOENT;
840 }
841
842 if (!mod->file) {
843 mod->file = kmod_file_open(mod->ctx, path);
844 if (mod->file == NULL) {
845 err = -errno;
846 return err;
847 }
848 }
849
850 if (kmod_file_get_direct(mod->file)) {
851 unsigned int kernel_flags = 0;
852
853 if (flags & KMOD_INSERT_FORCE_VERMAGIC)
854 kernel_flags |= MODULE_INIT_IGNORE_VERMAGIC;
855 if (flags & KMOD_INSERT_FORCE_MODVERSION)
856 kernel_flags |= MODULE_INIT_IGNORE_MODVERSIONS;
857
858 err = finit_module(kmod_file_get_fd(mod->file), args, kernel_flags);
859 if (err == 0 || errno != ENOSYS)
860 goto init_finished;
861 }
862
863 if (flags & (KMOD_INSERT_FORCE_VERMAGIC | KMOD_INSERT_FORCE_MODVERSION)) {
864 elf = kmod_file_get_elf(mod->file);
865 if (elf == NULL) {
866 err = -errno;
867 return err;
868 }
869
870 if (flags & KMOD_INSERT_FORCE_MODVERSION) {
871 err = kmod_elf_strip_section(elf, "__versions");
872 if (err < 0)
873 INFO(mod->ctx, "Failed to strip modversion: %s\n", strerror(-err));
874 }
875
876 if (flags & KMOD_INSERT_FORCE_VERMAGIC) {
877 err = kmod_elf_strip_vermagic(elf);
878 if (err < 0)
879 INFO(mod->ctx, "Failed to strip vermagic: %s\n", strerror(-err));
880 }
881
882 mem = kmod_elf_get_memory(elf);
883 } else {
884 mem = kmod_file_get_contents(mod->file);
885 }
886 size = kmod_file_get_size(mod->file);
887
888 err = init_module(mem, size, args);
889 init_finished:
890 if (err < 0) {
891 err = -errno;
892 INFO(mod->ctx, "Failed to insert module '%s': %m\n", path);
893 }
894 return err;
895 }
896
897 static bool module_is_blacklisted(struct kmod_module *mod)
898 {
899 struct kmod_ctx *ctx = mod->ctx;
900 const struct kmod_config *config = kmod_get_config(ctx);
901 const struct kmod_list *bl = config->blacklists;
902 const struct kmod_list *l;
903
904 kmod_list_foreach(l, bl) {
905 const char *modname = kmod_blacklist_get_modname(l);
906
907 if (streq(modname, mod->name))
908 return true;
909 }
910
911 return false;
912 }
913
914 /**
915 * kmod_module_apply_filter
916 * @ctx: kmod library context
917 * @filter_type: bitmask to filter modules out, valid types are
918 * KMOD_FILTER_BLACKLIST: filter modules in blacklist out;
919 * KMOD_FILTER_BUILTIN: filter builtin modules out.
920 * @input: list of kmod_module to be filtered
921 * @output: where to save the new list
922 *
923 * Given a list @input, this function filter it out by the filter mask
924 * and save it in @output.
925 *
926 * Returns: 0 on success or < 0 otherwise. @output is saved with the updated
927 * list.
928 */
929 int kmod_module_apply_filter(const struct kmod_ctx *ctx,
930 enum kmod_filter filter_type,
931 const struct kmod_list *input,
932 struct kmod_list **output)
933 {
934 const struct kmod_list *li;
935
936 if (ctx == NULL || output == NULL)
937 return -ENOENT;
938
939 *output = NULL;
940 if (input == NULL)
941 return 0;
942
943 kmod_list_foreach(li, input) {
944 struct kmod_module *mod = li->data;
945 struct kmod_list *node;
946
947 if ((filter_type & KMOD_FILTER_BLACKLIST) &&
948 module_is_blacklisted(mod))
949 continue;
950
951 if ((filter_type & KMOD_FILTER_BUILTIN)
952 && kmod_module_is_builtin(mod))
953 continue;
954
955 node = __kmod_list_append(*output, mod);
956 if (node == NULL)
957 goto fail;
958
959 *output = node;
960 kmod_module_ref(mod);
961 }
962
963 return 0;
964
965 fail:
966 kmod_module_unref_list(*output);
967 *output = NULL;
968 return -ENOMEM;
969 }
970
971 static int command_do(struct kmod_module *mod, const char *type,
972 const char *cmd)
973 {
974 const char *modname = kmod_module_get_name(mod);
975 int err;
976
977 DBG(mod->ctx, "%s %s\n", type, cmd);
978
979 setenv("MODPROBE_MODULE", modname, 1);
980 err = system(cmd);
981 unsetenv("MODPROBE_MODULE");
982
983 if (err == -1 || WEXITSTATUS(err)) {
984 ERR(mod->ctx, "Error running %s command for %s\n",
985 type, modname);
986 if (err != -1)
987 err = -WEXITSTATUS(err);
988 }
989
990 return err;
991 }
992
993 struct probe_insert_cb {
994 int (*run_install)(struct kmod_module *m, const char *cmd, void *data);
995 void *data;
996 };
997
998 static int module_do_install_commands(struct kmod_module *mod,
999 const char *options,
1000 struct probe_insert_cb *cb)
1001 {
1002 const char *command = kmod_module_get_install_commands(mod);
1003 char *p;
1004 char *cmd = NULL;
1005 int err;
1006 size_t cmdlen, options_len, varlen;
1007
1008 assert(command);
1009
1010 if (options == NULL)
1011 options = "";
1012
1013 options_len = strlen(options);
1014 cmdlen = strlen(command);
1015 varlen = sizeof("$CMDLINE_OPTS") - 1;
1016
1017 cmd = memdup(command, cmdlen + 1);
1018 if (cmd == NULL)
1019 return -ENOMEM;
1020
1021 while ((p = strstr(cmd, "$CMDLINE_OPTS")) != NULL) {
1022 size_t prefixlen = p - cmd;
1023 size_t suffixlen = cmdlen - prefixlen - varlen;
1024 size_t slen = cmdlen - varlen + options_len;
1025 char *suffix = p + varlen;
1026 char *s = malloc(slen + 1);
1027 if (!s) {
1028 if (cmd)
1029 free(cmd);
1030 return -ENOMEM;
1031 }
1032
1033 memcpy(s, cmd, p - cmd);
1034 memcpy(s + prefixlen, options, options_len);
1035 memcpy(s + prefixlen + options_len, suffix, suffixlen);
1036 s[slen] = '\0';
1037
1038 free(cmd);
1039 cmd = s;
1040 cmdlen = slen;
1041 }
1042
1043 if (cb->run_install != NULL)
1044 err = cb->run_install(mod, cmd, cb->data);
1045 else
1046 err = command_do(mod, "install", cmd);
1047 return err;
1048 }
1049
1050 static char *module_options_concat(const char *opt, const char *xopt)
1051 {
1052 // TODO: we might need to check if xopt overrides options on opt
1053 size_t optlen = opt == NULL ? 0 : strlen(opt);
1054 size_t xoptlen = xopt == NULL ? 0 : strlen(xopt);
1055 char *r;
1056
1057 if (optlen == 0 && xoptlen == 0)
1058 return NULL;
1059
1060 r = malloc(optlen + xoptlen + 2);
1061
1062 if (opt != NULL) {
1063 memcpy(r, opt, optlen);
1064 r[optlen] = ' ';
1065 optlen++;
1066 }
1067
1068 if (xopt != NULL)
1069 memcpy(r + optlen, xopt, xoptlen);
1070
1071 r[optlen + xoptlen] = '\0';
1072
1073 return r;
1074 }
1075
1076 static int __kmod_module_get_probe_list(struct kmod_module *mod,
1077 bool required,
1078 bool ignorecmd,
1079 struct kmod_list **list);
1080
1081 /* re-entrant */
1082 static int __kmod_module_fill_softdep(struct kmod_module *mod,
1083 struct kmod_list **list)
1084 {
1085 struct kmod_list *pre = NULL, *post = NULL, *l;
1086 int err;
1087
1088 err = kmod_module_get_softdeps(mod, &pre, &post);
1089 if (err < 0) {
1090 ERR(mod->ctx, "could not get softdep: %s\n",
1091 strerror(-err));
1092 goto fail;
1093 }
1094
1095 kmod_list_foreach(l, pre) {
1096 struct kmod_module *m = l->data;
1097 err = __kmod_module_get_probe_list(m, false, false, list);
1098 if (err < 0)
1099 goto fail;
1100 }
1101
1102 l = __kmod_list_append(*list, kmod_module_ref(mod));
1103 if (l == NULL) {
1104 kmod_module_unref(mod);
1105 err = -ENOMEM;
1106 goto fail;
1107 }
1108 *list = l;
1109 mod->ignorecmd = (pre != NULL || post != NULL);
1110
1111 kmod_list_foreach(l, post) {
1112 struct kmod_module *m = l->data;
1113 err = __kmod_module_get_probe_list(m, false, false, list);
1114 if (err < 0)
1115 goto fail;
1116 }
1117
1118 fail:
1119 kmod_module_unref_list(pre);
1120 kmod_module_unref_list(post);
1121
1122 return err;
1123 }
1124
1125 /* re-entrant */
1126 static int __kmod_module_get_probe_list(struct kmod_module *mod,
1127 bool required,
1128 bool ignorecmd,
1129 struct kmod_list **list)
1130 {
1131 struct kmod_list *dep, *l;
1132 int err = 0;
1133
1134 if (mod->visited) {
1135 DBG(mod->ctx, "Ignore module '%s': already visited\n",
1136 mod->name);
1137 return 0;
1138 }
1139 mod->visited = true;
1140
1141 dep = kmod_module_get_dependencies(mod);
1142 if (required) {
1143 /*
1144 * Called from kmod_module_probe_insert_module(); set the
1145 * ->required flag on mod and all its dependencies before
1146 * they are possibly visited through some softdeps.
1147 */
1148 mod->required = true;
1149 kmod_list_foreach(l, dep) {
1150 struct kmod_module *m = l->data;
1151 m->required = true;
1152 }
1153 }
1154
1155 kmod_list_foreach(l, dep) {
1156 struct kmod_module *m = l->data;
1157 err = __kmod_module_fill_softdep(m, list);
1158 if (err < 0)
1159 goto finish;
1160 }
1161
1162 if (ignorecmd) {
1163 l = __kmod_list_append(*list, kmod_module_ref(mod));
1164 if (l == NULL) {
1165 kmod_module_unref(mod);
1166 err = -ENOMEM;
1167 goto finish;
1168 }
1169 *list = l;
1170 mod->ignorecmd = true;
1171 } else
1172 err = __kmod_module_fill_softdep(mod, list);
1173
1174 finish:
1175 kmod_module_unref_list(dep);
1176 return err;
1177 }
1178
1179 static int kmod_module_get_probe_list(struct kmod_module *mod,
1180 bool ignorecmd,
1181 struct kmod_list **list)
1182 {
1183 int err;
1184
1185 assert(mod != NULL);
1186 assert(list != NULL && *list == NULL);
1187
1188 /*
1189 * Make sure we don't get screwed by previous calls to this function
1190 */
1191 kmod_set_modules_visited(mod->ctx, false);
1192 kmod_set_modules_required(mod->ctx, false);
1193
1194 err = __kmod_module_get_probe_list(mod, true, ignorecmd, list);
1195 if (err < 0) {
1196 kmod_module_unref_list(*list);
1197 *list = NULL;
1198 }
1199
1200 return err;
1201 }
1202
1203 /**
1204 * kmod_module_probe_insert_module:
1205 * @mod: kmod module
1206 * @flags: flags are not passed to Linux Kernel, but instead they dictate the
1207 * behavior of this function, valid flags are
1208 * KMOD_PROBE_FORCE_VERMAGIC: ignore kernel version magic;
1209 * KMOD_PROBE_FORCE_MODVERSION: ignore symbol version hashes;
1210 * KMOD_PROBE_IGNORE_COMMAND: whether the probe should ignore install
1211 * commands and softdeps configured in the system;
1212 * KMOD_PROBE_IGNORE_LOADED: do not check whether the module is already
1213 * live in kernel or not;
1214 * KMOD_PROBE_DRY_RUN: dry run, do not insert module, just call the
1215 * associated callback function;
1216 * KMOD_PROBE_FAIL_ON_LOADED: if KMOD_PROBE_IGNORE_LOADED is not specified
1217 * and the module is already live in kernel, the function will fail if this
1218 * flag is specified;
1219 * KMOD_PROBE_APPLY_BLACKLIST_ALL: probe will apply KMOD_FILTER_BLACKLIST
1220 * filter to this module and its dependencies. If any of the dependencies (or
1221 * the module) is blacklisted, the probe will fail, unless the blacklisted
1222 * module is already live in kernel;
1223 * KMOD_PROBE_APPLY_BLACKLIST: probe will fail if the module is blacklisted;
1224 * KMOD_PROBE_APPLY_BLACKLIST_ALIAS_ONLY: probe will fail if the module is an
1225 * alias and is blacklisted.
1226 * @extra_options: module's options to pass to Linux Kernel. It applies only
1227 * to @mod, not to its dependencies.
1228 * @run_install: function to run when @mod is backed by an install command.
1229 * @data: data to give back to @run_install callback
1230 * @print_action: function to call with the action being taken (install or
1231 * insmod). It's useful for tools like modprobe when running with verbose
1232 * output or in dry-run mode.
1233 *
1234 * Insert a module in Linux kernel resolving dependencies, soft dependencies,
1235 * install commands and applying blacklist.
1236 *
1237 * If @run_install is NULL, this function will fork and exec by calling
1238 * system(3). Don't pass a NULL argument in @run_install if your binary is
1239 * setuid/setgid (see warning in system(3)). If you need control over the
1240 * execution of an install command, give a callback function instead.
1241 *
1242 * Returns: 0 on success, > 0 if stopped by a reason given in @flags or < 0 on
1243 * failure.
1244 */
1245 int kmod_module_probe_insert_module(struct kmod_module *mod,
1246 unsigned int flags, const char *extra_options,
1247 int (*run_install)(struct kmod_module *m,
1248 const char *cmd, void *data),
1249 const void *data,
1250 void (*print_action)(struct kmod_module *m,
1251 bool install,
1252 const char *options))
1253 {
1254 struct kmod_list *list = NULL, *l;
1255 struct probe_insert_cb cb;
1256 int err;
1257
1258 if (mod == NULL)
1259 return -ENOENT;
1260
1261 if (!(flags & KMOD_PROBE_IGNORE_LOADED)
1262 && module_is_inkernel(mod)) {
1263 if (flags & KMOD_PROBE_FAIL_ON_LOADED)
1264 return -EEXIST;
1265 else
1266 return 0;
1267 }
1268
1269 /*
1270 * Ugly assignement + check. We need to check if we were told to check
1271 * blacklist and also return the reason why we failed.
1272 * KMOD_PROBE_APPLY_BLACKLIST_ALIAS_ONLY will take effect only if the
1273 * module is an alias, so we also need to check it
1274 */
1275 if ((mod->alias != NULL && ((err = flags & KMOD_PROBE_APPLY_BLACKLIST_ALIAS_ONLY)))
1276 || (err = flags & KMOD_PROBE_APPLY_BLACKLIST_ALL)
1277 || (err = flags & KMOD_PROBE_APPLY_BLACKLIST)) {
1278 if (module_is_blacklisted(mod))
1279 return err;
1280 }
1281
1282 err = kmod_module_get_probe_list(mod,
1283 !!(flags & KMOD_PROBE_IGNORE_COMMAND), &list);
1284 if (err < 0)
1285 return err;
1286
1287 if (flags & KMOD_PROBE_APPLY_BLACKLIST_ALL) {
1288 struct kmod_list *filtered = NULL;
1289
1290 err = kmod_module_apply_filter(mod->ctx,
1291 KMOD_FILTER_BLACKLIST, list, &filtered);
1292 if (err < 0)
1293 return err;
1294
1295 kmod_module_unref_list(list);
1296 if (filtered == NULL)
1297 return KMOD_PROBE_APPLY_BLACKLIST_ALL;
1298
1299 list = filtered;
1300 }
1301
1302 cb.run_install = run_install;
1303 cb.data = (void *) data;
1304
1305 kmod_list_foreach(l, list) {
1306 struct kmod_module *m = l->data;
1307 const char *moptions = kmod_module_get_options(m);
1308 const char *cmd = kmod_module_get_install_commands(m);
1309 char *options;
1310
1311 if (!(flags & KMOD_PROBE_IGNORE_LOADED)
1312 && module_is_inkernel(m)) {
1313 DBG(mod->ctx, "Ignoring module '%s': already loaded\n",
1314 m->name);
1315 err = -EEXIST;
1316 goto finish_module;
1317 }
1318
1319 options = module_options_concat(moptions,
1320 m == mod ? extra_options : NULL);
1321
1322 if (cmd != NULL && !m->ignorecmd) {
1323 if (print_action != NULL)
1324 print_action(m, true, options ?: "");
1325
1326 if (!(flags & KMOD_PROBE_DRY_RUN))
1327 err = module_do_install_commands(m, options,
1328 &cb);
1329 } else {
1330 if (print_action != NULL)
1331 print_action(m, false, options ?: "");
1332
1333 if (!(flags & KMOD_PROBE_DRY_RUN))
1334 err = kmod_module_insert_module(m, flags,
1335 options);
1336 }
1337
1338 free(options);
1339
1340 finish_module:
1341 /*
1342 * Treat "already loaded" error. If we were told to stop on
1343 * already loaded and the module being loaded is not a softdep
1344 * or dep, bail out. Otherwise, just ignore and continue.
1345 *
1346 * We need to check here because of race conditions. We
1347 * checked first if module was already loaded but it may have
1348 * been loaded between the check and the moment we try to
1349 * insert it.
1350 */
1351 if (err == -EEXIST && m == mod &&
1352 (flags & KMOD_PROBE_FAIL_ON_LOADED))
1353 break;
1354
1355 /*
1356 * Ignore errors from softdeps
1357 */
1358 if (err == -EEXIST || !m->required)
1359 err = 0;
1360
1361 else if (err < 0)
1362 break;
1363 }
1364
1365 kmod_module_unref_list(list);
1366 return err;
1367 }
1368
1369 /**
1370 * kmod_module_get_options:
1371 * @mod: kmod module
1372 *
1373 * Get options of this kmod module. Options come from the configuration file
1374 * and are cached in @mod. The first call to this function will search for
1375 * this module in configuration and subsequent calls return the cached string.
1376 *
1377 * Returns: a string with all the options separated by spaces. This string is
1378 * owned by @mod, do not free it.
1379 */
1380 const char *kmod_module_get_options(const struct kmod_module *mod)
1381 {
1382 if (mod == NULL)
1383 return NULL;
1384
1385 if (!mod->init.options) {
1386 /* lazy init */
1387 struct kmod_module *m = (struct kmod_module *)mod;
1388 const struct kmod_list *l;
1389 const struct kmod_config *config;
1390 char *opts = NULL;
1391 size_t optslen = 0;
1392
1393 config = kmod_get_config(mod->ctx);
1394
1395 kmod_list_foreach(l, config->options) {
1396 const char *modname = kmod_option_get_modname(l);
1397 const char *str;
1398 size_t len;
1399 void *tmp;
1400
1401 DBG(mod->ctx, "modname=%s mod->name=%s mod->alias=%s\n", modname, mod->name, mod->alias);
1402 if (!(streq(modname, mod->name) || (mod->alias != NULL &&
1403 streq(modname, mod->alias))))
1404 continue;
1405
1406 DBG(mod->ctx, "passed = modname=%s mod->name=%s mod->alias=%s\n", modname, mod->name, mod->alias);
1407 str = kmod_option_get_options(l);
1408 len = strlen(str);
1409 if (len < 1)
1410 continue;
1411
1412 tmp = realloc(opts, optslen + len + 2);
1413 if (tmp == NULL) {
1414 free(opts);
1415 goto failed;
1416 }
1417
1418 opts = tmp;
1419
1420 if (optslen > 0) {
1421 opts[optslen] = ' ';
1422 optslen++;
1423 }
1424
1425 memcpy(opts + optslen, str, len);
1426 optslen += len;
1427 opts[optslen] = '\0';
1428 }
1429
1430 m->init.options = true;
1431 m->options = opts;
1432 }
1433
1434 return mod->options;
1435
1436 failed:
1437 ERR(mod->ctx, "out of memory\n");
1438 return NULL;
1439 }
1440
1441 /**
1442 * kmod_module_get_install_commands:
1443 * @mod: kmod module
1444 *
1445 * Get install commands for this kmod module. Install commands come from the
1446 * configuration file and are cached in @mod. The first call to this function
1447 * will search for this module in configuration and subsequent calls return
1448 * the cached string. The install commands are returned as they were in the
1449 * configuration, concatenated by ';'. No other processing is made in this
1450 * string.
1451 *
1452 * Returns: a string with all install commands separated by semicolons. This
1453 * string is owned by @mod, do not free it.
1454 */
1455 const char *kmod_module_get_install_commands(const struct kmod_module *mod)
1456 {
1457 if (mod == NULL)
1458 return NULL;
1459
1460 if (!mod->init.install_commands) {
1461 /* lazy init */
1462 struct kmod_module *m = (struct kmod_module *)mod;
1463 const struct kmod_list *l;
1464 const struct kmod_config *config;
1465
1466 config = kmod_get_config(mod->ctx);
1467
1468 kmod_list_foreach(l, config->install_commands) {
1469 const char *modname = kmod_command_get_modname(l);
1470
1471 if (fnmatch(modname, mod->name, 0) != 0)
1472 continue;
1473
1474 m->install_commands = kmod_command_get_command(l);
1475
1476 /*
1477 * find only the first command, as modprobe from
1478 * module-init-tools does
1479 */
1480 break;
1481 }
1482
1483 m->init.install_commands = true;
1484 }
1485
1486 return mod->install_commands;
1487 }
1488
1489 void kmod_module_set_install_commands(struct kmod_module *mod, const char *cmd)
1490 {
1491 mod->init.install_commands = true;
1492 mod->install_commands = cmd;
1493 }
1494
1495 static struct kmod_list *lookup_softdep(struct kmod_ctx *ctx, const char * const * array, unsigned int count)
1496 {
1497 struct kmod_list *ret = NULL;
1498 unsigned i;
1499
1500 for (i = 0; i < count; i++) {
1501 const char *depname = array[i];
1502 struct kmod_list *lst = NULL;
1503 int err;
1504
1505 err = kmod_module_new_from_lookup(ctx, depname, &lst);
1506 if (err < 0) {
1507 ERR(ctx, "failed to lookup soft dependency '%s', continuing anyway.\n", depname);
1508 continue;
1509 } else if (lst != NULL)
1510 ret = kmod_list_append_list(ret, lst);
1511 }
1512 return ret;
1513 }
1514
1515 /**
1516 * kmod_module_get_softdeps:
1517 * @mod: kmod module
1518 * @pre: where to save the list of preceding soft dependencies.
1519 * @post: where to save the list of post soft dependencies.
1520 *
1521 * Get soft dependencies for this kmod module. Soft dependencies come
1522 * from configuration file and are not cached in @mod because it may include
1523 * dependency cycles that would make we leak kmod_module. Any call
1524 * to this function will search for this module in configuration, allocate a
1525 * list and return the result.
1526 *
1527 * Both @pre and @post are newly created list of kmod_module and
1528 * should be unreferenced with kmod_module_unref_list().
1529 *
1530 * Returns: 0 on success or < 0 otherwise.
1531 */
1532 int kmod_module_get_softdeps(const struct kmod_module *mod,
1533 struct kmod_list **pre,
1534 struct kmod_list **post)
1535 {
1536 const struct kmod_list *l;
1537 const struct kmod_config *config;
1538
1539 if (mod == NULL || pre == NULL || post == NULL)
1540 return -ENOENT;
1541
1542 assert(*pre == NULL);
1543 assert(*post == NULL);
1544
1545 config = kmod_get_config(mod->ctx);
1546
1547 kmod_list_foreach(l, config->softdeps) {
1548 const char *modname = kmod_softdep_get_name(l);
1549 const char * const *array;
1550 unsigned count;
1551
1552 if (fnmatch(modname, mod->name, 0) != 0)
1553 continue;
1554
1555 array = kmod_softdep_get_pre(l, &count);
1556 *pre = lookup_softdep(mod->ctx, array, count);
1557 array = kmod_softdep_get_post(l, &count);
1558 *post = lookup_softdep(mod->ctx, array, count);
1559
1560 /*
1561 * find only the first command, as modprobe from
1562 * module-init-tools does
1563 */
1564 break;
1565 }
1566
1567 return 0;
1568 }
1569
1570 /**
1571 * kmod_module_get_remove_commands:
1572 * @mod: kmod module
1573 *
1574 * Get remove commands for this kmod module. Remove commands come from the
1575 * configuration file and are cached in @mod. The first call to this function
1576 * will search for this module in configuration and subsequent calls return
1577 * the cached string. The remove commands are returned as they were in the
1578 * configuration, concatenated by ';'. No other processing is made in this
1579 * string.
1580 *
1581 * Returns: a string with all remove commands separated by semicolons. This
1582 * string is owned by @mod, do not free it.
1583 */
1584 const char *kmod_module_get_remove_commands(const struct kmod_module *mod)
1585 {
1586 if (mod == NULL)
1587 return NULL;
1588
1589 if (!mod->init.remove_commands) {
1590 /* lazy init */
1591 struct kmod_module *m = (struct kmod_module *)mod;
1592 const struct kmod_list *l;
1593 const struct kmod_config *config;
1594
1595 config = kmod_get_config(mod->ctx);
1596
1597 kmod_list_foreach(l, config->remove_commands) {
1598 const char *modname = kmod_command_get_modname(l);
1599
1600 if (fnmatch(modname, mod->name, 0) != 0)
1601 continue;
1602
1603 m->remove_commands = kmod_command_get_command(l);
1604
1605 /*
1606 * find only the first command, as modprobe from
1607 * module-init-tools does
1608 */
1609 break;
1610 }
1611
1612 m->init.remove_commands = true;
1613 }
1614
1615 return mod->remove_commands;
1616 }
1617
1618 void kmod_module_set_remove_commands(struct kmod_module *mod, const char *cmd)
1619 {
1620 mod->init.remove_commands = true;
1621 mod->remove_commands = cmd;
1622 }
1623
1624 /**
1625 * SECTION:libkmod-loaded
1626 * @short_description: currently loaded modules
1627 *
1628 * Information about currently loaded modules, as reported by Linux kernel.
1629 * These information are not cached by libkmod and are always read from /sys
1630 * and /proc/modules.
1631 */
1632
1633 /**
1634 * kmod_module_new_from_loaded:
1635 * @ctx: kmod library context
1636 * @list: where to save the list of loaded modules
1637 *
1638 * Create a new list of kmod modules with all modules currently loaded in
1639 * kernel. It uses /proc/modules to get the names of loaded modules and to
1640 * create kmod modules by calling kmod_module_new_from_name() in each of them.
1641 * They are put in @list in no particular order.
1642 *
1643 * The initial refcount is 1, and needs to be decremented to release the
1644 * resources of the kmod_module. The returned @list must be released by
1645 * calling kmod_module_unref_list(). Since libkmod keeps track of all
1646 * kmod_modules created, they are all released upon @ctx destruction too. Do
1647 * not unref @ctx before all the desired operations with the returned list are
1648 * completed.
1649 *
1650 * Returns: 0 on success or < 0 on error.
1651 */
1652 int kmod_module_new_from_loaded(struct kmod_ctx *ctx,
1653 struct kmod_list **list)
1654 {
1655 struct kmod_list *l = NULL;
1656 FILE *fp;
1657 char line[4096];
1658
1659 if (ctx == NULL || list == NULL)
1660 return -ENOENT;
1661
1662 fp = fopen("/proc/modules", "re");
1663 if (fp == NULL) {
1664 int err = -errno;
1665 ERR(ctx, "could not open /proc/modules: %s\n", strerror(errno));
1666 return err;
1667 }
1668
1669 while (fgets(line, sizeof(line), fp)) {
1670 struct kmod_module *m;
1671 struct kmod_list *node;
1672 int err;
1673 size_t len = strlen(line);
1674 char *saveptr, *name = strtok_r(line, " \t", &saveptr);
1675
1676 err = kmod_module_new_from_name(ctx, name, &m);
1677 if (err < 0) {
1678 ERR(ctx, "could not get module from name '%s': %s\n",
1679 name, strerror(-err));
1680 goto eat_line;
1681 }
1682
1683 node = __kmod_list_append(l, m);
1684 if (node)
1685 l = node;
1686 else {
1687 ERR(ctx, "out of memory\n");
1688 kmod_module_unref(m);
1689 }
1690 eat_line:
1691 while (line[len - 1] != '\n' && fgets(line, sizeof(line), fp))
1692 len = strlen(line);
1693 }
1694
1695 fclose(fp);
1696 *list = l;
1697
1698 return 0;
1699 }
1700
1701 /**
1702 * kmod_module_initstate_str:
1703 * @state: the state as returned by kmod_module_get_initstate()
1704 *
1705 * Translate a initstate to a string.
1706 *
1707 * Returns: the string associated to the @state. This string is statically
1708 * allocated, do not free it.
1709 */
1710 const char *kmod_module_initstate_str(enum kmod_module_initstate state)
1711 {
1712 switch (state) {
1713 case KMOD_MODULE_BUILTIN:
1714 return "builtin";
1715 case KMOD_MODULE_LIVE:
1716 return "live";
1717 case KMOD_MODULE_COMING:
1718 return "coming";
1719 case KMOD_MODULE_GOING:
1720 return "going";
1721 default:
1722 return NULL;
1723 }
1724 }
1725
1726 /**
1727 * kmod_module_get_initstate:
1728 * @mod: kmod module
1729 *
1730 * Get the initstate of this @mod, as returned by Linux Kernel, by reading
1731 * /sys filesystem.
1732 *
1733 * Returns: < 0 on error or module state if module is found in kernel, valid states are
1734 * KMOD_MODULE_BUILTIN: module is builtin;
1735 * KMOD_MODULE_LIVE: module is live in kernel;
1736 * KMOD_MODULE_COMING: module is being loaded;
1737 * KMOD_MODULE_GOING: module is being unloaded.
1738 */
1739 int kmod_module_get_initstate(const struct kmod_module *mod)
1740 {
1741 char path[PATH_MAX], buf[32];
1742 int fd, err, pathlen;
1743
1744 if (mod == NULL)
1745 return -ENOENT;
1746
1747 /* remove const: this can only change internal state */
1748 if (kmod_module_is_builtin((struct kmod_module *)mod))
1749 return KMOD_MODULE_BUILTIN;
1750
1751 pathlen = snprintf(path, sizeof(path),
1752 "/sys/module/%s/initstate", mod->name);
1753 fd = open(path, O_RDONLY|O_CLOEXEC);
1754 if (fd < 0) {
1755 err = -errno;
1756
1757 DBG(mod->ctx, "could not open '%s': %s\n",
1758 path, strerror(-err));
1759
1760 if (pathlen > (int)sizeof("/initstate") - 1) {
1761 struct stat st;
1762 path[pathlen - (sizeof("/initstate") - 1)] = '\0';
1763 if (stat(path, &st) == 0 && S_ISDIR(st.st_mode))
1764 return KMOD_MODULE_COMING;
1765 }
1766
1767 DBG(mod->ctx, "could not open '%s': %s\n",
1768 path, strerror(-err));
1769 return err;
1770 }
1771
1772 err = read_str_safe(fd, buf, sizeof(buf));
1773 close(fd);
1774 if (err < 0) {
1775 ERR(mod->ctx, "could not read from '%s': %s\n",
1776 path, strerror(-err));
1777 return err;
1778 }
1779
1780 if (streq(buf, "live\n"))
1781 return KMOD_MODULE_LIVE;
1782 else if (streq(buf, "coming\n"))
1783 return KMOD_MODULE_COMING;
1784 else if (streq(buf, "going\n"))
1785 return KMOD_MODULE_GOING;
1786
1787 ERR(mod->ctx, "unknown %s: '%s'\n", path, buf);
1788 return -EINVAL;
1789 }
1790
1791 /**
1792 * kmod_module_get_size:
1793 * @mod: kmod module
1794 *
1795 * Get the size of this kmod module as returned by Linux kernel. If supported,
1796 * the size is read from the coresize attribute in /sys/module. For older
1797 * kernels, this falls back on /proc/modules and searches for the specified
1798 * module to get its size.
1799 *
1800 * Returns: the size of this kmod module.
1801 */
1802 long kmod_module_get_size(const struct kmod_module *mod)
1803 {
1804 FILE *fp;
1805 char line[4096];
1806 int lineno = 0;
1807 long size = -ENOENT;
1808 int dfd, cfd;
1809
1810 if (mod == NULL)
1811 return -ENOENT;
1812
1813 /* try to open the module dir in /sys. If this fails, don't
1814 * bother trying to find the size as we know the module isn't
1815 * loaded.
1816 */
1817 snprintf(line, sizeof(line), "/sys/module/%s", mod->name);
1818 dfd = open(line, O_RDONLY|O_CLOEXEC);
1819 if (dfd < 0)
1820 return -errno;
1821
1822 /* available as of linux 3.3.x */
1823 cfd = openat(dfd, "coresize", O_RDONLY|O_CLOEXEC);
1824 if (cfd >= 0) {
1825 if (read_str_long(cfd, &size, 10) < 0)
1826 ERR(mod->ctx, "failed to read coresize from %s\n", line);
1827 close(cfd);
1828 goto done;
1829 }
1830
1831 /* fall back on parsing /proc/modules */
1832 fp = fopen("/proc/modules", "re");
1833 if (fp == NULL) {
1834 int err = -errno;
1835 ERR(mod->ctx,
1836 "could not open /proc/modules: %s\n", strerror(errno));
1837 close(dfd);
1838 return err;
1839 }
1840
1841 while (fgets(line, sizeof(line), fp)) {
1842 size_t len = strlen(line);
1843 char *saveptr, *endptr, *tok = strtok_r(line, " \t", &saveptr);
1844 long value;
1845
1846 lineno++;
1847 if (tok == NULL || !streq(tok, mod->name))
1848 goto eat_line;
1849
1850 tok = strtok_r(NULL, " \t", &saveptr);
1851 if (tok == NULL) {
1852 ERR(mod->ctx,
1853 "invalid line format at /proc/modules:%d\n", lineno);
1854 break;
1855 }
1856
1857 value = strtol(tok, &endptr, 10);
1858 if (endptr == tok || *endptr != '\0') {
1859 ERR(mod->ctx,
1860 "invalid line format at /proc/modules:%d\n", lineno);
1861 break;
1862 }
1863
1864 size = value;
1865 break;
1866 eat_line:
1867 while (line[len - 1] != '\n' && fgets(line, sizeof(line), fp))
1868 len = strlen(line);
1869 }
1870 fclose(fp);
1871
1872 done:
1873 close(dfd);
1874 return size;
1875 }
1876
1877 /**
1878 * kmod_module_get_refcnt:
1879 * @mod: kmod module
1880 *
1881 * Get the ref count of this @mod, as returned by Linux Kernel, by reading
1882 * /sys filesystem.
1883 *
1884 * Returns: the reference count on success or < 0 on failure.
1885 */
1886 int kmod_module_get_refcnt(const struct kmod_module *mod)
1887 {
1888 char path[PATH_MAX];
1889 long refcnt;
1890 int fd, err;
1891
1892 if (mod == NULL)
1893 return -ENOENT;
1894
1895 snprintf(path, sizeof(path), "/sys/module/%s/refcnt", mod->name);
1896 fd = open(path, O_RDONLY|O_CLOEXEC);
1897 if (fd < 0) {
1898 err = -errno;
1899 DBG(mod->ctx, "could not open '%s': %s\n",
1900 path, strerror(errno));
1901 return err;
1902 }
1903
1904 err = read_str_long(fd, &refcnt, 10);
1905 close(fd);
1906 if (err < 0) {
1907 ERR(mod->ctx, "could not read integer from '%s': '%s'\n",
1908 path, strerror(-err));
1909 return err;
1910 }
1911
1912 return (int)refcnt;
1913 }
1914
1915 /**
1916 * kmod_module_get_holders:
1917 * @mod: kmod module
1918 *
1919 * Get a list of kmod modules that are holding this @mod, as returned by Linux
1920 * Kernel. After use, free the @list by calling kmod_module_unref_list().
1921 *
1922 * Returns: a new list of kmod modules on success or NULL on failure.
1923 */
1924 struct kmod_list *kmod_module_get_holders(const struct kmod_module *mod)
1925 {
1926 char dname[PATH_MAX];
1927 struct kmod_list *list = NULL;
1928 struct dirent *dent;
1929 DIR *d;
1930
1931 if (mod == NULL || mod->ctx == NULL)
1932 return NULL;
1933
1934 snprintf(dname, sizeof(dname), "/sys/module/%s/holders", mod->name);
1935
1936 d = opendir(dname);
1937 if (d == NULL) {
1938 ERR(mod->ctx, "could not open '%s': %s\n",
1939 dname, strerror(errno));
1940 return NULL;
1941 }
1942
1943 for (dent = readdir(d); dent != NULL; dent = readdir(d)) {
1944 struct kmod_module *holder;
1945 struct kmod_list *l;
1946 int err;
1947
1948 if (dent->d_name[0] == '.') {
1949 if (dent->d_name[1] == '\0' ||
1950 (dent->d_name[1] == '.' && dent->d_name[2] == '\0'))
1951 continue;
1952 }
1953
1954 err = kmod_module_new_from_name(mod->ctx, dent->d_name,
1955 &holder);
1956 if (err < 0) {
1957 ERR(mod->ctx, "could not create module for '%s': %s\n",
1958 dent->d_name, strerror(-err));
1959 goto fail;
1960 }
1961
1962 l = __kmod_list_append(list, holder);
1963 if (l != NULL) {
1964 list = l;
1965 } else {
1966 ERR(mod->ctx, "out of memory\n");
1967 kmod_module_unref(holder);
1968 goto fail;
1969 }
1970 }
1971
1972 closedir(d);
1973 return list;
1974
1975 fail:
1976 closedir(d);
1977 kmod_module_unref_list(list);
1978 return NULL;
1979 }
1980
1981 struct kmod_module_section {
1982 unsigned long address;
1983 char name[];
1984 };
1985
1986 static void kmod_module_section_free(struct kmod_module_section *section)
1987 {
1988 free(section);
1989 }
1990
1991 /**
1992 * kmod_module_get_sections:
1993 * @mod: kmod module
1994 *
1995 * Get a list of kmod sections of this @mod, as returned by Linux Kernel. The
1996 * structure contained in this list is internal to libkmod and their fields
1997 * can be obtained by calling kmod_module_section_get_name() and
1998 * kmod_module_section_get_address().
1999 *
2000 * After use, free the @list by calling kmod_module_section_free_list().
2001 *
2002 * Returns: a new list of kmod module sections on success or NULL on failure.
2003 */
2004 struct kmod_list *kmod_module_get_sections(const struct kmod_module *mod)
2005 {
2006 char dname[PATH_MAX];
2007 struct kmod_list *list = NULL;
2008 struct dirent *dent;
2009 DIR *d;
2010 int dfd;
2011
2012 if (mod == NULL)
2013 return NULL;
2014
2015 snprintf(dname, sizeof(dname), "/sys/module/%s/sections", mod->name);
2016
2017 d = opendir(dname);
2018 if (d == NULL) {
2019 ERR(mod->ctx, "could not open '%s': %s\n",
2020 dname, strerror(errno));
2021 return NULL;
2022 }
2023
2024 dfd = dirfd(d);
2025
2026 for (dent = readdir(d); dent; dent = readdir(d)) {
2027 struct kmod_module_section *section;
2028 struct kmod_list *l;
2029 unsigned long address;
2030 size_t namesz;
2031 int fd, err;
2032
2033 if (dent->d_name[0] == '.') {
2034 if (dent->d_name[1] == '\0' ||
2035 (dent->d_name[1] == '.' && dent->d_name[2] == '\0'))
2036 continue;
2037 }
2038
2039 fd = openat(dfd, dent->d_name, O_RDONLY|O_CLOEXEC);
2040 if (fd < 0) {
2041 ERR(mod->ctx, "could not open '%s/%s': %m\n",
2042 dname, dent->d_name);
2043 goto fail;
2044 }
2045
2046 err = read_str_ulong(fd, &address, 16);
2047 close(fd);
2048 if (err < 0) {
2049 ERR(mod->ctx, "could not read long from '%s/%s': %m\n",
2050 dname, dent->d_name);
2051 goto fail;
2052 }
2053
2054 namesz = strlen(dent->d_name) + 1;
2055 section = malloc(sizeof(*section) + namesz);
2056
2057 if (section == NULL) {
2058 ERR(mod->ctx, "out of memory\n");
2059 goto fail;
2060 }
2061
2062 section->address = address;
2063 memcpy(section->name, dent->d_name, namesz);
2064
2065 l = __kmod_list_append(list, section);
2066 if (l != NULL) {
2067 list = l;
2068 } else {
2069 ERR(mod->ctx, "out of memory\n");
2070 free(section);
2071 goto fail;
2072 }
2073 }
2074
2075 closedir(d);
2076 return list;
2077
2078 fail:
2079 closedir(d);
2080 kmod_module_unref_list(list);
2081 return NULL;
2082 }
2083
2084 /**
2085 * kmod_module_section_get_module_name:
2086 * @entry: a list entry representing a kmod module section
2087 *
2088 * Get the name of a kmod module section.
2089 *
2090 * After use, free the @list by calling kmod_module_section_free_list().
2091 *
2092 * Returns: the name of this kmod module section on success or NULL on
2093 * failure. The string is owned by the section, do not free it.
2094 */
2095 const char *kmod_module_section_get_name(const struct kmod_list *entry)
2096 {
2097 struct kmod_module_section *section;
2098
2099 if (entry == NULL)
2100 return NULL;
2101
2102 section = entry->data;
2103 return section->name;
2104 }
2105
2106 /**
2107 * kmod_module_section_get_address:
2108 * @entry: a list entry representing a kmod module section
2109 *
2110 * Get the address of a kmod module section.
2111 *
2112 * After use, free the @list by calling kmod_module_section_free_list().
2113 *
2114 * Returns: the address of this kmod module section on success or ULONG_MAX
2115 * on failure.
2116 */
2117 unsigned long kmod_module_section_get_address(const struct kmod_list *entry)
2118 {
2119 struct kmod_module_section *section;
2120
2121 if (entry == NULL)
2122 return (unsigned long)-1;
2123
2124 section = entry->data;
2125 return section->address;
2126 }
2127
2128 /**
2129 * kmod_module_section_free_list:
2130 * @list: kmod module section list
2131 *
2132 * Release the resources taken by @list
2133 */
2134 void kmod_module_section_free_list(struct kmod_list *list)
2135 {
2136 while (list) {
2137 kmod_module_section_free(list->data);
2138 list = __kmod_list_remove(list);
2139 }
2140 }
2141
2142 static struct kmod_elf *kmod_module_get_elf(const struct kmod_module *mod)
2143 {
2144 if (mod->file == NULL) {
2145 const char *path = kmod_module_get_path(mod);
2146
2147 if (path == NULL) {
2148 errno = ENOENT;
2149 return NULL;
2150 }
2151
2152 ((struct kmod_module *)mod)->file = kmod_file_open(mod->ctx,
2153 path);
2154 if (mod->file == NULL)
2155 return NULL;
2156 }
2157
2158 return kmod_file_get_elf(mod->file);
2159 }
2160
2161 struct kmod_module_info {
2162 char *key;
2163 char value[];
2164 };
2165
2166 static struct kmod_module_info *kmod_module_info_new(const char *key, size_t keylen, const char *value, size_t valuelen)
2167 {
2168 struct kmod_module_info *info;
2169
2170 info = malloc(sizeof(struct kmod_module_info) + keylen + valuelen + 2);
2171 if (info == NULL)
2172 return NULL;
2173
2174 info->key = (char *)info + sizeof(struct kmod_module_info)
2175 + valuelen + 1;
2176 memcpy(info->key, key, keylen);
2177 info->key[keylen] = '\0';
2178 memcpy(info->value, value, valuelen);
2179 info->value[valuelen] = '\0';
2180 return info;
2181 }
2182
2183 static void kmod_module_info_free(struct kmod_module_info *info)
2184 {
2185 free(info);
2186 }
2187
2188 static struct kmod_list *kmod_module_info_append(struct kmod_list **list, const char *key, size_t keylen, const char *value, size_t valuelen)
2189 {
2190 struct kmod_module_info *info;
2191 struct kmod_list *n;
2192
2193 info = kmod_module_info_new(key, keylen, value, valuelen);
2194 if (info == NULL)
2195 return NULL;
2196 n = __kmod_list_append(*list, info);
2197 if (n != NULL)
2198 *list = n;
2199 else
2200 kmod_module_info_free(info);
2201 return n;
2202 }
2203
2204 /**
2205 * kmod_module_get_info:
2206 * @mod: kmod module
2207 * @list: where to return list of module information. Use
2208 * kmod_module_info_get_key() and
2209 * kmod_module_info_get_value(). Release this list with
2210 * kmod_module_info_free_list()
2211 *
2212 * Get a list of entries in ELF section ".modinfo", these contain
2213 * alias, license, depends, vermagic and other keys with respective
2214 * values. If the module is signed (CONFIG_MODULE_SIG), information
2215 * about the module signature is included as well: signer,
2216 * sig_key and sig_hashalgo.
2217 *
2218 * After use, free the @list by calling kmod_module_info_free_list().
2219 *
2220 * Returns: 0 on success or < 0 otherwise.
2221 */
2222 int kmod_module_get_info(const struct kmod_module *mod, struct kmod_list **list)
2223 {
2224 struct kmod_elf *elf;
2225 char **strings;
2226 int i, count, ret = -ENOMEM;
2227 struct kmod_signature_info sig_info;
2228
2229 if (mod == NULL || list == NULL)
2230 return -ENOENT;
2231
2232 assert(*list == NULL);
2233
2234 elf = kmod_module_get_elf(mod);
2235 if (elf == NULL)
2236 return -errno;
2237
2238 count = kmod_elf_get_strings(elf, ".modinfo", &strings);
2239 if (count < 0)
2240 return count;
2241
2242 for (i = 0; i < count; i++) {
2243 struct kmod_list *n;
2244 const char *key, *value;
2245 size_t keylen, valuelen;
2246
2247 key = strings[i];
2248 value = strchr(key, '=');
2249 if (value == NULL) {
2250 keylen = strlen(key);
2251 valuelen = 0;
2252 value = key;
2253 } else {
2254 keylen = value - key;
2255 value++;
2256 valuelen = strlen(value);
2257 }
2258
2259 n = kmod_module_info_append(list, key, keylen, value, valuelen);
2260 if (n == NULL)
2261 goto list_error;
2262 }
2263
2264 if (kmod_module_signature_info(mod->file, &sig_info)) {
2265 struct kmod_list *n;
2266 char *key_hex;
2267
2268 n = kmod_module_info_append(list, "signature", strlen("sig_id"),
2269 sig_info.id_type, strlen(sig_info.id_type));
2270 if (n == NULL)
2271 goto list_error;
2272 count++;
2273
2274 n = kmod_module_info_append(list, "signer", strlen("signer"),
2275 sig_info.signer, sig_info.signer_len);
2276 if (n == NULL)
2277 goto list_error;
2278 count++;
2279
2280 if (sig_info.key_id_len) {
2281 /* Display the key id as 01:12:DE:AD:BE:EF:... */
2282 key_hex = malloc(sig_info.key_id_len * 3);
2283 if (key_hex == NULL)
2284 goto list_error;
2285 for (i = 0; i < (int)sig_info.key_id_len; i++) {
2286 sprintf(key_hex + i * 3, "%02X",
2287 (unsigned char)sig_info.key_id[i]);
2288 if (i < (int)sig_info.key_id_len - 1)
2289 key_hex[i * 3 + 2] = ':';
2290 }
2291 n = kmod_module_info_append(list, "sig_key", strlen("sig_key"),
2292 key_hex, sig_info.key_id_len * 3 - 1);
2293 free(key_hex);
2294 if (n == NULL)
2295 goto list_error;
2296 count++;
2297 } else {
2298 n = kmod_module_info_append(list, "sig_key", strlen("sig_key"),
2299 NULL, 0);
2300 if (n == NULL)
2301 goto list_error;
2302 count++;
2303 }
2304
2305 n = kmod_module_info_append(list,
2306 "sig_hashalgo", strlen("sig_hashalgo"),
2307 sig_info.hash_algo, strlen(sig_info.hash_algo));
2308 if (n == NULL)
2309 goto list_error;
2310 count++;
2311
2312 /*
2313 * Omit sig_info.algo for now, as these
2314 * are currently constant.
2315 */
2316 }
2317 ret = count;
2318
2319 list_error:
2320 if (ret < 0) {
2321 kmod_module_info_free_list(*list);
2322 *list = NULL;
2323 }
2324 free(strings);
2325 return ret;
2326 }
2327
2328 /**
2329 * kmod_module_info_get_key:
2330 * @entry: a list entry representing a kmod module info
2331 *
2332 * Get the key of a kmod module info.
2333 *
2334 * Returns: the key of this kmod module info on success or NULL on
2335 * failure. The string is owned by the info, do not free it.
2336 */
2337 const char *kmod_module_info_get_key(const struct kmod_list *entry)
2338 {
2339 struct kmod_module_info *info;
2340
2341 if (entry == NULL)
2342 return NULL;
2343
2344 info = entry->data;
2345 return info->key;
2346 }
2347
2348 /**
2349 * kmod_module_info_get_value:
2350 * @entry: a list entry representing a kmod module info
2351 *
2352 * Get the value of a kmod module info.
2353 *
2354 * Returns: the value of this kmod module info on success or NULL on
2355 * failure. The string is owned by the info, do not free it.
2356 */
2357 const char *kmod_module_info_get_value(const struct kmod_list *entry)
2358 {
2359 struct kmod_module_info *info;
2360
2361 if (entry == NULL)
2362 return NULL;
2363
2364 info = entry->data;
2365 return info->value;
2366 }
2367
2368 /**
2369 * kmod_module_info_free_list:
2370 * @list: kmod module info list
2371 *
2372 * Release the resources taken by @list
2373 */
2374 void kmod_module_info_free_list(struct kmod_list *list)
2375 {
2376 while (list) {
2377 kmod_module_info_free(list->data);
2378 list = __kmod_list_remove(list);
2379 }
2380 }
2381
2382 struct kmod_module_version {
2383 uint64_t crc;
2384 char symbol[];
2385 };
2386
2387 static struct kmod_module_version *kmod_module_versions_new(uint64_t crc, const char *symbol)
2388 {
2389 struct kmod_module_version *mv;
2390 size_t symbollen = strlen(symbol) + 1;
2391
2392 mv = malloc(sizeof(struct kmod_module_version) + symbollen);
2393 if (mv == NULL)
2394 return NULL;
2395
2396 mv->crc = crc;
2397 memcpy(mv->symbol, symbol, symbollen);
2398 return mv;
2399 }
2400
2401 static void kmod_module_version_free(struct kmod_module_version *version)
2402 {
2403 free(version);
2404 }
2405
2406 /**
2407 * kmod_module_get_versions:
2408 * @mod: kmod module
2409 * @list: where to return list of module versions. Use
2410 * kmod_module_version_get_symbol() and
2411 * kmod_module_version_get_crc(). Release this list with
2412 * kmod_module_versions_free_list()
2413 *
2414 * Get a list of entries in ELF section "__versions".
2415 *
2416 * After use, free the @list by calling kmod_module_versions_free_list().
2417 *
2418 * Returns: 0 on success or < 0 otherwise.
2419 */
2420 int kmod_module_get_versions(const struct kmod_module *mod, struct kmod_list **list)
2421 {
2422 struct kmod_elf *elf;
2423 struct kmod_modversion *versions;
2424 int i, count, ret = 0;
2425
2426 if (mod == NULL || list == NULL)
2427 return -ENOENT;
2428
2429 assert(*list == NULL);
2430
2431 elf = kmod_module_get_elf(mod);
2432 if (elf == NULL)
2433 return -errno;
2434
2435 count = kmod_elf_get_modversions(elf, &versions);
2436 if (count < 0)
2437 return count;
2438
2439 for (i = 0; i < count; i++) {
2440 struct kmod_module_version *mv;
2441 struct kmod_list *n;
2442
2443 mv = kmod_module_versions_new(versions[i].crc, versions[i].symbol);
2444 if (mv == NULL) {
2445 ret = -errno;
2446 kmod_module_versions_free_list(*list);
2447 *list = NULL;
2448 goto list_error;
2449 }
2450
2451 n = __kmod_list_append(*list, mv);
2452 if (n != NULL)
2453 *list = n;
2454 else {
2455 kmod_module_version_free(mv);
2456 kmod_module_versions_free_list(*list);
2457 *list = NULL;
2458 ret = -ENOMEM;
2459 goto list_error;
2460 }
2461 }
2462 ret = count;
2463
2464 list_error:
2465 free(versions);
2466 return ret;
2467 }
2468
2469 /**
2470 * kmod_module_version_get_symbol:
2471 * @entry: a list entry representing a kmod module versions
2472 *
2473 * Get the symbol of a kmod module versions.
2474 *
2475 * Returns: the symbol of this kmod module versions on success or NULL
2476 * on failure. The string is owned by the versions, do not free it.
2477 */
2478 const char *kmod_module_version_get_symbol(const struct kmod_list *entry)
2479 {
2480 struct kmod_module_version *version;
2481
2482 if (entry == NULL)
2483 return NULL;
2484
2485 version = entry->data;
2486 return version->symbol;
2487 }
2488
2489 /**
2490 * kmod_module_version_get_crc:
2491 * @entry: a list entry representing a kmod module version
2492 *
2493 * Get the crc of a kmod module version.
2494 *
2495 * Returns: the crc of this kmod module version on success or NULL on
2496 * failure. The string is owned by the version, do not free it.
2497 */
2498 uint64_t kmod_module_version_get_crc(const struct kmod_list *entry)
2499 {
2500 struct kmod_module_version *version;
2501
2502 if (entry == NULL)
2503 return 0;
2504
2505 version = entry->data;
2506 return version->crc;
2507 }
2508
2509 /**
2510 * kmod_module_versions_free_list:
2511 * @list: kmod module versions list
2512 *
2513 * Release the resources taken by @list
2514 */
2515 void kmod_module_versions_free_list(struct kmod_list *list)
2516 {
2517 while (list) {
2518 kmod_module_version_free(list->data);
2519 list = __kmod_list_remove(list);
2520 }
2521 }
2522
2523 struct kmod_module_symbol {
2524 uint64_t crc;
2525 char symbol[];
2526 };
2527
2528 static struct kmod_module_symbol *kmod_module_symbols_new(uint64_t crc, const char *symbol)
2529 {
2530 struct kmod_module_symbol *mv;
2531 size_t symbollen = strlen(symbol) + 1;
2532
2533 mv = malloc(sizeof(struct kmod_module_symbol) + symbollen);
2534 if (mv == NULL)
2535 return NULL;
2536
2537 mv->crc = crc;
2538 memcpy(mv->symbol, symbol, symbollen);
2539 return mv;
2540 }
2541
2542 static void kmod_module_symbol_free(struct kmod_module_symbol *symbol)
2543 {
2544 free(symbol);
2545 }
2546
2547 /**
2548 * kmod_module_get_symbols:
2549 * @mod: kmod module
2550 * @list: where to return list of module symbols. Use
2551 * kmod_module_symbol_get_symbol() and
2552 * kmod_module_symbol_get_crc(). Release this list with
2553 * kmod_module_symbols_free_list()
2554 *
2555 * Get a list of entries in ELF section ".symtab" or "__ksymtab_strings".
2556 *
2557 * After use, free the @list by calling kmod_module_symbols_free_list().
2558 *
2559 * Returns: 0 on success or < 0 otherwise.
2560 */
2561 int kmod_module_get_symbols(const struct kmod_module *mod, struct kmod_list **list)
2562 {
2563 struct kmod_elf *elf;
2564 struct kmod_modversion *symbols;
2565 int i, count, ret = 0;
2566
2567 if (mod == NULL || list == NULL)
2568 return -ENOENT;
2569
2570 assert(*list == NULL);
2571
2572 elf = kmod_module_get_elf(mod);
2573 if (elf == NULL)
2574 return -errno;
2575
2576 count = kmod_elf_get_symbols(elf, &symbols);
2577 if (count < 0)
2578 return count;
2579
2580 for (i = 0; i < count; i++) {
2581 struct kmod_module_symbol *mv;
2582 struct kmod_list *n;
2583
2584 mv = kmod_module_symbols_new(symbols[i].crc, symbols[i].symbol);
2585 if (mv == NULL) {
2586 ret = -errno;
2587 kmod_module_symbols_free_list(*list);
2588 *list = NULL;
2589 goto list_error;
2590 }
2591
2592 n = __kmod_list_append(*list, mv);
2593 if (n != NULL)
2594 *list = n;
2595 else {
2596 kmod_module_symbol_free(mv);
2597 kmod_module_symbols_free_list(*list);
2598 *list = NULL;
2599 ret = -ENOMEM;
2600 goto list_error;
2601 }
2602 }
2603 ret = count;
2604
2605 list_error:
2606 free(symbols);
2607 return ret;
2608 }
2609
2610 /**
2611 * kmod_module_symbol_get_symbol:
2612 * @entry: a list entry representing a kmod module symbols
2613 *
2614 * Get the symbol of a kmod module symbols.
2615 *
2616 * Returns: the symbol of this kmod module symbols on success or NULL
2617 * on failure. The string is owned by the symbols, do not free it.
2618 */
2619 const char *kmod_module_symbol_get_symbol(const struct kmod_list *entry)
2620 {
2621 struct kmod_module_symbol *symbol;
2622
2623 if (entry == NULL)
2624 return NULL;
2625
2626 symbol = entry->data;
2627 return symbol->symbol;
2628 }
2629
2630 /**
2631 * kmod_module_symbol_get_crc:
2632 * @entry: a list entry representing a kmod module symbol
2633 *
2634 * Get the crc of a kmod module symbol.
2635 *
2636 * Returns: the crc of this kmod module symbol on success or NULL on
2637 * failure. The string is owned by the symbol, do not free it.
2638 */
2639 uint64_t kmod_module_symbol_get_crc(const struct kmod_list *entry)
2640 {
2641 struct kmod_module_symbol *symbol;
2642
2643 if (entry == NULL)
2644 return 0;
2645
2646 symbol = entry->data;
2647 return symbol->crc;
2648 }
2649
2650 /**
2651 * kmod_module_symbols_free_list:
2652 * @list: kmod module symbols list
2653 *
2654 * Release the resources taken by @list
2655 */
2656 void kmod_module_symbols_free_list(struct kmod_list *list)
2657 {
2658 while (list) {
2659 kmod_module_symbol_free(list->data);
2660 list = __kmod_list_remove(list);
2661 }
2662 }
2663
2664 struct kmod_module_dependency_symbol {
2665 uint64_t crc;
2666 uint8_t bind;
2667 char symbol[];
2668 };
2669
2670 static struct kmod_module_dependency_symbol *kmod_module_dependency_symbols_new(uint64_t crc, uint8_t bind, const char *symbol)
2671 {
2672 struct kmod_module_dependency_symbol *mv;
2673 size_t symbollen = strlen(symbol) + 1;
2674
2675 mv = malloc(sizeof(struct kmod_module_dependency_symbol) + symbollen);
2676 if (mv == NULL)
2677 return NULL;
2678
2679 mv->crc = crc;
2680 mv->bind = bind;
2681 memcpy(mv->symbol, symbol, symbollen);
2682 return mv;
2683 }
2684
2685 static void kmod_module_dependency_symbol_free(struct kmod_module_dependency_symbol *dependency_symbol)
2686 {
2687 free(dependency_symbol);
2688 }
2689
2690 /**
2691 * kmod_module_get_dependency_symbols:
2692 * @mod: kmod module
2693 * @list: where to return list of module dependency_symbols. Use
2694 * kmod_module_dependency_symbol_get_symbol() and
2695 * kmod_module_dependency_symbol_get_crc(). Release this list with
2696 * kmod_module_dependency_symbols_free_list()
2697 *
2698 * Get a list of entries in ELF section ".symtab" or "__ksymtab_strings".
2699 *
2700 * After use, free the @list by calling
2701 * kmod_module_dependency_symbols_free_list().
2702 *
2703 * Returns: 0 on success or < 0 otherwise.
2704 */
2705 int kmod_module_get_dependency_symbols(const struct kmod_module *mod, struct kmod_list **list)
2706 {
2707 struct kmod_elf *elf;
2708 struct kmod_modversion *symbols;
2709 int i, count, ret = 0;
2710
2711 if (mod == NULL || list == NULL)
2712 return -ENOENT;
2713
2714 assert(*list == NULL);
2715
2716 elf = kmod_module_get_elf(mod);
2717 if (elf == NULL)
2718 return -errno;
2719
2720 count = kmod_elf_get_dependency_symbols(elf, &symbols);
2721 if (count < 0)
2722 return count;
2723
2724 for (i = 0; i < count; i++) {
2725 struct kmod_module_dependency_symbol *mv;
2726 struct kmod_list *n;
2727
2728 mv = kmod_module_dependency_symbols_new(symbols[i].crc,
2729 symbols[i].bind,
2730 symbols[i].symbol);
2731 if (mv == NULL) {
2732 ret = -errno;
2733 kmod_module_dependency_symbols_free_list(*list);
2734 *list = NULL;
2735 goto list_error;
2736 }
2737
2738 n = __kmod_list_append(*list, mv);
2739 if (n != NULL)
2740 *list = n;
2741 else {
2742 kmod_module_dependency_symbol_free(mv);
2743 kmod_module_dependency_symbols_free_list(*list);
2744 *list = NULL;
2745 ret = -ENOMEM;
2746 goto list_error;
2747 }
2748 }
2749 ret = count;
2750
2751 list_error:
2752 free(symbols);
2753 return ret;
2754 }
2755
2756 /**
2757 * kmod_module_dependency_symbol_get_symbol:
2758 * @entry: a list entry representing a kmod module dependency_symbols
2759 *
2760 * Get the dependency symbol of a kmod module
2761 *
2762 * Returns: the symbol of this kmod module dependency_symbols on success or NULL
2763 * on failure. The string is owned by the dependency_symbols, do not free it.
2764 */
2765 const char *kmod_module_dependency_symbol_get_symbol(const struct kmod_list *entry)
2766 {
2767 struct kmod_module_dependency_symbol *dependency_symbol;
2768
2769 if (entry == NULL)
2770 return NULL;
2771
2772 dependency_symbol = entry->data;
2773 return dependency_symbol->symbol;
2774 }
2775
2776 /**
2777 * kmod_module_dependency_symbol_get_crc:
2778 * @entry: a list entry representing a kmod module dependency_symbol
2779 *
2780 * Get the crc of a kmod module dependency_symbol.
2781 *
2782 * Returns: the crc of this kmod module dependency_symbol on success or NULL on
2783 * failure. The string is owned by the dependency_symbol, do not free it.
2784 */
2785 uint64_t kmod_module_dependency_symbol_get_crc(const struct kmod_list *entry)
2786 {
2787 struct kmod_module_dependency_symbol *dependency_symbol;
2788
2789 if (entry == NULL)
2790 return 0;
2791
2792 dependency_symbol = entry->data;
2793 return dependency_symbol->crc;
2794 }
2795
2796 /**
2797 * kmod_module_dependency_symbol_get_bind:
2798 * @entry: a list entry representing a kmod module dependency_symbol
2799 *
2800 * Get the bind type of a kmod module dependency_symbol.
2801 *
2802 * Returns: the bind of this kmod module dependency_symbol on success
2803 * or < 0 on failure.
2804 */
2805 int kmod_module_dependency_symbol_get_bind(const struct kmod_list *entry)
2806 {
2807 struct kmod_module_dependency_symbol *dependency_symbol;
2808
2809 if (entry == NULL)
2810 return 0;
2811
2812 dependency_symbol = entry->data;
2813 return dependency_symbol->bind;
2814 }
2815
2816 /**
2817 * kmod_module_dependency_symbols_free_list:
2818 * @list: kmod module dependency_symbols list
2819 *
2820 * Release the resources taken by @list
2821 */
2822 void kmod_module_dependency_symbols_free_list(struct kmod_list *list)
2823 {
2824 while (list) {
2825 kmod_module_dependency_symbol_free(list->data);
2826 list = __kmod_list_remove(list);
2827 }
2828 }
File src/libkmod-namespace.h added (mode: 100644) (index 0000000..9eb2892)
1 #ifndef LIBKMOD_NAMESPACE
2 #define LIBKMOD_NAMESPACE
3 #ifdef NAMESPACE_ON
4 /*----------------------------------------------------------------------------*/
5 /* util */
6 #define strchr_replace libkmod_strchr_replace
7 #define memdup libkmod_memdup
8 #define asprintf libkmod_asprintf
9 #define vasprintf libkmod_vasprintf
10 #define alias_normalize libkmod_alias_normalize
11 #define underscores libkmod_underscores
12 #define modname_normalize libkmod_modname_normalize
13 #define path_to_modname libkmod_path_to_modname
14 #define path_ends_with_kmod_ext libkmod_path_ends_with_kmod_ext
15 #define read_str_safe libkmod_read_str_safe
16 #define write_str_safe libkmod_write_str_safe
17 #define read_str_long libkmod_read_str_long
18 #define read_str_ulong libkmod_read_str_ulong
19 #define freadline_wrapped libkmod_freadline_wrapped
20 #define path_is_absolute libkmod_path_is_absolute
21 #define path_make_absolute_cwd libkmod_path_make_absolute_cwd
22 #define mkdir_p libkmod_mkdir_p
23 #define mkdir_parents libkmod_mkdir_parents
24 #define stat_mstamp libkmod_stat_mstamp
25 #define ts_usec libkmod_ts_usec
26 /*----------------------------------------------------------------------------*/
27
28 /*----------------------------------------------------------------------------*/
29 /* strbuf */
30 #define strbuf_init libkmod_strbuf_init
31 #define strbuf_release libkmod_strbuf_release
32 #define strbuf_clear libkmod_strbuf_clear
33 #define strbuf_steal libkmod_strbuf_steal
34 #define strbuf_str libkmod_strbuf_str
35 #define strbuf_pushchar libkmod_strbuf_pushchar
36 #define strbuf_pushchars libkmod_strbuf_pushchars
37 #define strbuf_popchar libkmod_strbuf_popchar
38 #define strbuf_popchars libkmod_strbuf_popchars
39 /*----------------------------------------------------------------------------*/
40 #endif
41 #endif
File src/libkmod-signature.c added (mode: 100644) (index 0000000..45fad29)
1 /*
2 * libkmod - module signature display
3 *
4 * Copyright (C) 2013 Michal Marek, SUSE
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <endian.h>
21 #include <inttypes.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <limits.h>
26
27 #include "config.h"
28
29 #include "libkmod.h"
30 #include "libkmod-namespace.h"
31 #include "libkmod-paths.h"
32 #include "shared/macro.h"
33 #include "shared/util.h"
34 #define LIBKMOD_SIGNATURE_C
35 #include "libkmod-internal.h"
36 #undef LIBKMOD_SIGNATURE_C
37
38 /* These types and tables were copied from the 3.7 kernel sources.
39 * As this is just description of the signature format, it should not be
40 * considered derived work (so libkmod can use the LGPL license).
41 */
42 enum pkey_algo {
43 PKEY_ALGO_DSA,
44 PKEY_ALGO_RSA,
45 PKEY_ALGO__LAST
46 };
47
48 static const char *const pkey_algo[PKEY_ALGO__LAST] = {
49 [PKEY_ALGO_DSA] = "DSA",
50 [PKEY_ALGO_RSA] = "RSA",
51 };
52
53 enum pkey_hash_algo {
54 PKEY_HASH_MD4,
55 PKEY_HASH_MD5,
56 PKEY_HASH_SHA1,
57 PKEY_HASH_RIPE_MD_160,
58 PKEY_HASH_SHA256,
59 PKEY_HASH_SHA384,
60 PKEY_HASH_SHA512,
61 PKEY_HASH_SHA224,
62 PKEY_HASH__LAST
63 };
64
65 const char *const pkey_hash_algo[PKEY_HASH__LAST] = {
66 [PKEY_HASH_MD4] = "md4",
67 [PKEY_HASH_MD5] = "md5",
68 [PKEY_HASH_SHA1] = "sha1",
69 [PKEY_HASH_RIPE_MD_160] = "rmd160",
70 [PKEY_HASH_SHA256] = "sha256",
71 [PKEY_HASH_SHA384] = "sha384",
72 [PKEY_HASH_SHA512] = "sha512",
73 [PKEY_HASH_SHA224] = "sha224",
74 };
75
76 enum pkey_id_type {
77 PKEY_ID_PGP, /* OpenPGP generated key ID */
78 PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */
79 PKEY_ID_PKCS7, /* Signature in PKCS#7 message */
80 PKEY_ID_TYPE__LAST
81 };
82
83 const char *const pkey_id_type[PKEY_ID_TYPE__LAST] = {
84 [PKEY_ID_PGP] = "PGP",
85 [PKEY_ID_X509] = "X509",
86 [PKEY_ID_PKCS7] = "PKCS#7",
87 };
88
89 /*
90 * Module signature information block.
91 */
92 struct module_signature {
93 uint8_t algo; /* Public-key crypto algorithm [enum pkey_algo] */
94 uint8_t hash; /* Digest algorithm [enum pkey_hash_algo] */
95 uint8_t id_type; /* Key identifier type [enum pkey_id_type] */
96 uint8_t signer_len; /* Length of signer's name */
97 uint8_t key_id_len; /* Length of key identifier */
98 uint8_t __pad[3];
99 uint32_t sig_len; /* Length of signature data (big endian) */
100 };
101
102 #define SIG_MAGIC "~Module signature appended~\n"
103
104 /*
105 * A signed module has the following layout:
106 *
107 * [ module ]
108 * [ signer's name ]
109 * [ key identifier ]
110 * [ signature data ]
111 * [ struct module_signature ]
112 * [ SIG_MAGIC ]
113 */
114
115 bool kmod_module_signature_info(const struct kmod_file *file, struct kmod_signature_info *sig_info)
116 {
117 const char *mem;
118 off_t size;
119 const struct module_signature *modsig;
120 size_t sig_len;
121
122
123 size = kmod_file_get_size(file);
124 mem = kmod_file_get_contents(file);
125 if (size < (off_t)strlen(SIG_MAGIC))
126 return false;
127 size -= strlen(SIG_MAGIC);
128 if (memcmp(SIG_MAGIC, mem + size, strlen(SIG_MAGIC)) != 0)
129 return false;
130
131 if (size < (off_t)sizeof(struct module_signature))
132 return false;
133 size -= sizeof(struct module_signature);
134 modsig = (struct module_signature *)(mem + size);
135 if (modsig->algo >= PKEY_ALGO__LAST ||
136 modsig->hash >= PKEY_HASH__LAST ||
137 modsig->id_type >= PKEY_ID_TYPE__LAST)
138 return false;
139 sig_len = be32toh(modsig->sig_len);
140 if (sig_len == 0 ||
141 size < (int64_t)(modsig->signer_len + modsig->key_id_len + sig_len))
142 return false;
143
144 size -= modsig->key_id_len + sig_len;
145 sig_info->key_id = mem + size;
146 sig_info->key_id_len = modsig->key_id_len;
147
148 size -= modsig->signer_len;
149 sig_info->signer = mem + size;
150 sig_info->signer_len = modsig->signer_len;
151
152 sig_info->algo = pkey_algo[modsig->algo];
153 sig_info->hash_algo = pkey_hash_algo[modsig->hash];
154 sig_info->id_type = pkey_id_type[modsig->id_type];
155
156 return true;
157 }
File src/libkmod.c added (mode: 100644) (index 0000000..5134e7b)
1 /*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <assert.h>
21 #include <ctype.h>
22 #include <errno.h>
23 #include <fnmatch.h>
24 #include <limits.h>
25 #include <stdarg.h>
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <stdbool.h>
32 #include <stdint.h>
33 #include <syslog.h>
34 #include <sys/stat.h>
35 #include <sys/utsname.h>
36
37 #include "config.h"
38
39 #include "libkmod.h"
40
41 #include "libkmod-namespace.h"
42 #include "libkmod-paths.h"
43 #include "shared/macro.h"
44 #include "shared/hash.h"
45 #include "shared/util.h"
46 #define LIBKMOD_C
47 #include "libkmod-internal.h"
48 #undef LIBKMOD_C
49 #include "libkmod-index.h"
50
51 #define KMOD_HASH_SIZE (256)
52 #define KMOD_LRU_MAX (128)
53 #define _KMOD_INDEX_MODULES_SIZE KMOD_INDEX_MODULES_BUILTIN + 1
54
55 /**
56 * SECTION:libkmod
57 * @short_description: libkmod context
58 *
59 * The context contains the default values for the library user,
60 * and is passed to all library operations.
61 */
62
63 static struct _index_files {
64 const char *fn;
65 const char *prefix;
66 } index_files[] = {
67 [KMOD_INDEX_MODULES_DEP] = { .fn = "modules.dep", .prefix = "" },
68 [KMOD_INDEX_MODULES_ALIAS] = { .fn = "modules.alias", .prefix = "alias " },
69 [KMOD_INDEX_MODULES_SYMBOL] = { .fn = "modules.symbols", .prefix = "alias "},
70 [KMOD_INDEX_MODULES_BUILTIN] = { .fn = "modules.builtin", .prefix = ""},
71 };
72
73 static const char *default_config_paths[] = {
74 SYSCONFDIR "/modprobe.d",
75 "/run/modprobe.d",
76 "/lib/modprobe.d",
77 NULL
78 };
79
80 /**
81 * kmod_ctx:
82 *
83 * Opaque object representing the library context.
84 */
85 struct kmod_ctx {
86 int refcount;
87 int log_priority;
88 void (*log_fn)(void *data,
89 int priority, const char *file, int line,
90 const char *fn, const char *format, va_list args);
91 void *log_data;
92 const void *userdata;
93 char *dirname;
94 struct kmod_config *config;
95 struct hash *modules_by_name;
96 struct index_mm *indexes[_KMOD_INDEX_MODULES_SIZE];
97 unsigned long long indexes_stamp[_KMOD_INDEX_MODULES_SIZE];
98 };
99
100 void kmod_log(const struct kmod_ctx *ctx,
101 int priority, const char *file, int line, const char *fn,
102 const char *format, ...)
103 {
104 va_list args;
105
106 if (ctx->log_fn == NULL)
107 return;
108
109 va_start(args, format);
110 ctx->log_fn(ctx->log_data, priority, file, line, fn, format, args);
111 va_end(args);
112 }
113
114 static void log_filep(void *data,
115 int priority, const char *file, int line,
116 const char *fn, const char *format, va_list args)
117 {
118 FILE *fp = data;
119 #ifdef ENABLE_DEBUG
120 char buf[16];
121 const char *priname;
122 switch (priority) {
123 case LOG_EMERG:
124 priname = "EMERGENCY";
125 break;
126 case LOG_ALERT:
127 priname = "ALERT";
128 break;
129 case LOG_CRIT:
130 priname = "CRITICAL";
131 break;
132 case LOG_ERR:
133 priname = "ERROR";
134 break;
135 case LOG_WARNING:
136 priname = "WARNING";
137 break;
138 case LOG_NOTICE:
139 priname = "NOTICE";
140 break;
141 case LOG_INFO:
142 priname = "INFO";
143 break;
144 case LOG_DEBUG:
145 priname = "DEBUG";
146 break;
147 default:
148 snprintf(buf, sizeof(buf), "L:%d", priority);
149 priname = buf;
150 }
151 fprintf(fp, "libkmod: %s %s:%d %s: ", priname, file, line, fn);
152 #else
153 fprintf(fp, "libkmod: %s: ", fn);
154 #endif
155 vfprintf(fp, format, args);
156 }
157
158
159 /**
160 * kmod_get_dirname:
161 * @ctx: kmod library context
162 *
163 * Retrieve the absolute path used for linux modules in this context. The path
164 * is computed from the arguments to kmod_new().
165 */
166 const char *kmod_get_dirname(const struct kmod_ctx *ctx)
167 {
168 return ctx->dirname;
169 }
170
171 /**
172 * kmod_get_userdata:
173 * @ctx: kmod library context
174 *
175 * Retrieve stored data pointer from library context. This might be useful
176 * to access from callbacks.
177 *
178 * Returns: stored userdata
179 */
180 void *kmod_get_userdata(const struct kmod_ctx *ctx)
181 {
182 if (ctx == NULL)
183 return NULL;
184 return (void *)ctx->userdata;
185 }
186
187 /**
188 * kmod_set_userdata:
189 * @ctx: kmod library context
190 * @userdata: data pointer
191 *
192 * Store custom @userdata in the library context.
193 */
194 void kmod_set_userdata(struct kmod_ctx *ctx, const void *userdata)
195 {
196 if (ctx == NULL)
197 return;
198 ctx->userdata = userdata;
199 }
200
201 static int log_priority(const char *priority)
202 {
203 char *endptr;
204 int prio;
205
206 prio = strtol(priority, &endptr, 10);
207 if (endptr[0] == '\0' || isspace(endptr[0]))
208 return prio;
209 if (strncmp(priority, "err", 3) == 0)
210 return LOG_ERR;
211 if (strncmp(priority, "info", 4) == 0)
212 return LOG_INFO;
213 if (strncmp(priority, "debug", 5) == 0)
214 return LOG_DEBUG;
215 return 0;
216 }
217
218 static const char *dirname_default_prefix = "/lib/modules";
219
220 static char *get_kernel_release(const char *dirname)
221 {
222 struct utsname u;
223 char *p;
224
225 if (dirname != NULL)
226 return path_make_absolute_cwd(dirname);
227
228 if (uname(&u) < 0)
229 return NULL;
230
231 if (asprintf(&p, "%s/%s", dirname_default_prefix, u.release) < 0)
232 return NULL;
233
234 return p;
235 }
236
237 /**
238 * kmod_new:
239 * @dirname: what to consider as linux module's directory, if NULL
240 * defaults to /lib/modules/`uname -r`. If it's relative,
241 * it's treated as relative to the current working directory.
242 * Otherwise, give an absolute dirname.
243 * @config_paths: ordered array of paths (directories or files) where
244 * to load from user-defined configuration parameters such as
245 * alias, blacklists, commands (install, remove). If
246 * NULL defaults to /run/modprobe.d, /etc/modprobe.d and
247 * /lib/modprobe.d. Give an empty vector if configuration should
248 * not be read. This array must be null terminated.
249 *
250 * Create kmod library context. This reads the kmod configuration
251 * and fills in the default values.
252 *
253 * The initial refcount is 1, and needs to be decremented to
254 * release the resources of the kmod library context.
255 *
256 * Returns: a new kmod library context
257 */
258 struct kmod_ctx *kmod_new(const char *dirname,
259 const char * const *config_paths)
260 {
261 const char *env;
262 struct kmod_ctx *ctx;
263 int err;
264
265 ctx = calloc(1, sizeof(struct kmod_ctx));
266 if (!ctx)
267 return NULL;
268
269 ctx->refcount = 1;
270 ctx->log_fn = log_filep;
271 ctx->log_data = stderr;
272 ctx->log_priority = LOG_ERR;
273
274 ctx->dirname = get_kernel_release(dirname);
275
276 /* environment overwrites config */
277 env = getenv("KMOD_LOG");
278 if (env != NULL)
279 kmod_set_log_priority(ctx, log_priority(env));
280
281 if (config_paths == NULL)
282 config_paths = default_config_paths;
283 err = kmod_config_new(ctx, &ctx->config, config_paths);
284 if (err < 0) {
285 ERR(ctx, "could not create config\n");
286 goto fail;
287 }
288
289 ctx->modules_by_name = hash_new(KMOD_HASH_SIZE, NULL);
290 if (ctx->modules_by_name == NULL) {
291 ERR(ctx, "could not create by-name hash\n");
292 goto fail;
293 }
294
295 INFO(ctx, "ctx %p created\n", ctx);
296 DBG(ctx, "log_priority=%d\n", ctx->log_priority);
297
298 return ctx;
299
300 fail:
301 free(ctx->modules_by_name);
302 free(ctx->dirname);
303 free(ctx);
304 return NULL;
305 }
306
307 /**
308 * kmod_ref:
309 * @ctx: kmod library context
310 *
311 * Take a reference of the kmod library context.
312 *
313 * Returns: the passed kmod library context
314 */
315 struct kmod_ctx *kmod_ref(struct kmod_ctx *ctx)
316 {
317 if (ctx == NULL)
318 return NULL;
319 ctx->refcount++;
320 return ctx;
321 }
322
323 /**
324 * kmod_unref:
325 * @ctx: kmod library context
326 *
327 * Drop a reference of the kmod library context. If the refcount
328 * reaches zero, the resources of the context will be released.
329 *
330 * Returns: the passed kmod library context or NULL if it's freed
331 */
332 struct kmod_ctx *kmod_unref(struct kmod_ctx *ctx)
333 {
334 if (ctx == NULL)
335 return NULL;
336
337 if (--ctx->refcount > 0)
338 return ctx;
339
340 INFO(ctx, "context %p released\n", ctx);
341
342 kmod_unload_resources(ctx);
343 hash_free(ctx->modules_by_name);
344 free(ctx->dirname);
345 if (ctx->config)
346 kmod_config_free(ctx->config);
347
348 free(ctx);
349 return NULL;
350 }
351
352 /**
353 * kmod_set_log_fn:
354 * @ctx: kmod library context
355 * @log_fn: function to be called for logging messages
356 * @data: data to pass to log function
357 *
358 * The built-in logging writes to stderr. It can be
359 * overridden by a custom function, to plug log messages
360 * into the user's logging functionality.
361 */
362 void kmod_set_log_fn(struct kmod_ctx *ctx,
363 void (*log_fn)(void *data,
364 int priority, const char *file,
365 int line, const char *fn,
366 const char *format, va_list args),
367 const void *data)
368 {
369 if (ctx == NULL)
370 return;
371 ctx->log_fn = log_fn;
372 ctx->log_data = (void *)data;
373 INFO(ctx, "custom logging function %p registered\n", log_fn);
374 }
375
376 /**
377 * kmod_get_log_priority:
378 * @ctx: kmod library context
379 *
380 * Returns: the current logging priority
381 */
382 int kmod_get_log_priority(const struct kmod_ctx *ctx)
383 {
384 if (ctx == NULL)
385 return -1;
386 return ctx->log_priority;
387 }
388
389 /**
390 * kmod_set_log_priority:
391 * @ctx: kmod library context
392 * @priority: the new logging priority
393 *
394 * Set the current logging priority. The value controls which messages
395 * are logged.
396 */
397 void kmod_set_log_priority(struct kmod_ctx *ctx, int priority)
398 {
399 if (ctx == NULL)
400 return;
401 ctx->log_priority = priority;
402 }
403
404 struct kmod_module *kmod_pool_get_module(struct kmod_ctx *ctx,
405 const char *key)
406 {
407 struct kmod_module *mod;
408
409 mod = hash_find(ctx->modules_by_name, key);
410
411 DBG(ctx, "get module name='%s' found=%p\n", key, mod);
412
413 return mod;
414 }
415
416 void kmod_pool_add_module(struct kmod_ctx *ctx, struct kmod_module *mod,
417 const char *key)
418 {
419 DBG(ctx, "add %p key='%s'\n", mod, key);
420
421 hash_add(ctx->modules_by_name, key, mod);
422 }
423
424 void kmod_pool_del_module(struct kmod_ctx *ctx, struct kmod_module *mod,
425 const char *key)
426 {
427 DBG(ctx, "del %p key='%s'\n", mod, key);
428
429 hash_del(ctx->modules_by_name, key);
430 }
431
432 static int kmod_lookup_alias_from_alias_bin(struct kmod_ctx *ctx,
433 enum kmod_index index_number,
434 const char *name,
435 struct kmod_list **list)
436 {
437 int err, nmatch = 0;
438 struct index_file *idx;
439 struct index_value *realnames, *realname;
440
441 if (ctx->indexes[index_number] != NULL) {
442 DBG(ctx, "use mmaped index '%s' for name=%s\n",
443 index_files[index_number].fn, name);
444 realnames = index_mm_searchwild(ctx->indexes[index_number],
445 name);
446 } else {
447 char fn[PATH_MAX];
448
449 snprintf(fn, sizeof(fn), "%s/%s.bin", ctx->dirname,
450 index_files[index_number].fn);
451
452 DBG(ctx, "file=%s name=%s\n", fn, name);
453
454 idx = index_file_open(fn);
455 if (idx == NULL)
456 return -ENOSYS;
457
458 realnames = index_searchwild(idx, name);
459 index_file_close(idx);
460 }
461
462 for (realname = realnames; realname; realname = realname->next) {
463 struct kmod_module *mod;
464
465 err = kmod_module_new_from_alias(ctx, name, realname->value, &mod);
466 if (err < 0) {
467 ERR(ctx, "Could not create module for alias=%s realname=%s: %s\n",
468 name, realname->value, strerror(-err));
469 goto fail;
470 }
471
472 *list = __kmod_list_append(*list, mod);
473 nmatch++;
474 }
475
476 index_values_free(realnames);
477 return nmatch;
478
479 fail:
480 *list = kmod_list_remove_n_latest(*list, nmatch);
481 index_values_free(realnames);
482 return err;
483
484 }
485
486 int kmod_lookup_alias_from_symbols_file(struct kmod_ctx *ctx, const char *name,
487 struct kmod_list **list)
488 {
489 if (!strstartswith(name, "symbol:"))
490 return 0;
491
492 return kmod_lookup_alias_from_alias_bin(ctx, KMOD_INDEX_MODULES_SYMBOL,
493 name, list);
494 }
495
496 int kmod_lookup_alias_from_aliases_file(struct kmod_ctx *ctx, const char *name,
497 struct kmod_list **list)
498 {
499 return kmod_lookup_alias_from_alias_bin(ctx, KMOD_INDEX_MODULES_ALIAS,
500 name, list);
501 }
502
503 static char *lookup_builtin_file(struct kmod_ctx *ctx, const char *name)
504 {
505 char *line;
506
507 if (ctx->indexes[KMOD_INDEX_MODULES_BUILTIN]) {
508 DBG(ctx, "use mmaped index '%s' modname=%s\n",
509 index_files[KMOD_INDEX_MODULES_BUILTIN].fn,
510 name);
511 line = index_mm_search(ctx->indexes[KMOD_INDEX_MODULES_BUILTIN],
512 name);
513 } else {
514 struct index_file *idx;
515 char fn[PATH_MAX];
516
517 snprintf(fn, sizeof(fn), "%s/%s.bin", ctx->dirname,
518 index_files[KMOD_INDEX_MODULES_BUILTIN].fn);
519 DBG(ctx, "file=%s modname=%s\n", fn, name);
520
521 idx = index_file_open(fn);
522 if (idx == NULL) {
523 DBG(ctx, "could not open builtin file '%s'\n", fn);
524 return NULL;
525 }
526
527 line = index_search(idx, name);
528 index_file_close(idx);
529 }
530
531 return line;
532 }
533
534 int kmod_lookup_alias_from_builtin_file(struct kmod_ctx *ctx, const char *name,
535 struct kmod_list **list)
536 {
537 char *line;
538 int err = 0;
539
540 assert(*list == NULL);
541
542 line = lookup_builtin_file(ctx, name);
543 if (line != NULL) {
544 struct kmod_module *mod;
545
546 err = kmod_module_new_from_name(ctx, name, &mod);
547 if (err < 0) {
548 ERR(ctx, "Could not create module from name %s: %s\n",
549 name, strerror(-err));
550 goto finish;
551 }
552
553 /* already mark it as builtin since it's being created from
554 * this index */
555 kmod_module_set_builtin(mod, true);
556 *list = __kmod_list_append(*list, mod);
557 if (*list == NULL)
558 err = -ENOMEM;
559 }
560
561 finish:
562 free(line);
563 return err;
564 }
565
566 bool kmod_lookup_alias_is_builtin(struct kmod_ctx *ctx, const char *name)
567 {
568 char *line;
569 bool found;
570
571 line = lookup_builtin_file(ctx, name);
572 found = line != NULL;
573 if (found)
574 free(line);
575 return found;
576 }
577
578 char *kmod_search_moddep(struct kmod_ctx *ctx, const char *name)
579 {
580 struct index_file *idx;
581 char fn[PATH_MAX];
582 char *line;
583
584 if (ctx->indexes[KMOD_INDEX_MODULES_DEP]) {
585 DBG(ctx, "use mmaped index '%s' modname=%s\n",
586 index_files[KMOD_INDEX_MODULES_DEP].fn, name);
587 return index_mm_search(ctx->indexes[KMOD_INDEX_MODULES_DEP],
588 name);
589 }
590
591 snprintf(fn, sizeof(fn), "%s/%s.bin", ctx->dirname,
592 index_files[KMOD_INDEX_MODULES_DEP].fn);
593
594 DBG(ctx, "file=%s modname=%s\n", fn, name);
595
596 idx = index_file_open(fn);
597 if (idx == NULL) {
598 DBG(ctx, "could not open moddep file '%s'\n", fn);
599 return NULL;
600 }
601
602 line = index_search(idx, name);
603 index_file_close(idx);
604
605 return line;
606 }
607
608 int kmod_lookup_alias_from_moddep_file(struct kmod_ctx *ctx, const char *name,
609 struct kmod_list **list)
610 {
611 char *line;
612 int n = 0;
613
614 /*
615 * Module names do not contain ':'. Return early if we know it will
616 * not be found.
617 */
618 if (strchr(name, ':'))
619 return 0;
620
621 line = kmod_search_moddep(ctx, name);
622 if (line != NULL) {
623 struct kmod_module *mod;
624
625 n = kmod_module_new_from_name(ctx, name, &mod);
626 if (n < 0) {
627 ERR(ctx, "Could not create module from name %s: %s\n",
628 name, strerror(-n));
629 goto finish;
630 }
631
632 *list = __kmod_list_append(*list, mod);
633 kmod_module_parse_depline(mod, line);
634 }
635
636 finish:
637 free(line);
638
639 return n;
640 }
641
642 int kmod_lookup_alias_from_config(struct kmod_ctx *ctx, const char *name,
643 struct kmod_list **list)
644 {
645 struct kmod_config *config = ctx->config;
646 struct kmod_list *l;
647 int err, nmatch = 0;
648
649 kmod_list_foreach(l, config->aliases) {
650 const char *aliasname = kmod_alias_get_name(l);
651 const char *modname = kmod_alias_get_modname(l);
652
653 if (fnmatch(aliasname, name, 0) == 0) {
654 struct kmod_module *mod;
655
656 err = kmod_module_new_from_alias(ctx, aliasname,
657 modname, &mod);
658 if (err < 0) {
659 ERR(ctx, "Could not create module for alias=%s modname=%s: %s\n",
660 name, modname, strerror(-err));
661 goto fail;
662 }
663
664 *list = __kmod_list_append(*list, mod);
665 nmatch++;
666 }
667 }
668
669 return nmatch;
670
671 fail:
672 *list = kmod_list_remove_n_latest(*list, nmatch);
673 return err;
674 }
675
676 int kmod_lookup_alias_from_commands(struct kmod_ctx *ctx, const char *name,
677 struct kmod_list **list)
678 {
679 struct kmod_config *config = ctx->config;
680 struct kmod_list *l, *node;
681 int err, nmatch = 0;
682
683 kmod_list_foreach(l, config->install_commands) {
684 const char *modname = kmod_command_get_modname(l);
685
686 if (streq(modname, name)) {
687 const char *cmd = kmod_command_get_command(l);
688 struct kmod_module *mod;
689
690 err = kmod_module_new_from_name(ctx, modname, &mod);
691 if (err < 0) {
692 ERR(ctx, "Could not create module from name %s: %s\n",
693 modname, strerror(-err));
694 return err;
695 }
696
697 node = __kmod_list_append(*list, mod);
698 if (node == NULL) {
699 ERR(ctx, "out of memory\n");
700 return -ENOMEM;
701 }
702
703 *list = node;
704 nmatch = 1;
705
706 kmod_module_set_install_commands(mod, cmd);
707
708 /*
709 * match only the first one, like modprobe from
710 * module-init-tools does
711 */
712 break;
713 }
714 }
715
716 if (nmatch)
717 return nmatch;
718
719 kmod_list_foreach(l, config->remove_commands) {
720 const char *modname = kmod_command_get_modname(l);
721
722 if (streq(modname, name)) {
723 const char *cmd = kmod_command_get_command(l);
724 struct kmod_module *mod;
725
726 err = kmod_module_new_from_name(ctx, modname, &mod);
727 if (err < 0) {
728 ERR(ctx, "Could not create module from name %s: %s\n",
729 modname, strerror(-err));
730 return err;
731 }
732
733 node = __kmod_list_append(*list, mod);
734 if (node == NULL) {
735 ERR(ctx, "out of memory\n");
736 return -ENOMEM;
737 }
738
739 *list = node;
740 nmatch = 1;
741
742 kmod_module_set_remove_commands(mod, cmd);
743
744 /*
745 * match only the first one, like modprobe from
746 * module-init-tools does
747 */
748 break;
749 }
750 }
751
752 return nmatch;
753 }
754
755 void kmod_set_modules_visited(struct kmod_ctx *ctx, bool visited)
756 {
757 struct hash_iter iter;
758 const void *v;
759
760 hash_iter_init(ctx->modules_by_name, &iter);
761 while (hash_iter_next(&iter, NULL, &v))
762 kmod_module_set_visited((struct kmod_module *)v, visited);
763 }
764
765 void kmod_set_modules_required(struct kmod_ctx *ctx, bool required)
766 {
767 struct hash_iter iter;
768 const void *v;
769
770 hash_iter_init(ctx->modules_by_name, &iter);
771 while (hash_iter_next(&iter, NULL, &v))
772 kmod_module_set_required((struct kmod_module *)v, required);
773 }
774
775 static bool is_cache_invalid(const char *path, unsigned long long stamp)
776 {
777 struct stat st;
778
779 if (stat(path, &st) < 0)
780 return true;
781
782 if (stamp != stat_mstamp(&st))
783 return true;
784
785 return false;
786 }
787
788 /**
789 * kmod_validate_resources:
790 * @ctx: kmod library context
791 *
792 * Check if indexes and configuration files changed on disk and the current
793 * context is not valid anymore.
794 *
795 * Returns: KMOD_RESOURCES_OK if resources are still valid,
796 * KMOD_RESOURCES_MUST_RELOAD if it's sufficient to call
797 * kmod_unload_resources() and kmod_load_resources() or
798 * KMOD_RESOURCES_MUST_RECREATE if @ctx must be re-created.
799 */
800 int kmod_validate_resources(struct kmod_ctx *ctx)
801 {
802 struct kmod_list *l;
803 size_t i;
804
805 if (ctx == NULL || ctx->config == NULL)
806 return KMOD_RESOURCES_MUST_RECREATE;
807
808 kmod_list_foreach(l, ctx->config->paths) {
809 struct kmod_config_path *cf = l->data;
810
811 if (is_cache_invalid(cf->path, cf->stamp))
812 return KMOD_RESOURCES_MUST_RECREATE;
813 }
814
815 for (i = 0; i < _KMOD_INDEX_MODULES_SIZE; i++) {
816 char path[PATH_MAX];
817
818 if (ctx->indexes[i] == NULL)
819 continue;
820
821 snprintf(path, sizeof(path), "%s/%s.bin", ctx->dirname,
822 index_files[i].fn);
823
824 if (is_cache_invalid(path, ctx->indexes_stamp[i]))
825 return KMOD_RESOURCES_MUST_RELOAD;
826 }
827
828 return KMOD_RESOURCES_OK;
829 }
830
831 /**
832 * kmod_load_resources:
833 * @ctx: kmod library context
834 *
835 * Load indexes and keep them open in @ctx. This way it's faster to lookup
836 * information within the indexes. If this function is not called before a
837 * search, the necessary index is always opened and closed.
838 *
839 * If user will do more than one or two lookups, insertions, deletions, most
840 * likely it's good to call this function first. Particularly in a daemon like
841 * udev that on bootup issues hundreds of calls to lookup the index, calling
842 * this function will speedup the searches.
843 *
844 * Returns: 0 on success or < 0 otherwise.
845 */
846 int kmod_load_resources(struct kmod_ctx *ctx)
847 {
848 size_t i;
849
850 if (ctx == NULL)
851 return -ENOENT;
852
853 for (i = 0; i < _KMOD_INDEX_MODULES_SIZE; i++) {
854 char path[PATH_MAX];
855
856 if (ctx->indexes[i] != NULL) {
857 INFO(ctx, "Index %s already loaded\n",
858 index_files[i].fn);
859 continue;
860 }
861
862 snprintf(path, sizeof(path), "%s/%s.bin", ctx->dirname,
863 index_files[i].fn);
864 ctx->indexes[i] = index_mm_open(ctx, path,
865 &ctx->indexes_stamp[i]);
866 if (ctx->indexes[i] == NULL)
867 goto fail;
868 }
869
870 return 0;
871
872 fail:
873 kmod_unload_resources(ctx);
874 return -ENOMEM;
875 }
876
877 /**
878 * kmod_unload_resources:
879 * @ctx: kmod library context
880 *
881 * Unload all the indexes. This will free the resources to maintain the index
882 * open and all subsequent searches will need to open and close the index.
883 *
884 * User is free to call kmod_load_resources() and kmod_unload_resources() as
885 * many times as wanted during the lifecycle of @ctx. For example, if a daemon
886 * knows that when starting up it will lookup a lot of modules, it could call
887 * kmod_load_resources() and after the first burst of searches is gone, it
888 * could free the resources by calling kmod_unload_resources().
889 *
890 * Returns: 0 on success or < 0 otherwise.
891 */
892 void kmod_unload_resources(struct kmod_ctx *ctx)
893 {
894 size_t i;
895
896 if (ctx == NULL)
897 return;
898
899 for (i = 0; i < _KMOD_INDEX_MODULES_SIZE; i++) {
900 if (ctx->indexes[i] != NULL) {
901 index_mm_close(ctx->indexes[i]);
902 ctx->indexes[i] = NULL;
903 ctx->indexes_stamp[i] = 0;
904 }
905 }
906 }
907
908 /**
909 * kmod_dump_index:
910 * @ctx: kmod library context
911 * @type: index to dump, valid indexes are
912 * KMOD_INDEX_MODULES_DEP: index of module dependencies;
913 * KMOD_INDEX_MODULES_ALIAS: index of module aliases;
914 * KMOD_INDEX_MODULES_SYMBOL: index of symbol aliases;
915 * KMOD_INDEX_MODULES_BUILTIN: index of builtin module.
916 * @fd: file descriptor to dump index to
917 *
918 * Dump index to file descriptor. Note that this function doesn't use stdio.h
919 * so call fflush() before calling this function to be sure data is written in
920 * order.
921 *
922 * Returns: 0 on success or < 0 otherwise.
923 */
924 int kmod_dump_index(struct kmod_ctx *ctx, enum kmod_index type,
925 int fd)
926 {
927 if (ctx == NULL)
928 return -ENOSYS;
929
930 if (type < 0 || type >= _KMOD_INDEX_MODULES_SIZE)
931 return -ENOENT;
932
933 if (ctx->indexes[type] != NULL) {
934 DBG(ctx, "use mmaped index '%s'\n", index_files[type].fn);
935 index_mm_dump(ctx->indexes[type], fd,
936 index_files[type].prefix);
937 } else {
938 char fn[PATH_MAX];
939 struct index_file *idx;
940
941 snprintf(fn, sizeof(fn), "%s/%s.bin", ctx->dirname,
942 index_files[type].fn);
943
944 DBG(ctx, "file=%s\n", fn);
945
946 idx = index_file_open(fn);
947 if (idx == NULL)
948 return -ENOSYS;
949
950 index_dump(idx, fd, index_files[type].prefix);
951 index_file_close(idx);
952 }
953
954 return 0;
955 }
956
957 const struct kmod_config *kmod_get_config(const struct kmod_ctx *ctx)
958 {
959 return ctx->config;
960 }
File src/libkmod.h added (mode: 100644) (index 0000000..ddf02dc)
1 /*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #pragma once
21 #ifndef _LIBKMOD_H_
22 #define _LIBKMOD_H_
23
24 #include <fcntl.h>
25 #include <stdarg.h>
26 #include <stdbool.h>
27 #include <inttypes.h>
28
29 #ifdef __cplusplus
30 extern "C" {
31 #endif
32
33 /*
34 * kmod_ctx
35 *
36 * library user context - reads the config and system
37 * environment, user variables, allows custom logging
38 */
39 struct kmod_ctx;
40 struct kmod_ctx *kmod_new(const char *dirname, const char * const *config_paths);
41 struct kmod_ctx *kmod_ref(struct kmod_ctx *ctx);
42 struct kmod_ctx *kmod_unref(struct kmod_ctx *ctx);
43 void kmod_set_log_fn(struct kmod_ctx *ctx,
44 void (*log_fn)(void *log_data,
45 int priority, const char *file, int line,
46 const char *fn, const char *format,
47 va_list args),
48 const void *data);
49 int kmod_get_log_priority(const struct kmod_ctx *ctx);
50 void kmod_set_log_priority(struct kmod_ctx *ctx, int priority);
51 void *kmod_get_userdata(const struct kmod_ctx *ctx);
52 void kmod_set_userdata(struct kmod_ctx *ctx, const void *userdata);
53
54 const char *kmod_get_dirname(const struct kmod_ctx *ctx);
55
56 /*
57 * Management of libkmod's resources
58 */
59 int kmod_load_resources(struct kmod_ctx *ctx);
60 void kmod_unload_resources(struct kmod_ctx *ctx);
61
62 enum kmod_resources {
63 KMOD_RESOURCES_OK = 0,
64 KMOD_RESOURCES_MUST_RELOAD = 1,
65 KMOD_RESOURCES_MUST_RECREATE = 2,
66 };
67 int kmod_validate_resources(struct kmod_ctx *ctx);
68
69 enum kmod_index {
70 KMOD_INDEX_MODULES_DEP = 0,
71 KMOD_INDEX_MODULES_ALIAS,
72 KMOD_INDEX_MODULES_SYMBOL,
73 KMOD_INDEX_MODULES_BUILTIN,
74 /* Padding to make sure enum is not mapped to char */
75 _KMOD_INDEX_PAD = (1 << 31),
76 };
77 int kmod_dump_index(struct kmod_ctx *ctx, enum kmod_index type, int fd);
78
79 /*
80 * kmod_list
81 *
82 * access to kmod generated lists
83 */
84 struct kmod_list;
85 struct kmod_list *kmod_list_next(const struct kmod_list *list,
86 const struct kmod_list *curr);
87 struct kmod_list *kmod_list_prev(const struct kmod_list *list,
88 const struct kmod_list *curr);
89 struct kmod_list *kmod_list_last(const struct kmod_list *list);
90
91 #define kmod_list_foreach(list_entry, first_entry) \
92 for (list_entry = first_entry; \
93 list_entry != NULL; \
94 list_entry = kmod_list_next(first_entry, list_entry))
95
96 #define kmod_list_foreach_reverse(list_entry, first_entry) \
97 for (list_entry = kmod_list_last(first_entry); \
98 list_entry != NULL; \
99 list_entry = kmod_list_prev(first_entry, list_entry))
100
101 /*
102 * kmod_config_iter
103 *
104 * access to configuration lists - it allows to get each configuration's
105 * key/value stored by kmod
106 */
107 struct kmod_config_iter;
108 struct kmod_config_iter *kmod_config_get_blacklists(const struct kmod_ctx *ctx);
109 struct kmod_config_iter *kmod_config_get_install_commands(const struct kmod_ctx *ctx);
110 struct kmod_config_iter *kmod_config_get_remove_commands(const struct kmod_ctx *ctx);
111 struct kmod_config_iter *kmod_config_get_aliases(const struct kmod_ctx *ctx);
112 struct kmod_config_iter *kmod_config_get_options(const struct kmod_ctx *ctx);
113 struct kmod_config_iter *kmod_config_get_softdeps(const struct kmod_ctx *ctx);
114 const char *kmod_config_iter_get_key(const struct kmod_config_iter *iter);
115 const char *kmod_config_iter_get_value(const struct kmod_config_iter *iter);
116 bool kmod_config_iter_next(struct kmod_config_iter *iter);
117 void kmod_config_iter_free_iter(struct kmod_config_iter *iter);
118
119 /*
120 * kmod_module
121 *
122 * Operate on kernel modules
123 */
124 struct kmod_module;
125 int kmod_module_new_from_name(struct kmod_ctx *ctx, const char *name,
126 struct kmod_module **mod);
127 int kmod_module_new_from_path(struct kmod_ctx *ctx, const char *path,
128 struct kmod_module **mod);
129 int kmod_module_new_from_lookup(struct kmod_ctx *ctx, const char *given_alias,
130 struct kmod_list **list);
131 int kmod_module_new_from_loaded(struct kmod_ctx *ctx,
132 struct kmod_list **list);
133
134 struct kmod_module *kmod_module_ref(struct kmod_module *mod);
135 struct kmod_module *kmod_module_unref(struct kmod_module *mod);
136 int kmod_module_unref_list(struct kmod_list *list);
137 struct kmod_module *kmod_module_get_module(const struct kmod_list *entry);
138
139
140 /* Removal flags */
141 enum kmod_remove {
142 KMOD_REMOVE_FORCE = O_TRUNC,
143 KMOD_REMOVE_NOWAIT = O_NONBLOCK, /* always set */
144 };
145
146 /* Insertion flags */
147 enum kmod_insert {
148 KMOD_INSERT_FORCE_VERMAGIC = 0x1,
149 KMOD_INSERT_FORCE_MODVERSION = 0x2,
150 };
151
152 /* Flags to kmod_module_probe_insert_module() */
153 enum kmod_probe {
154 KMOD_PROBE_FORCE_VERMAGIC = 0x00001,
155 KMOD_PROBE_FORCE_MODVERSION = 0x00002,
156 KMOD_PROBE_IGNORE_COMMAND = 0x00004,
157 KMOD_PROBE_IGNORE_LOADED = 0x00008,
158 KMOD_PROBE_DRY_RUN = 0x00010,
159 KMOD_PROBE_FAIL_ON_LOADED = 0x00020,
160
161 /* codes below can be used in return value, too */
162 KMOD_PROBE_APPLY_BLACKLIST_ALL = 0x10000,
163 KMOD_PROBE_APPLY_BLACKLIST = 0x20000,
164 KMOD_PROBE_APPLY_BLACKLIST_ALIAS_ONLY = 0x40000,
165 };
166
167 /* Flags to kmod_module_apply_filter() */
168 enum kmod_filter {
169 KMOD_FILTER_BLACKLIST = 0x00001,
170 KMOD_FILTER_BUILTIN = 0x00002,
171 };
172
173 int kmod_module_remove_module(struct kmod_module *mod, unsigned int flags);
174 int kmod_module_insert_module(struct kmod_module *mod, unsigned int flags,
175 const char *options);
176 int kmod_module_probe_insert_module(struct kmod_module *mod,
177 unsigned int flags, const char *extra_options,
178 int (*run_install)(struct kmod_module *m,
179 const char *cmdline, void *data),
180 const void *data,
181 void (*print_action)(struct kmod_module *m, bool install,
182 const char *options));
183
184
185 const char *kmod_module_get_name(const struct kmod_module *mod);
186 const char *kmod_module_get_path(const struct kmod_module *mod);
187 const char *kmod_module_get_options(const struct kmod_module *mod);
188 const char *kmod_module_get_install_commands(const struct kmod_module *mod);
189 const char *kmod_module_get_remove_commands(const struct kmod_module *mod);
190 struct kmod_list *kmod_module_get_dependencies(const struct kmod_module *mod);
191 int kmod_module_get_softdeps(const struct kmod_module *mod,
192 struct kmod_list **pre, struct kmod_list **post);
193 int kmod_module_get_filtered_blacklist(const struct kmod_ctx *ctx,
194 const struct kmod_list *input,
195 struct kmod_list **output);
196 int kmod_module_apply_filter(const struct kmod_ctx *ctx,
197 enum kmod_filter filter_type,
198 const struct kmod_list *input,
199 struct kmod_list **output);
200
201
202
203 /*
204 * Information regarding "live information" from module's state, as returned
205 * by kernel
206 */
207
208 enum kmod_module_initstate {
209 KMOD_MODULE_BUILTIN = 0,
210 KMOD_MODULE_LIVE,
211 KMOD_MODULE_COMING,
212 KMOD_MODULE_GOING,
213 /* Padding to make sure enum is not mapped to char */
214 _KMOD_MODULE_PAD = (1 << 31),
215 };
216 const char *kmod_module_initstate_str(enum kmod_module_initstate state);
217 int kmod_module_get_initstate(const struct kmod_module *mod);
218 int kmod_module_get_refcnt(const struct kmod_module *mod);
219 struct kmod_list *kmod_module_get_holders(const struct kmod_module *mod);
220 struct kmod_list *kmod_module_get_sections(const struct kmod_module *mod);
221 const char *kmod_module_section_get_name(const struct kmod_list *entry);
222 unsigned long kmod_module_section_get_address(const struct kmod_list *entry);
223 void kmod_module_section_free_list(struct kmod_list *list);
224 long kmod_module_get_size(const struct kmod_module *mod);
225
226
227
228 /*
229 * Information retrieved from ELF headers and sections
230 */
231
232 int kmod_module_get_info(const struct kmod_module *mod, struct kmod_list **list);
233 const char *kmod_module_info_get_key(const struct kmod_list *entry);
234 const char *kmod_module_info_get_value(const struct kmod_list *entry);
235 void kmod_module_info_free_list(struct kmod_list *list);
236
237 int kmod_module_get_versions(const struct kmod_module *mod, struct kmod_list **list);
238 const char *kmod_module_version_get_symbol(const struct kmod_list *entry);
239 uint64_t kmod_module_version_get_crc(const struct kmod_list *entry);
240 void kmod_module_versions_free_list(struct kmod_list *list);
241
242 int kmod_module_get_symbols(const struct kmod_module *mod, struct kmod_list **list);
243 const char *kmod_module_symbol_get_symbol(const struct kmod_list *entry);
244 uint64_t kmod_module_symbol_get_crc(const struct kmod_list *entry);
245 void kmod_module_symbols_free_list(struct kmod_list *list);
246
247 enum kmod_symbol_bind {
248 KMOD_SYMBOL_NONE = '\0',
249 KMOD_SYMBOL_LOCAL = 'L',
250 KMOD_SYMBOL_GLOBAL = 'G',
251 KMOD_SYMBOL_WEAK = 'W',
252 KMOD_SYMBOL_UNDEF = 'U'
253 };
254
255 int kmod_module_get_dependency_symbols(const struct kmod_module *mod, struct kmod_list **list);
256 const char *kmod_module_dependency_symbol_get_symbol(const struct kmod_list *entry);
257 int kmod_module_dependency_symbol_get_bind(const struct kmod_list *entry);
258 uint64_t kmod_module_dependency_symbol_get_crc(const struct kmod_list *entry);
259 void kmod_module_dependency_symbols_free_list(struct kmod_list *list);
260
261 #ifdef __cplusplus
262 } /* extern "C" */
263 #endif
264 #endif
File src/shared/array.c added (mode: 100644) (index 0000000..eb9b148)
1 /*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <assert.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "config.h"
26 #define SHARED_ARRAY_C
27 #include "shared/array.h"
28 #undef SHARED_ARRAY_C
29
30 /* basic pointer array growing in steps */
31
32
33 static int array_realloc(struct array *array, size_t new_total)
34 {
35 void *tmp = realloc(array->array, sizeof(void *) * new_total);
36 if (tmp == NULL)
37 return -ENOMEM;
38 array->array = tmp;
39 array->total = new_total;
40 return 0;
41 }
42
43 void array_init(struct array *array, size_t step)
44 {
45 assert(step > 0);
46 array->array = NULL;
47 array->count = 0;
48 array->total = 0;
49 array->step = step;
50 }
51
52 int array_append(struct array *array, const void *element)
53 {
54 size_t idx;
55
56 if (array->count + 1 >= array->total) {
57 int r = array_realloc(array, array->total + array->step);
58 if (r < 0)
59 return r;
60 }
61 idx = array->count;
62 array->array[idx] = (void *)element;
63 array->count++;
64 return idx;
65 }
66
67 int array_append_unique(struct array *array, const void *element)
68 {
69 void **itr = array->array;
70 void **itr_end = itr + array->count;
71 for (; itr < itr_end; itr++)
72 if (*itr == element)
73 return -EEXIST;
74 return array_append(array, element);
75 }
76
77 void array_pop(struct array *array) {
78 array->count--;
79 if (array->count + array->step < array->total) {
80 int r = array_realloc(array, array->total - array->step);
81 if (r < 0)
82 return;
83 }
84 }
85
86 void array_free_array(struct array *array) {
87 free(array->array);
88 array->count = 0;
89 array->total = 0;
90 }
91
92
93 void array_sort(struct array *array, int (*cmp)(const void *a, const void *b))
94 {
95 qsort(array->array, array->count, sizeof(void *), cmp);
96 }
97
98 int array_remove_at(struct array *array, unsigned int pos)
99 {
100 if (array->count <= pos)
101 return -ENOENT;
102
103 array->count--;
104 if (pos < array->count)
105 memmove(array->array + pos, array->array + pos + 1,
106 sizeof(void *) * (array->count - pos));
107
108 if (array->count + array->step < array->total) {
109 int r = array_realloc(array, array->total - array->step);
110 /* ignore error */
111 if (r < 0)
112 return 0;
113 }
114
115 return 0;
116 }
File src/shared/array.h added (mode: 100644) (index 0000000..f745fa5)
1 #ifndef SHARED_ARRAY_H
2 #define SHARED_ARRAY_H
3
4 #ifdef SHARED_ARRAY_C
5 #define EXTERN
6 #else
7 #define EXTERN extern
8 #endif
9 /*
10 * Declaration of struct array is in header because we may want to embed the
11 * structure into another, so we need to know its size
12 */
13 struct array {
14 void **array;
15 size_t count;
16 size_t total;
17 size_t step;
18 };
19
20 EXTERN void array_init(struct array *array, size_t step);
21 EXTERN int array_append(struct array *array, const void *element);
22 EXTERN int array_append_unique(struct array *array, const void *element);
23 EXTERN void array_pop(struct array *array);
24 EXTERN void array_free_array(struct array *array);
25 EXTERN void array_sort(struct array *array, int (*cmp)(const void *a, const void *b));
26 EXTERN int array_remove_at(struct array *array, unsigned int pos);
27 #undef EXTERN
28 #endif
File src/shared/hash.c added (mode: 100644) (index 0000000..8733a40)
1 /*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <errno.h>
21 #include <inttypes.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <limits.h>
25 #include <stdio.h>
26 #include <stdbool.h>
27 #include <sys/stat.h>
28
29 #include "config.h"
30 #include "shared/macro.h"
31 #define SHARED_HASH_C
32 #include "shared/hash.h"
33 #undef SHARED_HASH_C
34 #include "shared/util.h"
35
36 struct hash_entry {
37 const char *key;
38 const void *value;
39 };
40
41 struct hash_bucket {
42 struct hash_entry *entries;
43 unsigned int used;
44 unsigned int total;
45 };
46
47 struct hash {
48 unsigned int count;
49 unsigned int step;
50 unsigned int n_buckets;
51 void (*free_value)(void *value);
52 struct hash_bucket buckets[];
53 };
54
55 struct hash *hash_new(unsigned int n_buckets,
56 void (*free_value)(void *value))
57 {
58 struct hash *hash;
59
60 n_buckets = ALIGN_POWER2(n_buckets);
61 hash = calloc(1, sizeof(struct hash) +
62 n_buckets * sizeof(struct hash_bucket));
63 if (hash == NULL)
64 return NULL;
65 hash->n_buckets = n_buckets;
66 hash->free_value = free_value;
67 hash->step = n_buckets / 32;
68 if (hash->step == 0)
69 hash->step = 4;
70 else if (hash->step > 64)
71 hash->step = 64;
72 return hash;
73 }
74
75 void hash_free(struct hash *hash)
76 {
77 struct hash_bucket *bucket, *bucket_end;
78
79 if (hash == NULL)
80 return;
81
82 bucket = hash->buckets;
83 bucket_end = bucket + hash->n_buckets;
84 for (; bucket < bucket_end; bucket++) {
85 if (hash->free_value) {
86 struct hash_entry *entry, *entry_end;
87 entry = bucket->entries;
88 entry_end = entry + bucket->used;
89 for (; entry < entry_end; entry++)
90 hash->free_value((void *)entry->value);
91 }
92 free(bucket->entries);
93 }
94 free(hash);
95 }
96
97 static inline unsigned int hash_superfast(const char *key, unsigned int len)
98 {
99 /* Paul Hsieh (http://www.azillionmonkeys.com/qed/hash.html)
100 * used by WebCore (http://webkit.org/blog/8/hashtables-part-2/)
101 * EFL's eina and possible others.
102 */
103 unsigned int tmp, hash = len, rem = len & 3;
104
105 len /= 4;
106
107 /* Main loop */
108 for (; len > 0; len--) {
109 hash += *(uint16_t *)key;
110 tmp = ((*(uint16_t *)(key + 2)) << 11) ^ hash;
111 hash = (hash << 16) ^ tmp;
112 key += 4;
113 hash += hash >> 11;
114 }
115
116 /* Handle end cases */
117 switch (rem) {
118 case 3:
119 hash += *(uint16_t *)key;
120 hash ^= hash << 16;
121 hash ^= key[2] << 18;
122 hash += hash >> 11;
123 break;
124
125 case 2:
126 hash += *(uint16_t *)key;
127 hash ^= hash << 11;
128 hash += hash >> 17;
129 break;
130
131 case 1:
132 hash += *key;
133 hash ^= hash << 10;
134 hash += hash >> 1;
135 }
136
137 /* Force "avalanching" of final 127 bits */
138 hash ^= hash << 3;
139 hash += hash >> 5;
140 hash ^= hash << 4;
141 hash += hash >> 17;
142 hash ^= hash << 25;
143 hash += hash >> 6;
144
145 return hash;
146 }
147
148 /*
149 * add or replace key in hash map.
150 *
151 * none of key or value are copied, just references are remembered as is,
152 * make sure they are live while pair exists in hash!
153 */
154 int hash_add(struct hash *hash, const char *key, const void *value)
155 {
156 unsigned int keylen = strlen(key);
157 unsigned int hashval = hash_superfast(key, keylen);
158 unsigned int pos = hashval & (hash->n_buckets - 1);
159 struct hash_bucket *bucket = hash->buckets + pos;
160 struct hash_entry *entry, *entry_end;
161
162 if (bucket->used + 1 >= bucket->total) {
163 unsigned new_total = bucket->total + hash->step;
164 size_t size = new_total * sizeof(struct hash_entry);
165 struct hash_entry *tmp = realloc(bucket->entries, size);
166 if (tmp == NULL)
167 return -errno;
168 bucket->entries = tmp;
169 bucket->total = new_total;
170 }
171
172 entry = bucket->entries;
173 entry_end = entry + bucket->used;
174 for (; entry < entry_end; entry++) {
175 int c = strcmp(key, entry->key);
176 if (c == 0) {
177 if (hash->free_value)
178 hash->free_value((void *)entry->value);
179 entry->key = key;
180 entry->value = value;
181 return 0;
182 } else if (c < 0) {
183 memmove(entry + 1, entry,
184 (entry_end - entry) * sizeof(struct hash_entry));
185 break;
186 }
187 }
188
189 entry->key = key;
190 entry->value = value;
191 bucket->used++;
192 hash->count++;
193 return 0;
194 }
195
196 /* similar to hash_add(), but fails if key already exists */
197 int hash_add_unique(struct hash *hash, const char *key, const void *value)
198 {
199 unsigned int keylen = strlen(key);
200 unsigned int hashval = hash_superfast(key, keylen);
201 unsigned int pos = hashval & (hash->n_buckets - 1);
202 struct hash_bucket *bucket = hash->buckets + pos;
203 struct hash_entry *entry, *entry_end;
204
205 if (bucket->used + 1 >= bucket->total) {
206 unsigned new_total = bucket->total + hash->step;
207 size_t size = new_total * sizeof(struct hash_entry);
208 struct hash_entry *tmp = realloc(bucket->entries, size);
209 if (tmp == NULL)
210 return -errno;
211 bucket->entries = tmp;
212 bucket->total = new_total;
213 }
214
215 entry = bucket->entries;
216 entry_end = entry + bucket->used;
217 for (; entry < entry_end; entry++) {
218 int c = strcmp(key, entry->key);
219 if (c == 0)
220 return -EEXIST;
221 else if (c < 0) {
222 memmove(entry + 1, entry,
223 (entry_end - entry) * sizeof(struct hash_entry));
224 break;
225 }
226 }
227
228 entry->key = key;
229 entry->value = value;
230 bucket->used++;
231 hash->count++;
232 return 0;
233 }
234
235 static int hash_entry_cmp(const void *pa, const void *pb)
236 {
237 const struct hash_entry *a = pa;
238 const struct hash_entry *b = pb;
239 return strcmp(a->key, b->key);
240 }
241
242 void *hash_find(const struct hash *hash, const char *key)
243 {
244 unsigned int keylen = strlen(key);
245 unsigned int hashval = hash_superfast(key, keylen);
246 unsigned int pos = hashval & (hash->n_buckets - 1);
247 const struct hash_bucket *bucket = hash->buckets + pos;
248 const struct hash_entry se = {
249 .key = key,
250 .value = NULL
251 };
252 const struct hash_entry *entry = bsearch(
253 &se, bucket->entries, bucket->used,
254 sizeof(struct hash_entry), hash_entry_cmp);
255 if (entry == NULL)
256 return NULL;
257 return (void *)entry->value;
258 }
259
260 int hash_del(struct hash *hash, const char *key)
261 {
262 unsigned int keylen = strlen(key);
263 unsigned int hashval = hash_superfast(key, keylen);
264 unsigned int pos = hashval & (hash->n_buckets - 1);
265 unsigned int steps_used, steps_total;
266 struct hash_bucket *bucket = hash->buckets + pos;
267 struct hash_entry *entry, *entry_end;
268 const struct hash_entry se = {
269 .key = key,
270 .value = NULL
271 };
272
273 entry = bsearch(&se, bucket->entries, bucket->used,
274 sizeof(struct hash_entry), hash_entry_cmp);
275 if (entry == NULL)
276 return -ENOENT;
277
278 if (hash->free_value)
279 hash->free_value((void *)entry->value);
280
281 entry_end = bucket->entries + bucket->used;
282 memmove(entry, entry + 1,
283 (entry_end - entry) * sizeof(struct hash_entry));
284
285 bucket->used--;
286 hash->count--;
287
288 steps_used = bucket->used / hash->step;
289 steps_total = bucket->total / hash->step;
290 if (steps_used + 1 < steps_total) {
291 size_t size = (steps_used + 1) *
292 hash->step * sizeof(struct hash_entry);
293 struct hash_entry *tmp = realloc(bucket->entries, size);
294 if (tmp) {
295 bucket->entries = tmp;
296 bucket->total = (steps_used + 1) * hash->step;
297 }
298 }
299
300 return 0;
301 }
302
303 unsigned int hash_get_count(const struct hash *hash)
304 {
305 return hash->count;
306 }
307
308 void hash_iter_init(const struct hash *hash, struct hash_iter *iter)
309 {
310 iter->hash = hash;
311 iter->bucket = 0;
312 iter->entry = -1;
313 }
314
315 bool hash_iter_next(struct hash_iter *iter, const char **key,
316 const void **value)
317 {
318 const struct hash_bucket *b = iter->hash->buckets + iter->bucket;
319 const struct hash_entry *e;
320
321 iter->entry++;
322
323 if (iter->entry >= b->used) {
324 iter->entry = 0;
325
326 for (iter->bucket++; iter->bucket < iter->hash->n_buckets;
327 iter->bucket++) {
328 b = iter->hash->buckets + iter->bucket;
329
330 if (b->used > 0)
331 break;
332 }
333
334 if (iter->bucket >= iter->hash->n_buckets)
335 return false;
336 }
337
338 e = b->entries + iter->entry;
339
340 if (value != NULL)
341 *value = e->value;
342 if (key != NULL)
343 *key = e->key;
344
345 return true;
346 }
File src/shared/hash.h added (mode: 100644) (index 0000000..6236bad)
1 #ifndef SHARED_HASH_H
2 #define SHARED_HASH_H
3
4 #ifdef SHARED_HASH_C
5 #define EXTERN
6 #else
7 #define EXTERN extern
8 #endif
9
10 struct hash;
11
12 struct hash_iter {
13 const struct hash *hash;
14 unsigned int bucket;
15 unsigned int entry;
16 };
17
18 EXTERN struct hash *hash_new(unsigned int n_buckets, void (*free_value)(void *value));
19 EXTERN void hash_free(struct hash *hash);
20 EXTERN int hash_add(struct hash *hash, const char *key, const void *value);
21 EXTERN int hash_add_unique(struct hash *hash, const char *key, const void *value);
22 EXTERN int hash_del(struct hash *hash, const char *key);
23 EXTERN void *hash_find(const struct hash *hash, const char *key);
24 EXTERN unsigned int hash_get_count(const struct hash *hash);
25 EXTERN void hash_iter_init(const struct hash *hash, struct hash_iter *iter);
26 EXTERN bool hash_iter_next(struct hash_iter *iter, const char **key, const void **value);
27 #undef EXTERN
28 #endif
File src/shared/linux-syscalls.h added (mode: 100644) (index 0000000..7e0dcbe)
1 #ifndef LINUX_SYSCALLS_H
2 #define LINUX_SYSCALLS_H
3 static inline int finit_module(int fd, const char *uargs, int flags)
4 {
5 if (__NR_finit_module == -1) {
6 errno = ENOSYS;
7 return -1;
8 }
9
10 return syscall(__NR_finit_module, fd, uargs, flags);
11 }
12 #endif
File src/shared/macro.h added (mode: 100644) (index 0000000..1364470)
1 #ifndef SHARED_MACRO_H
2 #define SHARED_MACRO_H
3 /*
4 * kmod - interface to kernel module operations
5 *
6 * Copyright (C) 2011-2013 ProFUSION embedded systems
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #define check_types_match(expr1, expr2) \
23 ((typeof(expr1) *)0 != (typeof(expr2) *)0)
24
25 #define container_of(member_ptr, containing_type, member) \
26 ((containing_type *) \
27 ((char *)(member_ptr) - offsetof(containing_type, member)) \
28 - check_types_match(*(member_ptr), ((containing_type *)0)->member))
29
30
31 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
32 #define XSTRINGIFY(x) #x
33 #define STRINGIFY(x) XSTRINGIFY(x)
34
35 /* Temporaries for importing index handling */
36 #define NOFAIL(x) (x)
37 #define fatal(x...) do { } while (0)
38
39 /* Attributes */
40
41 #ifdef __GNUC__
42 #define _unused_ __attribute__((unused))
43 #else
44 #define _unused_
45 #endif
46
47 #endif
File src/shared/scratchbuf.c added (mode: 100644) (index 0000000..355ab60)
1 /*
2 * kmod - interface to kernel module operations
3 *
4 * Copyright (C) 2016 Intel Corporation. All rights reserved.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19 #include <errno.h>
20 #include <string.h>
21 #include <stdbool.h>
22 #include <stdlib.h>
23
24 #include "config.h"
25
26 #define SHARED_SCRATCHBUF_C
27 #include "shared/scratchbuf.h"
28 #undef SHARED_SCRATCHBUF_C
29
30 void scratchbuf_init(struct scratchbuf *buf, char *stackbuf, size_t size)
31 {
32 buf->bytes = stackbuf;
33 buf->size = size;
34 buf->need_free = false;
35 }
36
37 int scratchbuf_alloc(struct scratchbuf *buf, size_t size)
38 {
39 char *tmp;
40
41 if (size <= buf->size)
42 return 0;
43
44 if (buf->need_free) {
45 tmp = realloc(buf->bytes, size);
46 if (tmp == NULL)
47 return -ENOMEM;
48 } else {
49 tmp = malloc(size);
50 if (tmp == NULL)
51 return -ENOMEM;
52 memcpy(tmp, buf->bytes, buf->size);
53 }
54
55 buf->size = size;
56 buf->bytes = tmp;
57 buf->need_free = true;
58
59 return 0;
60 }
61
62 void scratchbuf_release(struct scratchbuf *buf)
63 {
64 if (buf->need_free)
65 free(buf->bytes);
66 }
File src/shared/scratchbuf.h added (mode: 100644) (index 0000000..647dd50)
1 #ifndef SHARED_SCRATCHBUF_H
2 #define SHARED_SCRATCHBUF_H
3
4 #ifdef SHARED_SCRATCHBUF_C
5 #define EXTERN
6 #else
7 #define EXTERN extern
8 #endif
9 /*
10 * Buffer abstract data type
11 */
12 struct scratchbuf {
13 char *bytes;
14 size_t size;
15 bool need_free;
16 };
17
18 EXTERN void scratchbuf_init(struct scratchbuf *buf, char *stackbuf, size_t size);
19 EXTERN int scratchbuf_alloc(struct scratchbuf *buf, size_t sz);
20 EXTERN void scratchbuf_release(struct scratchbuf *buf);
21
22 /* Return a C string */
23 static inline char *scratchbuf_str(struct scratchbuf *buf)
24 {
25 return buf->bytes;
26 }
27
28 #define SCRATCHBUF_INITIALIZER(buf_) { \
29 .bytes = buf_, \
30 .size = sizeof(buf_), \
31 .need_free = false, \
32 }
33 #undef EXTERN
34 #endif
File src/shared/strbuf.c added (mode: 100644) (index 0000000..8198bfd)
1 /*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
5 * Copyright (C) 2014 Intel Corporation. All rights reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <assert.h>
22 #include <stdbool.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <limits.h>
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <sys/stat.h>
29
30 #include "config.h"
31
32 #include "libkmod-namespace.h"
33 #include "shared/macro.h"
34 #include "shared/util.h"
35 #define SHARED_STRBUF_C
36 #include "shared/strbuf.h"
37 #undef SHARED_STRBUF_C
38
39 #define BUF_STEP 128
40
41 static bool buf_grow(struct strbuf *buf, size_t newsize)
42 {
43 void *tmp;
44 size_t sz;
45
46 if (newsize <= buf->size)
47 return true;
48
49 if (newsize % BUF_STEP == 0)
50 sz = newsize;
51 else
52 sz = ((newsize / BUF_STEP) + 1) * BUF_STEP;
53
54 tmp = realloc(buf->bytes, sz);
55 if (sz > 0 && tmp == NULL)
56 return false;
57 buf->bytes = tmp;
58 buf->size = sz;
59 return true;
60 }
61
62 void strbuf_init(struct strbuf *buf)
63 {
64 buf->bytes = NULL;
65 buf->size = 0;
66 buf->used = 0;
67 }
68
69 void strbuf_release(struct strbuf *buf)
70 {
71 free(buf->bytes);
72 }
73
74 char *strbuf_steal(struct strbuf *buf)
75 {
76 char *bytes;
77
78 bytes = realloc(buf->bytes, buf->used + 1);
79 if (!bytes) {
80 free(buf->bytes);
81 return NULL;
82 }
83 bytes[buf->used] = '\0';
84 return bytes;
85 }
86
87 const char *strbuf_str(struct strbuf *buf)
88 {
89 if (!buf_grow(buf, buf->used + 1))
90 return NULL;
91 buf->bytes[buf->used] = '\0';
92 return buf->bytes;
93 }
94
95 bool strbuf_pushchar(struct strbuf *buf, char ch)
96 {
97 if (!buf_grow(buf, buf->used + 1))
98 return false;
99 buf->bytes[buf->used] = ch;
100 buf->used++;
101 return true;
102 }
103
104 unsigned strbuf_pushchars(struct strbuf *buf, const char *str)
105 {
106 unsigned int len;
107
108 assert(str != NULL);
109 assert(buf != NULL);
110
111 len = strlen(str);
112
113 if (!buf_grow(buf, buf->used + len))
114 return 0;
115
116 memcpy(buf->bytes + buf->used, str, len);
117 buf->used += len;
118
119 return len;
120 }
121
122 void strbuf_popchar(struct strbuf *buf)
123 {
124 assert(buf->used > 0);
125 buf->used--;
126 }
127
128 void strbuf_popchars(struct strbuf *buf, unsigned n)
129 {
130 assert(buf->used >= n);
131 buf->used -= n;
132 }
133
134 void strbuf_clear(struct strbuf *buf)
135 {
136 buf->used = 0;
137 }
138
File src/shared/strbuf.h added (mode: 100644) (index 0000000..e6d78f7)
1 #ifndef SHARED_STRBUF_H
2 #define SHARED_STRBUF_H
3
4 #ifdef SHARED_STRBUF_C
5 #define EXTERN
6 #else
7 #define EXTERN extern
8 #endif
9
10 /*
11 * Buffer abstract data type
12 */
13 struct strbuf {
14 char *bytes;
15 unsigned size;
16 unsigned used;
17 };
18
19 EXTERN void strbuf_init(struct strbuf *buf);
20 EXTERN void strbuf_release(struct strbuf *buf);
21 EXTERN void strbuf_clear(struct strbuf *buf);
22
23 /* Destroy buffer and return a copy as a C string */
24 EXTERN char *strbuf_steal(struct strbuf *buf);
25
26 /*
27 * Return a C string owned by the buffer invalidated if the buffer is
28 * changed).
29 */
30 EXTERN const char *strbuf_str(struct strbuf *buf);
31
32 EXTERN bool strbuf_pushchar(struct strbuf *buf, char ch);
33 EXTERN unsigned strbuf_pushchars(struct strbuf *buf, const char *str);
34 EXTERN void strbuf_popchar(struct strbuf *buf);
35 EXTERN void strbuf_popchars(struct strbuf *buf, unsigned n);
36 #undef EXTERN
37 #endif
File src/shared/util.c added (mode: 100644) (index 0000000..5cfb205)
1 /*
2 * kmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
5 * Copyright (C) 2012 Lucas De Marchi <lucas.de.marchi@gmail.com>
6 * Copyright (C) 2013-2014 Intel Corporation. All rights reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <assert.h>
23 #include <ctype.h>
24 #include <errno.h>
25 #include <stdarg.h>
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <limits.h>
32 #include <stdint.h>
33 #include <stdbool.h>
34 #include <libgen.h>
35 #include <sys/stat.h>
36
37 #include "config.h"
38
39 #include "libkmod-namespace.h"
40 #include "shared/macro.h"
41 #define SHARED_UTIL_C
42 #include "shared/util.h"
43 #undef SHARED_UTIL_C
44
45 #define USEC_PER_SEC 1000000ULL
46 #define NSEC_PER_USEC 1000ULL
47
48 static const struct kmod_ext {
49 const char *ext;
50 size_t len;
51 } kmod_exts[] = {
52 {KMOD_EXTENSION_UNCOMPRESSED, sizeof(KMOD_EXTENSION_UNCOMPRESSED) - 1},
53 #ifdef ENABLE_ZLIB
54 {".ko.gz", sizeof(".ko.gz") - 1},
55 #endif
56 #ifdef ENABLE_XZ
57 {".ko.xz", sizeof(".ko.xz") - 1},
58 #endif
59 { }
60 };
61
62 #if EAGAIN != EWOULDBLOCK
63 #error EAGAIN != EWOULDBLOCK
64 #endif
65
66 /* string handling functions and memory allocations */
67 /* ************************************************************************ */
68
69 void *memdup(const void *p, size_t n)
70 {
71 void *r = malloc(n);
72
73 if (r == NULL)
74 return NULL;
75
76 return memcpy(r, p, n);
77 }
78
79 char *strchr_replace(char *s, char c, char r)
80 {
81 char *p;
82
83 for (p = s; *p != '\0'; p++) {
84 if (*p == c)
85 *p = r;
86 }
87
88 return s;
89 }
90
91 int asprintf(char **str, const char *fmt, ...)
92 {
93 int size = 0;
94 va_list args;
95
96 va_start(args, fmt);
97
98 size = vasprintf(str, fmt, args);
99
100 va_end(args);
101
102 return size;
103 }
104
105 int vasprintf(char **str, const char *fmt, va_list args)
106 {
107 int size = 0;
108 va_list tmpa;
109
110 va_copy(tmpa, args);
111
112 size = vsnprintf(NULL, size, fmt, tmpa);
113
114 va_end(tmpa);
115
116 if (size < 0)
117 return -1;
118
119 *str = malloc(size + 1);
120
121 if (NULL == *str)
122 return -1;
123
124 size = vsprintf(*str, fmt, args);
125 return size;
126 }
127
128 /* module-related functions */
129 /* ************************************************************************ */
130 int alias_normalize(const char *alias, char buf[static PATH_MAX], size_t *len)
131 {
132 size_t i;
133
134 for (i = 0; i < PATH_MAX - 1; i++) {
135 const char c = alias[i];
136 switch (c) {
137 case '-':
138 buf[i] = '_';
139 break;
140 case ']':
141 return -EINVAL;
142 case '[':
143 while (alias[i] != ']' && alias[i] != '\0') {
144 buf[i] = alias[i];
145 i++;
146 }
147
148 if (alias[i] != ']')
149 return -EINVAL;
150
151 buf[i] = alias[i];
152 break;
153 case '\0':
154 goto finish;
155 default:
156 buf[i] = c;
157 }
158 }
159
160 finish:
161 buf[i] = '\0';
162 if (len)
163 *len = i;
164
165 return 0;
166 }
167
168 /*
169 * Replace dashes with underscores.
170 * Dashes inside character range patterns (e.g. [0-9]) are left unchanged.
171 *
172 * For convenience, it returns error if @s is NULL
173 */
174 int underscores(char *s)
175 {
176 unsigned int i;
177
178 if (!s)
179 return -EINVAL;
180
181 for (i = 0; s[i]; i++) {
182 switch (s[i]) {
183 case '-':
184 s[i] = '_';
185 break;
186 case ']':
187 return -EINVAL;
188 case '[':
189 i += strcspn(&s[i], "]");
190 if (!s[i])
191 return -EINVAL;
192 break;
193 }
194 }
195
196 return 0;
197 }
198
199 char *modname_normalize(const char *modname, char buf[static PATH_MAX], size_t *len)
200 {
201 size_t s;
202
203 for (s = 0; s < PATH_MAX - 1; s++) {
204 const char c = modname[s];
205 if (c == '-')
206 buf[s] = '_';
207 else if (c == '\0' || c == '.')
208 break;
209 else
210 buf[s] = c;
211 }
212
213 buf[s] = '\0';
214
215 if (len)
216 *len = s;
217
218 return buf;
219 }
220
221 char *path_to_modname(const char *path, char buf[static PATH_MAX], size_t *len)
222 {
223 char *modname;
224 char *modname_normalized;
225 char *path_cpy=strdup(path);
226 if (!path_cpy)
227 return NULL;
228
229 modname = basename(path_cpy);
230 if (modname == NULL || modname[0] == '\0') {
231 free(path_cpy);
232 return NULL;
233 }
234
235 modname_normalized = modname_normalize(modname, buf, len);
236 free(path_cpy);
237 return modname_normalized;
238 }
239
240 bool path_ends_with_kmod_ext(const char *path, size_t len)
241 {
242 const struct kmod_ext *eitr;
243
244 for (eitr = kmod_exts; eitr->ext != NULL; eitr++) {
245 if (len <= eitr->len)
246 continue;
247 if (streq(path + len - eitr->len, eitr->ext))
248 return true;
249 }
250
251 return false;
252 }
253
254 /* read-like and fread-like functions */
255 /* ************************************************************************ */
256 ssize_t read_str_safe(int fd, char *buf, size_t buflen)
257 {
258 size_t todo = buflen - 1;
259 size_t done = 0;
260
261 do {
262 ssize_t r = read(fd, buf + done, todo);
263
264 if (r == 0)
265 break;
266 else if (r > 0) {
267 todo -= r;
268 done += r;
269 } else {
270 if (errno == EAGAIN || errno == EINTR)
271 continue;
272 else
273 return -errno;
274 }
275 } while (todo > 0);
276
277 buf[done] = '\0';
278 return done;
279 }
280
281 ssize_t write_str_safe(int fd, const char *buf, size_t buflen)
282 {
283 size_t todo = buflen;
284 size_t done = 0;
285
286 do {
287 ssize_t r = write(fd, buf + done, todo);
288
289 if (r == 0)
290 break;
291 else if (r > 0) {
292 todo -= r;
293 done += r;
294 } else {
295 if (errno == EAGAIN || errno == EINTR)
296 continue;
297 else
298 return -errno;
299 }
300 } while (todo > 0);
301
302 return done;
303 }
304
305 int read_str_long(int fd, long *value, int base)
306 {
307 char buf[32], *end;
308 long v;
309 int err;
310
311 *value = 0;
312 err = read_str_safe(fd, buf, sizeof(buf));
313 if (err < 0)
314 return err;
315 errno = 0;
316 v = strtol(buf, &end, base);
317 if (end == buf || !isspace(*end))
318 return -EINVAL;
319
320 *value = v;
321 return 0;
322 }
323
324 int read_str_ulong(int fd, unsigned long *value, int base)
325 {
326 char buf[32], *end;
327 long v;
328 int err;
329
330 *value = 0;
331 err = read_str_safe(fd, buf, sizeof(buf));
332 if (err < 0)
333 return err;
334 errno = 0;
335 v = strtoul(buf, &end, base);
336 if (end == buf || !isspace(*end))
337 return -EINVAL;
338 *value = v;
339 return 0;
340 }
341
342 /*
343 * Read one logical line from a configuration file.
344 *
345 * Line endings may be escaped with backslashes, to form one logical line from
346 * several physical lines. No end of line character(s) are included in the
347 * result.
348 *
349 * If linenum is not NULL, it is incremented by the number of physical lines
350 * which have been read.
351 */
352 char *freadline_wrapped(FILE *fp, unsigned int *linenum)
353 {
354 int size = 256;
355 int i = 0, n = 0;
356 char *buf = malloc(size);
357
358 if (buf == NULL)
359 return NULL;
360
361 for(;;) {
362 int ch = getc_unlocked(fp);
363
364 switch(ch) {
365 case EOF:
366 if (i == 0) {
367 if (buf)
368 free(buf);
369 return NULL;
370 }
371 /* else fall through */
372
373 case '\n':
374 n++;
375
376 {
377 char *ret = buf;
378 ret[i] = '\0';
379 if (linenum)
380 *linenum += n;
381 return ret;
382 }
383
384 case '\\':
385 ch = getc_unlocked(fp);
386
387 if (ch == '\n') {
388 n++;
389 continue;
390 }
391 /* else fall through */
392
393 default:
394 buf[i++] = ch;
395
396 if (i == size) {
397 char *tmp;
398 size *= 2;
399 tmp = realloc(buf, size);
400 if (!tmp) {
401 if (buf)
402 free(buf);
403 return NULL;
404 }
405 buf = tmp;
406 }
407 }
408 }
409 if (buf)
410 free(buf);
411 }
412
413 /* path handling functions */
414 /* ************************************************************************ */
415
416 bool path_is_absolute(const char *p)
417 {
418 assert(p != NULL);
419
420 return p[0] == '/';
421 }
422
423 static char *get_current_dir_name(void)
424 {
425 size_t sz = PATH_MAX;
426 char *buf = NULL;
427
428 for(;;) {
429 char *cwd;
430
431 char *tmp = realloc(buf, sz);
432 if (!tmp)
433 break;
434 buf = tmp;
435
436 errno = 0;
437 cwd = getcwd(buf, sz);
438 if (cwd)
439 return cwd;
440
441 if (errno != ERANGE)
442 break;
443
444 sz += PATH_MAX;
445 }
446 free(buf);
447 return NULL;
448 }
449
450 char *path_make_absolute_cwd(const char *p)
451 {
452 char *cwd = NULL;
453 size_t plen, cwdlen;
454 char *r;
455
456 if (path_is_absolute(p))
457 return strdup(p);
458
459 cwd = get_current_dir_name();
460 if (!cwd)
461 return NULL;
462
463 plen = strlen(p);
464 cwdlen = strlen(cwd);
465
466 /* cwd + '/' + p + '\0' */
467 r = realloc(cwd, cwdlen + 1 + plen + 1);
468 if (r == NULL) {
469 if (cwd)
470 free(cwd);
471 return NULL;
472 }
473
474 r[cwdlen] = '/';
475 memcpy(&r[cwdlen + 1], p, plen + 1);
476
477 return r;
478 }
479
480 static inline int is_dir(const char *path)
481 {
482 struct stat st;
483
484 if (stat(path, &st) >= 0)
485 return S_ISDIR(st.st_mode);
486
487 return -errno;
488 }
489
490 int mkdir_p(const char *path, int len, mode_t mode)
491 {
492 int ret;
493 char *start, *end;
494
495 ret = 0;
496
497 start = strndup(path, len);
498 end = start + len;
499
500 /*
501 * scan backwards, replacing '/' with '\0' while the component doesn't
502 * exist
503 */
504 for (;;) {
505 int r = is_dir(start);
506 if (r > 0) {
507 end += strlen(end);
508
509 if (end == start + len) {
510 ret = 0;
511 goto exit;
512 }
513
514 /* end != start, since it would be caught on the first
515 * iteration */
516 *end = '/';
517 break;
518 } else if (r == 0) {
519 ret = -ENOTDIR;
520 goto exit;
521 }
522
523 if (end == start)
524 break;
525
526 *end = '\0';
527
528 /* Find the next component, backwards, discarding extra '/'*/
529 while (end > start && *end != '/')
530 end--;
531
532 while (end > start && *(end - 1) == '/')
533 end--;
534 }
535
536 for (; end < start + len;) {
537 if (mkdir(start, mode) < 0 && errno != EEXIST) {
538 ret = -errno;
539 goto exit;
540 }
541
542 end += strlen(end);
543 *end = '/';
544 }
545
546 exit:
547 free(start);
548 return ret;
549 }
550
551 int mkdir_parents(const char *path, mode_t mode)
552 {
553 char *end = strrchr(path, '/');
554
555 /* no parent directories */
556 if (end == NULL)
557 return 0;
558
559 return mkdir_p(path, end - path, mode);
560 }
561
562 unsigned long long ts_usec(const struct timespec *ts)
563 {
564 return (unsigned long long) ts->tv_sec * USEC_PER_SEC +
565 (unsigned long long) ts->tv_nsec / NSEC_PER_USEC;
566 }
567
568 unsigned long long stat_mstamp(const struct stat *st)
569 {
570 return (unsigned long long) st->st_mtime;
571 }
File src/shared/util.h added (mode: 100644) (index 0000000..b4ec351)
1 #ifndef SHARED_UTIL_H
2 #define SHARED_UTIL_H
3
4 #ifdef SHARED_UTIL_C
5 #define EXTERN
6 #else
7 #define EXTERN extern
8 #endif
9
10 /* string handling functions and memory allocations */
11 /* ************************************************************************ */
12 #define streq(a, b) (strcmp((a), (b)) == 0)
13 #define strstartswith(a, b) (strncmp(a, b, strlen(b)) == 0)
14 EXTERN char *strchr_replace(char *s, char c, char r);
15 EXTERN void *memdup(const void *p, size_t n);
16 EXTERN int asprintf(char **str, const char *fmt, ...);
17 EXTERN int vasprintf(char **str, const char *fmt, va_list args);
18
19 /* module-related functions */
20 /* ************************************************************************ */
21 #define KMOD_EXTENSION_UNCOMPRESSED ".ko"
22
23 EXTERN int alias_normalize(const char *alias, char buf[static PATH_MAX], size_t *len);
24 EXTERN int underscores(char *s);
25 EXTERN char *modname_normalize(const char *modname, char buf[static PATH_MAX], size_t *len);
26 EXTERN char *path_to_modname(const char *path, char buf[static PATH_MAX], size_t *len);
27 EXTERN bool path_ends_with_kmod_ext(const char *path, size_t len);
28
29 /* read-like and fread-like functions */
30 /* ************************************************************************ */
31 EXTERN ssize_t read_str_safe(int fd, char *buf, size_t buflen);
32 EXTERN ssize_t write_str_safe(int fd, const char *buf, size_t buflen);
33 EXTERN int read_str_long(int fd, long *value, int base);
34 EXTERN int read_str_ulong(int fd, unsigned long *value, int base);
35 EXTERN char *freadline_wrapped(FILE *fp, unsigned int *linenum);
36
37 /* path handling functions */
38 /* ************************************************************************ */
39 EXTERN bool path_is_absolute(const char *p);
40 EXTERN char *path_make_absolute_cwd(const char *p);
41 EXTERN int mkdir_p(const char *path, int len, mode_t mode);
42 EXTERN int mkdir_parents(const char *path, mode_t mode);
43 EXTERN unsigned long long stat_mstamp(const struct stat *st);
44 EXTERN unsigned long long ts_usec(const struct timespec *ts);
45
46 /* endianess and alignments */
47 /* ************************************************************************ */
48 _unused_ static unsigned int ALIGN_POWER2(unsigned int u)
49 {
50 return 1 << ((sizeof(u) * 8) - __builtin_clz(u - 1));
51 }
52
53 /* misc */
54 /* ************************************************************************ */
55 _unused_ static inline bool addu64_overflow(uint64_t a, uint64_t b, uint64_t *res)
56 {
57 *res = a + b;
58 return UINT64_MAX - a < b;
59 }
60 #undef EXTERN
61 #endif
File src/tools/depmod.c added (mode: 100644) (index 0000000..fcfb327)
1 /*
2 * kmod-depmod - calculate modules.dep using libkmod.
3 *
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <assert.h>
21 #include <ctype.h>
22 #include <dirent.h>
23 #include <errno.h>
24 #include <getopt.h>
25 #include <limits.h>
26 #include <regex.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <stddef.h>
32 #include <syslog.h>
33 #include <libgen.h>
34 #include <sys/stat.h>
35 #include <sys/utsname.h>
36
37 #include "config.h"
38
39 #include "libkmod.h"
40 #include "libkmod-paths.h"
41
42 #include "shared/array.h"
43 #include "shared/hash.h"
44 #include "shared/macro.h"
45 #include "shared/util.h"
46 #include "shared/scratchbuf.h"
47
48 #include "libkmod-internal.h"
49
50 #undef ERR
51 #undef DBG
52 #define TOOLS_DEPMOD_C
53 #include "kmod.h"
54 #undef TOOLS_DEPMOD_C
55 #include "log.h"
56
57 #define DEFAULT_VERBOSE LOG_WARNING
58 static int verbose = DEFAULT_VERBOSE;
59
60 static const char CFG_BUILTIN_KEY[] = "built-in";
61 static const char *default_cfg_paths[] = {
62 "/run/depmod.d",
63 SYSCONFDIR "/depmod.d",
64 "/lib/depmod.d",
65 NULL
66 };
67
68 static const char cmdopts_s[] = "aAb:C:E:F:euqrvnP:wmVh";
69 static const struct option cmdopts[] = {
70 { "all", no_argument, 0, 'a' },
71 { "quick", no_argument, 0, 'A' },
72 { "basedir", required_argument, 0, 'b' },
73 { "config", required_argument, 0, 'C' },
74 { "symvers", required_argument, 0, 'E' },
75 { "filesyms", required_argument, 0, 'F' },
76 { "errsyms", no_argument, 0, 'e' },
77 { "unresolved-error", no_argument, 0, 'u' }, /* deprecated */
78 { "quiet", no_argument, 0, 'q' }, /* deprecated */
79 { "root", no_argument, 0, 'r' }, /* deprecated */
80 { "verbose", no_argument, 0, 'v' },
81 { "show", no_argument, 0, 'n' },
82 { "dry-run", no_argument, 0, 'n' },
83 { "symbol-prefix", required_argument, 0, 'P' },
84 { "warn", no_argument, 0, 'w' },
85 { "map", no_argument, 0, 'm' }, /* deprecated */
86 { "version", no_argument, 0, 'V' },
87 { "help", no_argument, 0, 'h' },
88 { }
89 };
90
91 static void help(void)
92 {
93 printf("Usage:\n"
94 "\t%s -[aA] [options] [forced_version]\n"
95 "\n"
96 "If no arguments (except options) are given, \"depmod -a\" is assumed\n"
97 "\n"
98 "depmod will output a dependency list suitable for the modprobe utility.\n"
99 "\n"
100 "Options:\n"
101 "\t-a, --all Probe all modules\n"
102 "\t-A, --quick Only does the work if there's a new module\n"
103 "\t-e, --errsyms Report not supplied symbols\n"
104 "\t-n, --show Write the dependency file on stdout only\n"
105 "\t-P, --symbol-prefix Architecture symbol prefix\n"
106 "\t-C, --config=PATH Read configuration from PATH\n"
107 "\t-v, --verbose Enable verbose mode\n"
108 "\t-w, --warn Warn on duplicates\n"
109 "\t-V, --version show version\n"
110 "\t-h, --help show this help\n"
111 "\n"
112 "The following options are useful for people managing distributions:\n"
113 "\t-b, --basedir=DIR Use an image of a module tree.\n"
114 "\t-F, --filesyms=FILE Use the file instead of the\n"
115 "\t current kernel symbols.\n"
116 "\t-E, --symvers=FILE Use Module.symvers file to check\n"
117 "\t symbol versions.\n",
118 program_invocation_short_name);
119 }
120
121 static inline void _show(const char *fmt, ...)
122 {
123 va_list args;
124
125 if (verbose <= DEFAULT_VERBOSE)
126 return;
127
128 va_start(args, fmt);
129 vfprintf(stdout, fmt, args);
130 fflush(stdout);
131 va_end(args);
132 }
133 #define SHOW(...) _show(__VA_ARGS__)
134
135
136 /* binary index write *************************************************/
137 #include <arpa/inet.h>
138 /* BEGIN: code from module-init-tools/index.c just modified to compile here.
139 *
140 * Original copyright:
141 * index.c: module index file shared functions for modprobe and depmod
142 * Copyright (C) 2008 Alan Jenkins <alan-jenkins@tuffmail.co.uk>.
143 *
144 * These programs are free software; you can redistribute it and/or modify
145 * it under the terms of the GNU General Public License as published by
146 * the Free Software Foundation; either version 2 of the License, or
147 * (at your option) any later version.
148 *
149 * This program is distributed in the hope that it will be useful,
150 * but WITHOUT ANY WARRANTY; without even the implied warranty of
151 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
152 * GNU General Public License for more details.
153 *
154 * You should have received a copy of the GNU General Public License
155 * along with these programs. If not, see <http://www.gnu.org/licenses/>.
156 */
157
158 /* see documentation in libkmod/libkmod-index.c */
159
160 #define INDEX_MAGIC 0xB007F457
161 #define INDEX_VERSION_MAJOR 0x0002
162 #define INDEX_VERSION_MINOR 0x0001
163 #define INDEX_VERSION ((INDEX_VERSION_MAJOR<<16)|INDEX_VERSION_MINOR)
164 #define INDEX_CHILDMAX 128
165
166 struct index_value {
167 struct index_value *next;
168 unsigned int priority;
169 char value[0];
170 };
171
172 /* In-memory index (depmod only) */
173 struct index_node {
174 char *prefix; /* path compression */
175 struct index_value *values;
176 unsigned char first; /* range of child nodes */
177 unsigned char last;
178 struct index_node *children[INDEX_CHILDMAX]; /* indexed by character */
179 };
180
181
182 /* Format of node offsets within index file */
183 enum node_offset {
184 INDEX_NODE_FLAGS = 0xF0000000, /* Flags in high nibble */
185 INDEX_NODE_PREFIX = 0x80000000,
186 INDEX_NODE_VALUES = 0x40000000,
187 INDEX_NODE_CHILDS = 0x20000000,
188
189 INDEX_NODE_MASK = 0x0FFFFFFF, /* Offset value */
190 };
191
192 static struct index_node *index_create(void)
193 {
194 struct index_node *node;
195
196 node = NOFAIL(calloc(sizeof(struct index_node), 1));
197 node->prefix = NOFAIL(strdup(""));
198 node->first = INDEX_CHILDMAX;
199
200 return node;
201 }
202
203 static void index_values_free(struct index_value *values)
204 {
205 while (values) {
206 struct index_value *value = values;
207
208 values = value->next;
209 free(value);
210 }
211 }
212
213 static void index_destroy(struct index_node *node)
214 {
215 int c;
216
217 for (c = node->first; c <= node->last; c++) {
218 struct index_node *child = node->children[c];
219
220 if (child)
221 index_destroy(child);
222 }
223 index_values_free(node->values);
224 free(node->prefix);
225 free(node);
226 }
227
228 static void index__checkstring(const char *str)
229 {
230 int i;
231
232 for (i = 0; str[i]; i++) {
233 int ch = str[i];
234
235 if (ch >= INDEX_CHILDMAX)
236 CRIT("Module index: bad character '%c'=0x%x - only 7-bit ASCII is supported:"
237 "\n%s\n", (char) ch, (int) ch, str);
238 }
239 }
240
241 static int index_add_value(struct index_value **values,
242 const char *value, unsigned int priority)
243 {
244 struct index_value *v;
245 int duplicate = 0;
246 int len;
247
248 /* report the presence of duplicate values */
249 for (v = *values; v; v = v->next) {
250 if (streq(v->value, value))
251 duplicate = 1;
252 }
253
254 /* find position to insert value */
255 while (*values && (*values)->priority < priority)
256 values = &(*values)->next;
257
258 len = strlen(value);
259 v = NOFAIL(calloc(sizeof(struct index_value) + len + 1, 1));
260 v->next = *values;
261 v->priority = priority;
262 memcpy(v->value, value, len + 1);
263 *values = v;
264
265 return duplicate;
266 }
267
268 static int index_insert(struct index_node *node, const char *key,
269 const char *value, unsigned int priority)
270 {
271 int i = 0; /* index within str */
272 int ch;
273
274 index__checkstring(key);
275 index__checkstring(value);
276
277 while(1) {
278 int j; /* index within node->prefix */
279
280 /* Ensure node->prefix is a prefix of &str[i].
281 If it is not already, then we must split node. */
282 for (j = 0; node->prefix[j]; j++) {
283 ch = node->prefix[j];
284
285 if (ch != key[i+j]) {
286 char *prefix = node->prefix;
287 struct index_node *n;
288
289 /* New child is copy of node with prefix[j+1..N] */
290 n = NOFAIL(calloc(sizeof(struct index_node), 1));
291 memcpy(n, node, sizeof(struct index_node));
292 n->prefix = NOFAIL(strdup(&prefix[j+1]));
293
294 /* Parent has prefix[0..j], child at prefix[j] */
295 memset(node, 0, sizeof(struct index_node));
296 prefix[j] = '\0';
297 node->prefix = prefix;
298 node->first = ch;
299 node->last = ch;
300 node->children[ch] = n;
301
302 break;
303 }
304 }
305 /* j is now length of node->prefix */
306 i += j;
307
308 ch = key[i];
309 if(ch == '\0')
310 return index_add_value(&node->values, value, priority);
311
312 if (!node->children[ch]) {
313 struct index_node *child;
314
315 if (ch < node->first)
316 node->first = ch;
317 if (ch > node->last)
318 node->last = ch;
319 node->children[ch] = NOFAIL(calloc(sizeof(struct index_node), 1));
320
321 child = node->children[ch];
322 child->prefix = NOFAIL(strdup(&key[i+1]));
323 child->first = INDEX_CHILDMAX;
324 index_add_value(&child->values, value, priority);
325
326 return 0;
327 }
328
329 /* Descend into child node and continue */
330 node = node->children[ch];
331 i++;
332 }
333 }
334
335 static int index__haschildren(const struct index_node *node)
336 {
337 return node->first < INDEX_CHILDMAX;
338 }
339
340 /* Recursive post-order traversal
341
342 Pre-order would make for better read-side buffering / readahead / caching.
343 (post-order means you go backwards in the file as you descend the tree).
344 However, index reading is already fast enough.
345 Pre-order is simpler for writing, and depmod is already slow.
346 */
347 static uint32_t index_write__node(const struct index_node *node, FILE *out)
348 {
349 uint32_t *child_offs = NULL;
350 int child_count = 0;
351 long offset;
352
353 if (!node)
354 return 0;
355
356 /* Write children and save their offsets */
357 if (index__haschildren(node)) {
358 const struct index_node *child;
359 int i;
360
361 child_count = node->last - node->first + 1;
362 child_offs = NOFAIL(malloc(child_count * sizeof(uint32_t)));
363
364 for (i = 0; i < child_count; i++) {
365 child = node->children[node->first + i];
366 child_offs[i] = htonl(index_write__node(child, out));
367 }
368 }
369
370 /* Now write this node */
371 offset = ftell(out);
372
373 if (node->prefix[0]) {
374 fputs(node->prefix, out);
375 fputc('\0', out);
376 offset |= INDEX_NODE_PREFIX;
377 }
378
379 if (child_count) {
380 fputc(node->first, out);
381 fputc(node->last, out);
382 fwrite(child_offs, sizeof(uint32_t), child_count, out);
383 offset |= INDEX_NODE_CHILDS;
384 }
385
386 free(child_offs);
387
388 if (node->values) {
389 const struct index_value *v;
390 unsigned int value_count;
391 uint32_t u;
392
393 value_count = 0;
394 for (v = node->values; v != NULL; v = v->next)
395 value_count++;
396 u = htonl(value_count);
397 fwrite(&u, sizeof(u), 1, out);
398
399 for (v = node->values; v != NULL; v = v->next) {
400 u = htonl(v->priority);
401 fwrite(&u, sizeof(u), 1, out);
402 fputs(v->value, out);
403 fputc('\0', out);
404 }
405 offset |= INDEX_NODE_VALUES;
406 }
407
408 return offset;
409 }
410
411 static void index_write(const struct index_node *node, FILE *out)
412 {
413 long initial_offset, final_offset;
414 uint32_t u;
415
416 u = htonl(INDEX_MAGIC);
417 fwrite(&u, sizeof(u), 1, out);
418 u = htonl(INDEX_VERSION);
419 fwrite(&u, sizeof(u), 1, out);
420
421 /* Second word is reserved for the offset of the root node */
422 initial_offset = ftell(out);
423 assert(initial_offset >= 0);
424 u = 0;
425 fwrite(&u, sizeof(uint32_t), 1, out);
426
427 /* Dump trie */
428 u = htonl(index_write__node(node, out));
429
430 /* Update first word */
431 final_offset = ftell(out);
432 assert(final_offset >= 0);
433 (void)fseek(out, initial_offset, SEEK_SET);
434 fwrite(&u, sizeof(uint32_t), 1, out);
435 (void)fseek(out, final_offset, SEEK_SET);
436 }
437
438 /* END: code from module-init-tools/index.c just modified to compile here.
439 */
440
441 /* configuration parsing **********************************************/
442 struct cfg_override {
443 struct cfg_override *next;
444 size_t len;
445 char path[];
446 };
447
448 struct cfg_search {
449 struct cfg_search *next;
450 uint8_t builtin;
451 size_t len;
452 char path[];
453 };
454
455 struct cfg {
456 const char *kversion;
457 char dirname[PATH_MAX];
458 size_t dirnamelen;
459 char sym_prefix;
460 uint8_t check_symvers;
461 uint8_t print_unknown;
462 uint8_t warn_dups;
463 struct cfg_override *overrides;
464 struct cfg_search *searches;
465 };
466
467 static int cfg_search_add(struct cfg *cfg, const char *path, uint8_t builtin)
468 {
469 struct cfg_search *s;
470 size_t len;
471
472 if (builtin)
473 len = 0;
474 else
475 len = strlen(path) + 1;
476
477 s = malloc(sizeof(struct cfg_search) + len);
478 if (s == NULL) {
479 ERR("search add: out of memory\n");
480 return -ENOMEM;
481 }
482 s->builtin = builtin;
483 if (builtin)
484 s->len = 0;
485 else {
486 s->len = len - 1;
487 memcpy(s->path, path, len);
488 }
489
490 DBG("search add: %s, builtin=%hhu\n", path, builtin);
491
492 s->next = cfg->searches;
493 cfg->searches = s;
494 return 0;
495 }
496
497 static void cfg_search_free(struct cfg_search *s)
498 {
499 free(s);
500 }
501
502 static int cfg_override_add(struct cfg *cfg, const char *modname, const char *subdir)
503 {
504 struct cfg_override *o;
505 size_t modnamelen = strlen(modname);
506 size_t subdirlen = strlen(subdir);
507 size_t i;
508
509 o = malloc(sizeof(struct cfg_override) + subdirlen + 1
510 + modnamelen + 1);
511 if (o == NULL) {
512 ERR("override add: out of memory\n");
513 return -ENOMEM;
514 }
515 memcpy(o->path, subdir, subdirlen);
516 i = subdirlen;
517 o->path[i] = '/';
518 i++;
519
520 memcpy(o->path + i, modname, modnamelen);
521 i += modnamelen;
522 o->path[i] = '\0'; /* no extension, so we can match .ko/.ko.gz */
523
524 o->len = i;
525
526 DBG("override add: %s\n", o->path);
527
528 o->next = cfg->overrides;
529 cfg->overrides = o;
530 return 0;
531 }
532
533 static void cfg_override_free(struct cfg_override *o)
534 {
535 free(o);
536 }
537
538 static int cfg_kernel_matches(const struct cfg *cfg, const char *pattern)
539 {
540 regex_t re;
541 int status;
542
543 /* old style */
544 if (streq(pattern, "*"))
545 return 1;
546
547 if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB) != 0)
548 return 0;
549
550 status = regexec(&re, cfg->kversion, 0, NULL, 0);
551 regfree(&re);
552
553 return status == 0;
554 }
555
556 static int cfg_file_parse(struct cfg *cfg, const char *filename)
557 {
558 char *line;
559 FILE *fp;
560 unsigned int linenum = 0;
561 int err;
562
563 fp = fopen(filename, "r");
564 if (fp == NULL) {
565 err = -errno;
566 ERR("file parse %s: %m\n", filename);
567 return err;
568 }
569
570 while ((line = freadline_wrapped(fp, &linenum)) != NULL) {
571 char *cmd, *saveptr;
572
573 if (line[0] == '\0' || line[0] == '#')
574 goto done_next;
575
576 cmd = strtok_r(line, "\t ", &saveptr);
577 if (cmd == NULL)
578 goto done_next;
579
580 if (streq(cmd, "search")) {
581 const char *sp;
582 while ((sp = strtok_r(NULL, "\t ", &saveptr)) != NULL) {
583 uint8_t builtin = streq(sp, CFG_BUILTIN_KEY);
584 cfg_search_add(cfg, sp, builtin);
585 }
586 } else if (streq(cmd, "override")) {
587 const char *modname = strtok_r(NULL, "\t ", &saveptr);
588 const char *version = strtok_r(NULL, "\t ", &saveptr);
589 const char *subdir = strtok_r(NULL, "\t ", &saveptr);
590
591 if (modname == NULL || version == NULL ||
592 subdir == NULL)
593 goto syntax_error;
594
595 if (!cfg_kernel_matches(cfg, version)) {
596 INF("%s:%u: override kernel did not match %s\n",
597 filename, linenum, version);
598 goto done_next;
599 }
600
601 cfg_override_add(cfg, modname, subdir);
602 } else if (streq(cmd, "include")
603 || streq(cmd, "make_map_files")) {
604 INF("%s:%u: command %s not implemented yet\n",
605 filename, linenum, cmd);
606 } else {
607 syntax_error:
608 ERR("%s:%u: ignoring bad line starting with '%s'\n",
609 filename, linenum, cmd);
610 }
611
612 done_next:
613 free(line);
614 }
615
616 fclose(fp);
617
618 return 0;
619 }
620
621 static int cfg_files_filter_out(DIR *d, const char *dir, const char *name)
622 {
623 size_t len = strlen(name);
624 struct stat st;
625
626 if (name[0] == '.')
627 return 1;
628
629 if (len < 6 || !streq(name + len - 5, ".conf")) {
630 INF("All cfg files need .conf: %s/%s\n", dir, name);
631 return 1;
632 }
633
634 fstatat(dirfd(d), name, &st, 0);
635 if (S_ISDIR(st.st_mode)) {
636 ERR("Directories inside directories are not supported: %s/%s\n",
637 dir, name);
638 return 1;
639 }
640
641 return 0;
642 }
643
644 struct cfg_file {
645 size_t dirlen;
646 size_t namelen;
647 const char *name;
648 char path[];
649 };
650
651 static void cfg_file_free(struct cfg_file *f)
652 {
653 free(f);
654 }
655
656 static int cfg_files_insert_sorted(struct cfg_file ***p_files, size_t *p_n_files,
657 const char *dir, const char *name)
658 {
659 struct cfg_file **files, *f;
660 size_t i, n_files, namelen, dirlen;
661 void *tmp;
662 char *dir_cpy = NULL;
663
664 dirlen = strlen(dir);
665 if (name != NULL)
666 namelen = strlen(name);
667 else {
668 dir_cpy = strdup(dir);
669 if (!dir_cpy)
670 return -ENOMEM;
671 name = basename(dir_cpy);
672 namelen = strlen(name);
673 dirlen -= namelen + 1;
674 }
675
676 n_files = *p_n_files;
677 files = *p_files;
678 for (i = 0; i < n_files; i++) {
679 int cmp = strcmp(name, files[i]->name);
680 if (cmp == 0) {
681 DBG("Ignoring duplicate config file: %.*s/%s\n",
682 (int)dirlen, dir, name);
683 free(dir_cpy);
684 return -EEXIST;
685 } else if (cmp < 0)
686 break;
687 }
688
689 f = malloc(sizeof(struct cfg_file) + dirlen + namelen + 2);
690 if (f == NULL) {
691 ERR("files insert sorted: out of memory\n");
692 free(dir_cpy);
693 return -ENOMEM;
694 }
695
696 tmp = realloc(files, sizeof(struct cfg_file *) * (n_files + 1));
697 if (tmp == NULL) {
698 ERR("files insert sorted: out of memory\n");
699 free(f);
700 free(dir_cpy);
701 return -ENOMEM;
702 }
703 *p_files = files = tmp;
704
705 if (i < n_files) {
706 memmove(files + i + 1, files + i,
707 sizeof(struct cfg_file *) * (n_files - i));
708 }
709 files[i] = f;
710
711 f->dirlen = dirlen;
712 f->namelen = namelen;
713 f->name = f->path + dirlen + 1;
714 memcpy(f->path, dir, dirlen);
715 f->path[dirlen] = '/';
716 memcpy(f->path + dirlen + 1, name, namelen);
717 f->path[dirlen + 1 + namelen] = '\0';
718
719 *p_n_files = n_files + 1;
720 free(dir_cpy);
721 return 0;
722 }
723
724 /*
725 * Insert configuration files ignoring duplicates
726 */
727 static int cfg_files_list(struct cfg_file ***p_files, size_t *p_n_files,
728 const char *path)
729 {
730 struct dirent *dent;
731 DIR *d;
732 int err = 0;
733 struct stat st;
734
735 if (stat(path, &st) != 0) {
736 err = -errno;
737 DBG("could not stat '%s': %m\n", path);
738 return err;
739 }
740
741 if (!S_ISDIR(st.st_mode)) {
742 cfg_files_insert_sorted(p_files, p_n_files, path, NULL);
743 return 0;
744 }
745
746 d = opendir(path);
747 if (d == NULL) {
748 ERR("files list %s: %m\n", path);
749 return -EINVAL;
750 }
751
752 for (dent = readdir(d); dent != NULL; dent = readdir(d)) {
753 if (cfg_files_filter_out(d, path, dent->d_name))
754 continue;
755
756 cfg_files_insert_sorted(p_files, p_n_files, path, dent->d_name);
757 }
758
759 closedir(d);
760 DBG("parsed configuration files from %s\n", path);
761 return err;
762 }
763
764 static int cfg_load(struct cfg *cfg, const char * const *cfg_paths)
765 {
766 size_t i, n_files = 0;
767 struct cfg_file **files = NULL;
768
769 if (cfg_paths == NULL)
770 cfg_paths = default_cfg_paths;
771
772 for (i = 0; cfg_paths[i] != NULL; i++)
773 cfg_files_list(&files, &n_files, cfg_paths[i]);
774
775 for (i = 0; i < n_files; i++) {
776 struct cfg_file *f = files[i];
777 cfg_file_parse(cfg, f->path);
778 cfg_file_free(f);
779 }
780 free(files);
781
782 /* For backward compatibility add "updates" to the head of the search
783 * list here. But only if there was no "search" option specified.
784 */
785 if (cfg->searches == NULL)
786 cfg_search_add(cfg, "updates", 0);
787
788 return 0;
789 }
790
791 static void cfg_free(struct cfg *cfg)
792 {
793 while (cfg->overrides) {
794 struct cfg_override *tmp = cfg->overrides;
795 cfg->overrides = cfg->overrides->next;
796 cfg_override_free(tmp);
797 }
798
799 while (cfg->searches) {
800 struct cfg_search *tmp = cfg->searches;
801 cfg->searches = cfg->searches->next;
802 cfg_search_free(tmp);
803 }
804 }
805
806
807 /* depmod calculations ***********************************************/
808 struct vertex;
809 struct mod {
810 struct kmod_module *kmod;
811 char *path;
812 const char *relpath; /* path relative to '$ROOT/lib/modules/$VER/' */
813 char *uncrelpath; /* same as relpath but ending in .ko */
814 struct kmod_list *info_list;
815 struct kmod_list *dep_sym_list;
816 struct array deps; /* struct symbol */
817 size_t baselen; /* points to start of basename/filename */
818 size_t modnamesz;
819 int sort_idx; /* sort index using modules.order */
820 int dep_sort_idx; /* topological sort index */
821 uint16_t idx; /* index in depmod->modules.array */
822 uint16_t users; /* how many modules depend on this one */
823 bool visited; /* helper field to report cycles */
824 struct vertex *vertex; /* helper field to report cycles */
825 char modname[];
826 };
827
828 struct symbol {
829 struct mod *owner;
830 uint64_t crc;
831 char name[];
832 };
833
834 struct depmod {
835 const struct cfg *cfg;
836 struct kmod_ctx *ctx;
837 struct array modules;
838 struct hash *modules_by_uncrelpath;
839 struct hash *modules_by_name;
840 struct hash *symbols;
841 };
842
843 static void mod_free(struct mod *mod)
844 {
845 DBG("free %p kmod=%p, path=%s\n", mod, mod->kmod, mod->path);
846 array_free_array(&mod->deps);
847 kmod_module_unref(mod->kmod);
848 kmod_module_info_free_list(mod->info_list);
849 kmod_module_dependency_symbols_free_list(mod->dep_sym_list);
850 free(mod->uncrelpath);
851 free(mod->path);
852 free(mod);
853 }
854
855 static int mod_add_dependency(struct mod *mod, struct symbol *sym)
856 {
857 int err;
858
859 DBG("%s depends on %s %s\n", mod->path, sym->name,
860 sym->owner != NULL ? sym->owner->path : "(unknown)");
861
862 if (sym->owner == NULL)
863 return 0;
864
865 err = array_append_unique(&mod->deps, sym->owner);
866 if (err == -EEXIST)
867 return 0;
868 if (err < 0)
869 return err;
870
871 sym->owner->users++;
872 SHOW("%s needs \"%s\": %s\n", mod->path, sym->name, sym->owner->path);
873 return 0;
874 }
875
876 static void symbol_free(struct symbol *sym)
877 {
878 DBG("free %p sym=%s, owner=%p %s\n", sym, sym->name, sym->owner,
879 sym->owner != NULL ? sym->owner->path : "");
880 free(sym);
881 }
882
883 static int depmod_init(struct depmod *depmod, struct cfg *cfg,
884 struct kmod_ctx *ctx)
885 {
886 int err = 0;
887
888 depmod->cfg = cfg;
889 depmod->ctx = ctx;
890
891 array_init(&depmod->modules, 128);
892
893 depmod->modules_by_uncrelpath = hash_new(512, NULL);
894 if (depmod->modules_by_uncrelpath == NULL) {
895 err = -errno;
896 goto modules_by_uncrelpath_failed;
897 }
898
899 depmod->modules_by_name = hash_new(512, NULL);
900 if (depmod->modules_by_name == NULL) {
901 err = -errno;
902 goto modules_by_name_failed;
903 }
904
905 depmod->symbols = hash_new(2048, (void (*)(void *))symbol_free);
906 if (depmod->symbols == NULL) {
907 err = -errno;
908 goto symbols_failed;
909 }
910
911 return 0;
912
913 symbols_failed:
914 hash_free(depmod->modules_by_name);
915 modules_by_name_failed:
916 hash_free(depmod->modules_by_uncrelpath);
917 modules_by_uncrelpath_failed:
918 return err;
919 }
920
921 static void depmod_shutdown(struct depmod *depmod)
922 {
923 size_t i;
924
925 hash_free(depmod->symbols);
926
927 hash_free(depmod->modules_by_uncrelpath);
928
929 hash_free(depmod->modules_by_name);
930
931 for (i = 0; i < depmod->modules.count; i++)
932 mod_free(depmod->modules.array[i]);
933 array_free_array(&depmod->modules);
934
935 kmod_unref(depmod->ctx);
936 }
937
938 static int depmod_module_add(struct depmod *depmod, struct kmod_module *kmod)
939 {
940 const struct cfg *cfg = depmod->cfg;
941 const char *modname, *lastslash;
942 size_t modnamesz;
943 struct mod *mod;
944 int err;
945
946 modname = kmod_module_get_name(kmod);
947 modnamesz = strlen(modname) + 1;
948
949 mod = calloc(1, sizeof(struct mod) + modnamesz);
950 if (mod == NULL)
951 return -ENOMEM;
952 mod->kmod = kmod;
953 mod->sort_idx = depmod->modules.count + 1;
954 mod->dep_sort_idx = INT32_MAX;
955 memcpy(mod->modname, modname, modnamesz);
956 mod->modnamesz = modnamesz;
957
958 array_init(&mod->deps, 4);
959
960 mod->path = strdup(kmod_module_get_path(kmod));
961 lastslash = strrchr(mod->path, '/');
962 mod->baselen = lastslash - mod->path;
963 if (strncmp(mod->path, cfg->dirname, cfg->dirnamelen) == 0 &&
964 mod->path[cfg->dirnamelen] == '/')
965 mod->relpath = mod->path + cfg->dirnamelen + 1;
966 else
967 mod->relpath = NULL;
968
969 err = hash_add_unique(depmod->modules_by_name, mod->modname, mod);
970 if (err < 0) {
971 ERR("hash_add_unique %s: %s\n", mod->modname, strerror(-err));
972 goto fail;
973 }
974
975 if (mod->relpath != NULL) {
976 size_t uncrelpathlen = lastslash - mod->relpath + modnamesz
977 + strlen(KMOD_EXTENSION_UNCOMPRESSED);
978 mod->uncrelpath = memdup(mod->relpath, uncrelpathlen + 1);
979 mod->uncrelpath[uncrelpathlen] = '\0';
980 err = hash_add_unique(depmod->modules_by_uncrelpath,
981 mod->uncrelpath, mod);
982 if (err < 0) {
983 ERR("hash_add_unique %s: %s\n",
984 mod->uncrelpath, strerror(-err));
985 hash_del(depmod->modules_by_name, mod->modname);
986 goto fail;
987 }
988 }
989
990 DBG("add %p kmod=%p, path=%s\n", mod, kmod, mod->path);
991
992 return 0;
993
994 fail:
995 free(mod->uncrelpath);
996 free(mod);
997 return err;
998 }
999
1000 static int depmod_module_del(struct depmod *depmod, struct mod *mod)
1001 {
1002 DBG("del %p kmod=%p, path=%s\n", mod, mod->kmod, mod->path);
1003
1004 if (mod->uncrelpath != NULL)
1005 hash_del(depmod->modules_by_uncrelpath, mod->uncrelpath);
1006
1007 hash_del(depmod->modules_by_name, mod->modname);
1008
1009 mod_free(mod);
1010 return 0;
1011 }
1012
1013 /* returns if existing module @mod is higher priority than newpath.
1014 * note this is the inverse of module-init-tools is_higher_priority()
1015 */
1016 static int depmod_module_is_higher_priority(const struct depmod *depmod, const struct mod *mod, size_t baselen, size_t namelen, size_t modnamelen, const char *newpath)
1017 {
1018 const struct cfg *cfg = depmod->cfg;
1019 const struct cfg_override *ov;
1020 const struct cfg_search *se;
1021
1022 /* baselen includes the last '/' and mod->baselen doesn't. So it's
1023 * actually correct to use modnamelen in the first and modnamesz in
1024 * the latter */
1025 size_t newlen = baselen + modnamelen;
1026 size_t oldlen = mod->baselen + mod->modnamesz;
1027 const char *oldpath = mod->path;
1028 int i, bprio = -1, oldprio = -1, newprio = -1;
1029
1030 assert(strncmp(newpath, cfg->dirname, cfg->dirnamelen) == 0);
1031 assert(strncmp(oldpath, cfg->dirname, cfg->dirnamelen) == 0);
1032
1033 newpath += cfg->dirnamelen + 1;
1034 newlen -= cfg->dirnamelen + 1;
1035 oldpath += cfg->dirnamelen + 1;
1036 oldlen -= cfg->dirnamelen + 1;
1037
1038 DBG("comparing priorities of %s and %s\n",
1039 oldpath, newpath);
1040
1041 for (ov = cfg->overrides; ov != NULL; ov = ov->next) {
1042 DBG("override %s\n", ov->path);
1043 if (newlen == ov->len && memcmp(ov->path, newpath, newlen) == 0)
1044 return 0;
1045 if (oldlen == ov->len && memcmp(ov->path, oldpath, oldlen) == 0)
1046 return 1;
1047 }
1048
1049 for (i = 0, se = cfg->searches; se != NULL; se = se->next, i++) {
1050 DBG("search %s\n", se->builtin ? "built-in" : se->path);
1051 if (se->builtin)
1052 bprio = i;
1053 else if (newlen > se->len && newpath[se->len] == '/' &&
1054 memcmp(se->path, newpath, se->len) == 0)
1055 newprio = i;
1056 else if (oldlen > se->len && oldpath[se->len] == '/' &&
1057 memcmp(se->path, oldpath, se->len) == 0)
1058 oldprio = i;
1059 }
1060
1061 if (newprio < 0)
1062 newprio = bprio;
1063 if (oldprio < 0)
1064 oldprio = bprio;
1065
1066 DBG("priorities: built-in: %d, old: %d, new: %d\n",
1067 bprio, oldprio, newprio);
1068
1069 return newprio <= oldprio;
1070 }
1071
1072 static int depmod_modules_search_file(struct depmod *depmod, size_t baselen, size_t namelen, const char *path)
1073 {
1074 struct kmod_module *kmod;
1075 struct mod *mod;
1076 const char *relpath;
1077 char modname[PATH_MAX];
1078 size_t modnamelen;
1079 int err;
1080
1081 if (!path_ends_with_kmod_ext(path + baselen, namelen))
1082 return 0;
1083
1084 if (path_to_modname(path, modname, &modnamelen) == NULL) {
1085 ERR("could not get modname from path %s\n", path);
1086 return -EINVAL;
1087 }
1088
1089 relpath = path + depmod->cfg->dirnamelen + 1;
1090 DBG("try %s (%s)\n", relpath, modname);
1091
1092 mod = hash_find(depmod->modules_by_name, modname);
1093 if (mod == NULL)
1094 goto add;
1095
1096 if (depmod_module_is_higher_priority(depmod, mod, baselen,
1097 namelen, modnamelen, path)) {
1098 DBG("Ignored lower priority: %s, higher: %s\n",
1099 path, mod->path);
1100 return 0;
1101 }
1102
1103 DBG("Replace lower priority %s with new module %s\n",
1104 mod->relpath, relpath);
1105 err = depmod_module_del(depmod, mod);
1106 if (err < 0) {
1107 ERR("could not del module %s: %s\n", mod->path, strerror(-err));
1108 return err;
1109 }
1110
1111 add:
1112 err = kmod_module_new_from_path(depmod->ctx, path, &kmod);
1113 if (err < 0) {
1114 ERR("could not create module %s: %s\n", path, strerror(-err));
1115 return err;
1116 }
1117
1118 err = depmod_module_add(depmod, kmod);
1119 if (err < 0) {
1120 ERR("could not add module %s: %s\n",
1121 path, strerror(-err));
1122 kmod_module_unref(kmod);
1123 return err;
1124 }
1125 return 0;
1126 }
1127
1128 static int depmod_modules_search_dir(struct depmod *depmod, DIR *d, size_t baselen, char *path)
1129 {
1130 struct dirent *de;
1131 int err = 0, dfd = dirfd(d);
1132
1133 while ((de = readdir(d)) != NULL) {
1134 const char *name = de->d_name;
1135 size_t namelen;
1136 uint8_t is_dir;
1137
1138 if (name[0] == '.' && (name[1] == '\0' ||
1139 (name[1] == '.' && name[2] == '\0')))
1140 continue;
1141 if (streq(name, "build") || streq(name, "source"))
1142 continue;
1143 namelen = strlen(name);
1144 if (baselen + namelen + 2 >= PATH_MAX) {
1145 path[baselen] = '\0';
1146 ERR("path is too long %s%s\n", path, name);
1147 continue;
1148 }
1149 memcpy(path + baselen, name, namelen + 1);
1150
1151 if (de->d_type == DT_REG)
1152 is_dir = 0;
1153 else if (de->d_type == DT_DIR)
1154 is_dir = 1;
1155 else {
1156 struct stat st;
1157 if (fstatat(dfd, name, &st, 0) < 0) {
1158 ERR("fstatat(%d, %s): %m\n", dfd, name);
1159 continue;
1160 } else if (S_ISREG(st.st_mode))
1161 is_dir = 0;
1162 else if (S_ISDIR(st.st_mode))
1163 is_dir = 1;
1164 else {
1165 ERR("unsupported file type %s: %o\n",
1166 path, st.st_mode & S_IFMT);
1167 continue;
1168 }
1169 }
1170
1171 if (is_dir) {
1172 int fd;
1173 DIR *subdir;
1174 if (baselen + namelen + 2 + NAME_MAX >= PATH_MAX) {
1175 ERR("directory path is too long %s\n", path);
1176 continue;
1177 }
1178 fd = openat(dfd, name, O_RDONLY);
1179 if (fd < 0) {
1180 ERR("openat(%d, %s, O_RDONLY): %m\n",
1181 dfd, name);
1182 continue;
1183 }
1184 subdir = fdopendir(fd);
1185 if (subdir == NULL) {
1186 ERR("fdopendir(%d): %m\n", fd);
1187 close(fd);
1188 continue;
1189 }
1190 path[baselen + namelen] = '/';
1191 path[baselen + namelen + 1] = '\0';
1192 err = depmod_modules_search_dir(depmod, subdir,
1193 baselen + namelen + 1,
1194 path);
1195 closedir(subdir);
1196 } else {
1197 err = depmod_modules_search_file(depmod, baselen,
1198 namelen, path);
1199 }
1200
1201 if (err < 0) {
1202 path[baselen + namelen] = '\0';
1203 ERR("failed %s: %s\n", path, strerror(-err));
1204 err = 0; /* ignore errors */
1205 }
1206 }
1207
1208 return err;
1209 }
1210
1211 static int depmod_modules_search(struct depmod *depmod)
1212 {
1213 char path[PATH_MAX];
1214 DIR *d = opendir(depmod->cfg->dirname);
1215 size_t baselen;
1216 int err;
1217 if (d == NULL) {
1218 err = -errno;
1219 ERR("could not open directory %s: %m\n", depmod->cfg->dirname);
1220 return err;
1221 }
1222
1223 baselen = depmod->cfg->dirnamelen;
1224 memcpy(path, depmod->cfg->dirname, baselen);
1225 path[baselen] = '/';
1226 baselen++;
1227 path[baselen] = '\0';
1228
1229 err = depmod_modules_search_dir(depmod, d, baselen, path);
1230 closedir(d);
1231 return err;
1232 }
1233
1234 static int mod_cmp(const void *pa, const void *pb) {
1235 const struct mod *a = *(const struct mod **)pa;
1236 const struct mod *b = *(const struct mod **)pb;
1237 return a->sort_idx - b->sort_idx;
1238 }
1239
1240 static int depmod_modules_build_array(struct depmod *depmod)
1241 {
1242 struct hash_iter module_iter;
1243 const void *v;
1244 int err;
1245
1246 hash_iter_init(depmod->modules_by_name, &module_iter);
1247 while (hash_iter_next(&module_iter, NULL, &v)) {
1248 struct mod *mod = (struct mod *) v;
1249 mod->idx = depmod->modules.count;
1250 err = array_append(&depmod->modules, mod);
1251 if (err < 0)
1252 return err;
1253 }
1254
1255 return 0;
1256 }
1257
1258 static void depmod_modules_sort(struct depmod *depmod)
1259 {
1260 char order_file[PATH_MAX], line[PATH_MAX];
1261 FILE *fp;
1262 unsigned idx = 0, total = 0;
1263
1264 snprintf(order_file, sizeof(order_file), "%s/modules.order",
1265 depmod->cfg->dirname);
1266 fp = fopen(order_file, "r");
1267 if (fp == NULL) {
1268 WRN("could not open %s: %m\n", order_file);
1269 return;
1270 }
1271
1272 while (fgets(line, sizeof(line), fp) != NULL) {
1273 size_t len = strlen(line);
1274 idx++;
1275 if (len == 0)
1276 continue;
1277 if (line[len - 1] != '\n') {
1278 ERR("%s:%u corrupted line misses '\\n'\n",
1279 order_file, idx);
1280 goto corrupted;
1281 }
1282 }
1283 total = idx + 1;
1284 idx = 0;
1285 fseek(fp, 0, SEEK_SET);
1286 while (fgets(line, sizeof(line), fp) != NULL) {
1287 size_t len = strlen(line);
1288 struct mod *mod;
1289
1290 idx++;
1291 if (len == 0)
1292 continue;
1293 line[len - 1] = '\0';
1294
1295 mod = hash_find(depmod->modules_by_uncrelpath, line);
1296 if (mod == NULL)
1297 continue;
1298 mod->sort_idx = idx - total;
1299 }
1300
1301 array_sort(&depmod->modules, mod_cmp);
1302 for (idx = 0; idx < depmod->modules.count; idx++) {
1303 struct mod *m = depmod->modules.array[idx];
1304 m->idx = idx;
1305 }
1306
1307 corrupted:
1308 fclose(fp);
1309 }
1310
1311 static int depmod_symbol_add(struct depmod *depmod, const char *name,
1312 bool prefix_skipped, uint64_t crc,
1313 const struct mod *owner)
1314 {
1315 size_t namelen;
1316 int err;
1317 struct symbol *sym;
1318
1319 if (!prefix_skipped && (name[0] == depmod->cfg->sym_prefix))
1320 name++;
1321
1322 namelen = strlen(name) + 1;
1323 sym = malloc(sizeof(struct symbol) + namelen);
1324 if (sym == NULL)
1325 return -ENOMEM;
1326
1327 sym->owner = (struct mod *)owner;
1328 sym->crc = crc;
1329 memcpy(sym->name, name, namelen);
1330
1331 err = hash_add(depmod->symbols, sym->name, sym);
1332 if (err < 0) {
1333 free(sym);
1334 return err;
1335 }
1336
1337 DBG("add %p sym=%s, owner=%p %s\n", sym, sym->name, owner,
1338 owner != NULL ? owner->path : "");
1339
1340 return 0;
1341 }
1342
1343 static struct symbol *depmod_symbol_find(const struct depmod *depmod,
1344 const char *name)
1345 {
1346 if (name[0] == '.') /* PPC64 needs this: .foo == foo */
1347 name++;
1348 if (name[0] == depmod->cfg->sym_prefix)
1349 name++;
1350 return hash_find(depmod->symbols, name);
1351 }
1352
1353 static int depmod_load_modules(struct depmod *depmod)
1354 {
1355 struct mod **itr, **itr_end;
1356
1357 DBG("load symbols (%zd modules)\n", depmod->modules.count);
1358
1359 itr = (struct mod **)depmod->modules.array;
1360 itr_end = itr + depmod->modules.count;
1361 for (; itr < itr_end; itr++) {
1362 struct mod *mod = *itr;
1363 struct kmod_list *l, *list = NULL;
1364 int err = kmod_module_get_symbols(mod->kmod, &list);
1365 if (err < 0) {
1366 if (err == -ENOENT)
1367 DBG("ignoring %s: no symbols\n", mod->path);
1368 else
1369 ERR("failed to load symbols from %s: %s\n",
1370 mod->path, strerror(-err));
1371 goto load_info;
1372 }
1373 kmod_list_foreach(l, list) {
1374 const char *name = kmod_module_symbol_get_symbol(l);
1375 uint64_t crc = kmod_module_symbol_get_crc(l);
1376 depmod_symbol_add(depmod, name, false, crc, mod);
1377 }
1378 kmod_module_symbols_free_list(list);
1379
1380 load_info:
1381 kmod_module_get_info(mod->kmod, &mod->info_list);
1382 kmod_module_get_dependency_symbols(mod->kmod,
1383 &mod->dep_sym_list);
1384 kmod_module_unref(mod->kmod);
1385 mod->kmod = NULL;
1386 }
1387
1388 DBG("loaded symbols (%zd modules, %u symbols)\n",
1389 depmod->modules.count, hash_get_count(depmod->symbols));
1390
1391 return 0;
1392 }
1393
1394 static int depmod_load_module_dependencies(struct depmod *depmod, struct mod *mod)
1395 {
1396 const struct cfg *cfg = depmod->cfg;
1397 struct kmod_list *l;
1398
1399 DBG("do dependencies of %s\n", mod->path);
1400 kmod_list_foreach(l, mod->dep_sym_list) {
1401 const char *name = kmod_module_dependency_symbol_get_symbol(l);
1402 uint64_t crc = kmod_module_dependency_symbol_get_crc(l);
1403 int bindtype = kmod_module_dependency_symbol_get_bind(l);
1404 struct symbol *sym = depmod_symbol_find(depmod, name);
1405 uint8_t is_weak = bindtype == KMOD_SYMBOL_WEAK;
1406
1407 if (sym == NULL) {
1408 DBG("%s needs (%c) unknown symbol %s\n",
1409 mod->path, bindtype, name);
1410 if (cfg->print_unknown && !is_weak)
1411 WRN("%s needs unknown symbol %s\n",
1412 mod->path, name);
1413 continue;
1414 }
1415
1416 if (cfg->check_symvers && sym->crc != crc && !is_weak) {
1417 DBG("symbol %s (%#"PRIx64") module %s (%#"PRIx64")\n",
1418 sym->name, sym->crc, mod->path, crc);
1419 if (cfg->print_unknown)
1420 WRN("%s disagrees about version of symbol %s\n",
1421 mod->path, name);
1422 }
1423
1424 mod_add_dependency(mod, sym);
1425 }
1426
1427 return 0;
1428 }
1429
1430 static int depmod_load_dependencies(struct depmod *depmod)
1431 {
1432 struct mod **itr, **itr_end;
1433
1434 DBG("load dependencies (%zd modules, %u symbols)\n",
1435 depmod->modules.count, hash_get_count(depmod->symbols));
1436
1437 itr = (struct mod **)depmod->modules.array;
1438 itr_end = itr + depmod->modules.count;
1439 for (; itr < itr_end; itr++) {
1440 struct mod *mod = *itr;
1441
1442 if (mod->dep_sym_list == NULL) {
1443 DBG("ignoring %s: no dependency symbols\n", mod->path);
1444 continue;
1445 }
1446
1447 depmod_load_module_dependencies(depmod, mod);
1448 }
1449
1450 DBG("loaded dependencies (%zd modules, %u symbols)\n",
1451 depmod->modules.count, hash_get_count(depmod->symbols));
1452
1453 return 0;
1454 }
1455
1456 static int dep_cmp(const void *pa, const void *pb)
1457 {
1458 const struct mod *a = *(const struct mod **)pa;
1459 const struct mod *b = *(const struct mod **)pb;
1460 return a->dep_sort_idx - b->dep_sort_idx;
1461 }
1462
1463 static void depmod_sort_dependencies(struct depmod *depmod)
1464 {
1465 struct mod **itr, **itr_end;
1466 itr = (struct mod **)depmod->modules.array;
1467 itr_end = itr + depmod->modules.count;
1468 for (; itr < itr_end; itr++) {
1469 struct mod *m = *itr;
1470 if (m->deps.count > 1)
1471 array_sort(&m->deps, dep_cmp);
1472 }
1473 }
1474
1475 struct vertex {
1476 struct vertex *parent;
1477 struct mod *mod;
1478 };
1479
1480 static struct vertex *vertex_new(struct mod *mod, struct vertex *parent)
1481 {
1482 struct vertex *v;
1483
1484 v = malloc(sizeof(*v));
1485 if (v == NULL)
1486 return NULL;
1487
1488 v->parent = parent;
1489 v->mod = mod;
1490 return v;
1491 }
1492
1493 static void depmod_list_remove_data(struct kmod_list **list, void *data)
1494 {
1495 struct kmod_list *l;
1496
1497 l = __kmod_list_remove_data(*list, data);
1498 *list = l;
1499 }
1500
1501 static void depmod_report_one_cycle(struct depmod *depmod,
1502 struct vertex *vertex,
1503 struct kmod_list **roots,
1504 struct hash *loop_set)
1505 {
1506 const char sep[] = " -> ";
1507 size_t sz;
1508 char *buf;
1509 struct array reverse;
1510 int i;
1511 int n;
1512 struct vertex *v;
1513
1514 array_init(&reverse, 3);
1515
1516 sz = 0;
1517 for (v = vertex->parent, n = 0;
1518 v != NULL;
1519 v = v->parent, n++) {
1520
1521 sz += v->mod->modnamesz - 1;
1522 array_append(&reverse, v);
1523 hash_add(loop_set, v->mod->modname, NULL);
1524 }
1525 sz += vertex->mod->modnamesz - 1;
1526
1527 buf = malloc(sz + n * strlen(sep) + 1);
1528
1529 sz = 0;
1530 for (i = reverse.count - 1; i >= 0; i--) {
1531 size_t len;
1532
1533 v = reverse.array[i];
1534
1535 len = v->mod->modnamesz - 1;
1536 memcpy(buf + sz, v->mod->modname, len);
1537 sz += len;
1538 strcpy(buf + sz, sep);
1539 sz += strlen(sep);
1540
1541 depmod_list_remove_data(roots, v->mod);
1542 }
1543 strcpy(buf + sz, vertex->mod->modname);
1544 ERR("Cycle detected: %s\n", buf);
1545
1546 free(buf);
1547 array_free_array(&reverse);
1548 }
1549
1550 static int depmod_report_cycles_from_root(struct depmod *depmod,
1551 struct mod *root_mod,
1552 struct kmod_list **roots,
1553 void **stack,
1554 size_t stack_size,
1555 struct hash *loop_set)
1556 {
1557 struct kmod_list *free_list = NULL; /* struct vertex */
1558 struct kmod_list *l;
1559 struct vertex *root;
1560 struct vertex *vertex;
1561 struct vertex *v;
1562 struct mod *m;
1563 struct mod **itr, **itr_end;
1564 size_t is;
1565
1566 root = vertex_new(root_mod, NULL);
1567 if (root == NULL) {
1568 ERR("No memory to report cycles\n");
1569 return -ENOMEM;
1570 }
1571
1572 l = __kmod_list_append(free_list, root);
1573 if (l == NULL) {
1574 ERR("No memory to report cycles\n");
1575 return -ENOMEM;
1576 }
1577 free_list = l;
1578
1579 is = 0;
1580 stack[is++] = (void *)root;
1581
1582 while (is > 0) {
1583 vertex = stack[--is];
1584 m = vertex->mod;
1585 /*
1586 * because of the topological sort we can start only
1587 * from part of a loop or from a branch after a loop
1588 */
1589 if (m->visited && m == root->mod) {
1590 depmod_report_one_cycle(depmod, vertex,
1591 roots, loop_set);
1592 continue;
1593 }
1594
1595 m->visited = true;
1596 if (m->deps.count == 0) {
1597 /*
1598 * boundary condition: if there is more than one
1599 * single node branch (not a loop), it is
1600 * recognized as a loop by the code above:
1601 * m->visited because more then one,
1602 * m == root->mod since it is a single node.
1603 * So, prevent deeping into the branch second
1604 * time.
1605 */
1606 depmod_list_remove_data(roots, m);
1607
1608 continue;
1609 }
1610
1611 itr = (struct mod **) m->deps.array;
1612 itr_end = itr + m->deps.count;
1613 for (; itr < itr_end; itr++) {
1614 struct mod *dep = *itr;
1615 v = vertex_new(dep, vertex);
1616 if (v == NULL) {
1617 ERR("No memory to report cycles\n");
1618 return -ENOMEM;
1619 }
1620 assert(is < stack_size);
1621 stack[is++] = v;
1622
1623 l = __kmod_list_append(free_list, v);
1624 if (l == NULL) {
1625 ERR("No memory to report cycles\n");
1626 return -ENOMEM;
1627 }
1628 free_list = l;
1629
1630 }
1631 }
1632 while (free_list) {
1633 v = free_list->data;
1634 l = __kmod_list_remove(free_list);
1635 free_list = l;
1636 free(v);
1637 }
1638
1639 return 0;
1640 }
1641
1642 static void depmod_report_cycles(struct depmod *depmod, uint16_t n_mods,
1643 uint16_t *users)
1644 {
1645 int num_cyclic = 0;
1646 struct kmod_list *roots = NULL; /* struct mod */
1647 struct kmod_list *l;
1648 size_t n_r; /* local n_roots */
1649 int i;
1650 int err;
1651 void **stack = NULL;
1652 struct mod *m;
1653 struct mod *root;
1654 struct hash *loop_set;
1655
1656 for (i = 0, n_r = 0; i < n_mods; i++) {
1657 if (users[i] <= 0)
1658 continue;
1659 m = depmod->modules.array[i];
1660 l = __kmod_list_append(roots, m);
1661 if (l == NULL) {
1662 ERR("No memory to report cycles\n");
1663 return;
1664 }
1665 roots = l;
1666 n_r++;
1667 }
1668
1669 stack = malloc(n_r * sizeof(void *));
1670 if (stack == NULL) {
1671 ERR("No memory to report cycles\n");
1672 return;
1673 }
1674
1675 loop_set = hash_new(16, NULL);
1676 if (loop_set == NULL) {
1677 ERR("No memory to report cycles\n");
1678 free(stack);
1679 return;
1680 }
1681
1682 while (roots != NULL) {
1683 root = roots->data;
1684 l = __kmod_list_remove(roots);
1685 roots = l;
1686 err = depmod_report_cycles_from_root(depmod,
1687 root,
1688 &roots,
1689 stack, n_r, loop_set);
1690 if (err < 0)
1691 goto err;
1692 }
1693
1694 num_cyclic = hash_get_count(loop_set);
1695 ERR("Found %d modules in dependency cycles!\n", num_cyclic);
1696
1697 err:
1698 hash_free(loop_set);
1699 free(stack);
1700 }
1701
1702 static int depmod_calculate_dependencies(struct depmod *depmod)
1703 {
1704 const struct mod **itrm;
1705 uint16_t *users, *roots, *sorted;
1706 uint16_t i, n_roots = 0, n_sorted = 0, n_mods = depmod->modules.count;
1707 int ret = 0;
1708
1709 users = malloc(sizeof(uint16_t) * n_mods * 3);
1710 if (users == NULL)
1711 return -ENOMEM;
1712 roots = users + n_mods;
1713 sorted = roots + n_mods;
1714
1715 DBG("calculate dependencies and ordering (%hu modules)\n", n_mods);
1716
1717 assert(depmod->modules.count < UINT16_MAX);
1718
1719 /* populate modules users (how many modules uses it) */
1720 itrm = (const struct mod **)depmod->modules.array;
1721 for (i = 0; i < n_mods; i++, itrm++) {
1722 const struct mod *m = *itrm;
1723 users[i] = m->users;
1724 if (users[i] == 0) {
1725 roots[n_roots] = i;
1726 n_roots++;
1727 }
1728 }
1729
1730 /* topological sort (outputs modules without users first) */
1731 while (n_roots > 0) {
1732 const struct mod **itr_dst, **itr_dst_end;
1733 struct mod *src;
1734 uint16_t src_idx = roots[--n_roots];
1735
1736 src = depmod->modules.array[src_idx];
1737 src->dep_sort_idx = n_sorted;
1738 sorted[n_sorted] = src_idx;
1739 n_sorted++;
1740
1741 itr_dst = (const struct mod **)src->deps.array;
1742 itr_dst_end = itr_dst + src->deps.count;
1743 for (; itr_dst < itr_dst_end; itr_dst++) {
1744 const struct mod *dst = *itr_dst;
1745 uint16_t dst_idx = dst->idx;
1746 assert(users[dst_idx] > 0);
1747 users[dst_idx]--;
1748 if (users[dst_idx] == 0) {
1749 roots[n_roots] = dst_idx;
1750 n_roots++;
1751 }
1752 }
1753 }
1754
1755 if (n_sorted < n_mods) {
1756 depmod_report_cycles(depmod, n_mods, users);
1757 ret = -EINVAL;
1758 goto exit;
1759 }
1760
1761 depmod_sort_dependencies(depmod);
1762
1763 DBG("calculated dependencies and ordering (%hu modules)\n", n_mods);
1764
1765 exit:
1766 free(users);
1767 return ret;
1768 }
1769
1770 static int depmod_load(struct depmod *depmod)
1771 {
1772 int err;
1773
1774 err = depmod_load_modules(depmod);
1775 if (err < 0)
1776 return err;
1777
1778 err = depmod_load_dependencies(depmod);
1779 if (err < 0)
1780 return err;
1781
1782 err = depmod_calculate_dependencies(depmod);
1783 if (err < 0)
1784 return err;
1785
1786 return 0;
1787 }
1788
1789 static size_t mod_count_all_dependencies(const struct mod *mod)
1790 {
1791 size_t i, count = 0;
1792 for (i = 0; i < mod->deps.count; i++) {
1793 const struct mod *d = mod->deps.array[i];
1794 count += 1 + mod_count_all_dependencies(d);
1795 }
1796 return count;
1797 }
1798
1799 static int mod_fill_all_unique_dependencies(const struct mod *mod, const struct mod **deps, size_t n_deps, size_t *last)
1800 {
1801 size_t i;
1802 int err = 0;
1803 for (i = 0; i < mod->deps.count; i++) {
1804 const struct mod *d = mod->deps.array[i];
1805 size_t j;
1806 uint8_t exists = 0;
1807
1808 for (j = 0; j < *last; j++) {
1809 if (deps[j] == d) {
1810 exists = 1;
1811 break;
1812 }
1813 }
1814
1815 if (exists)
1816 continue;
1817
1818 if (*last >= n_deps)
1819 return -ENOSPC;
1820 deps[*last] = d;
1821 (*last)++;
1822 err = mod_fill_all_unique_dependencies(d, deps, n_deps, last);
1823 if (err < 0)
1824 break;
1825 }
1826 return err;
1827 }
1828
1829 static const struct mod **mod_get_all_sorted_dependencies(const struct mod *mod, size_t *n_deps)
1830 {
1831 const struct mod **deps;
1832 size_t last = 0;
1833
1834 *n_deps = mod_count_all_dependencies(mod);
1835 if (*n_deps == 0)
1836 return NULL;
1837
1838 deps = malloc(sizeof(struct mod *) * (*n_deps));
1839 if (deps == NULL)
1840 return NULL;
1841
1842 if (mod_fill_all_unique_dependencies(mod, deps, *n_deps, &last) < 0) {
1843 free(deps);
1844 return NULL;
1845 }
1846
1847 qsort(deps, last, sizeof(struct mod *), dep_cmp);
1848 *n_deps = last;
1849 return deps;
1850 }
1851
1852 static inline const char *mod_get_compressed_path(const struct mod *mod)
1853 {
1854 if (mod->relpath != NULL)
1855 return mod->relpath;
1856 return mod->path;
1857 }
1858
1859 static int output_deps(struct depmod *depmod, FILE *out)
1860 {
1861 size_t i;
1862
1863 for (i = 0; i < depmod->modules.count; i++) {
1864 const struct mod **deps, *mod = depmod->modules.array[i];
1865 const char *p = mod_get_compressed_path(mod);
1866 size_t j, n_deps;
1867
1868 fprintf(out, "%s:", p);
1869
1870 if (mod->deps.count == 0)
1871 goto end;
1872
1873 deps = mod_get_all_sorted_dependencies(mod, &n_deps);
1874 if (deps == NULL) {
1875 ERR("could not get all sorted dependencies of %s\n", p);
1876 goto end;
1877 }
1878
1879 for (j = 0; j < n_deps; j++) {
1880 const struct mod *d = deps[j];
1881 fprintf(out, " %s", mod_get_compressed_path(d));
1882 }
1883 free(deps);
1884 end:
1885 putc('\n', out);
1886 }
1887
1888 return 0;
1889 }
1890
1891 static int output_deps_bin(struct depmod *depmod, FILE *out)
1892 {
1893 struct index_node *idx;
1894 size_t i;
1895
1896 if (out == stdout)
1897 return 0;
1898
1899 idx = index_create();
1900 if (idx == NULL)
1901 return -ENOMEM;
1902
1903 for (i = 0; i < depmod->modules.count; i++) {
1904 const struct mod **deps, *mod = depmod->modules.array[i];
1905 const char *p = mod_get_compressed_path(mod);
1906 char *line;
1907 size_t j, n_deps, linepos, linelen, slen;
1908 int duplicate;
1909
1910 deps = mod_get_all_sorted_dependencies(mod, &n_deps);
1911 if (deps == NULL && n_deps > 0) {
1912 ERR("could not get all sorted dependencies of %s\n", p);
1913 continue;
1914 }
1915
1916 linelen = strlen(p) + 1;
1917 for (j = 0; j < n_deps; j++) {
1918 const struct mod *d = deps[j];
1919 linelen += 1 + strlen(mod_get_compressed_path(d));
1920 }
1921
1922 line = malloc(linelen + 1);
1923 if (line == NULL) {
1924 free(deps);
1925 ERR("modules.deps.bin: out of memory\n");
1926 continue;
1927 }
1928
1929 linepos = 0;
1930 slen = strlen(p);
1931 memcpy(line + linepos, p, slen);
1932 linepos += slen;
1933 line[linepos] = ':';
1934 linepos++;
1935
1936 for (j = 0; j < n_deps; j++) {
1937 const struct mod *d = deps[j];
1938 const char *dp;
1939
1940 line[linepos] = ' ';
1941 linepos++;
1942
1943 dp = mod_get_compressed_path(d);
1944 slen = strlen(dp);
1945 memcpy(line + linepos, dp, slen);
1946 linepos += slen;
1947 }
1948 line[linepos] = '\0';
1949
1950 duplicate = index_insert(idx, mod->modname, line, mod->idx);
1951 if (duplicate && depmod->cfg->warn_dups)
1952 WRN("duplicate module deps:\n%s\n", line);
1953 free(line);
1954 free(deps);
1955 }
1956
1957 index_write(idx, out);
1958 index_destroy(idx);
1959
1960 return 0;
1961 }
1962
1963 static int output_aliases(struct depmod *depmod, FILE *out)
1964 {
1965 size_t i;
1966
1967 fputs("# Aliases extracted from modules themselves.\n", out);
1968
1969 for (i = 0; i < depmod->modules.count; i++) {
1970 const struct mod *mod = depmod->modules.array[i];
1971 struct kmod_list *l;
1972
1973 kmod_list_foreach(l, mod->info_list) {
1974 const char *key = kmod_module_info_get_key(l);
1975 const char *value = kmod_module_info_get_value(l);
1976
1977 if (!streq(key, "alias"))
1978 continue;
1979
1980 fprintf(out, "alias %s %s\n", value, mod->modname);
1981 }
1982 }
1983
1984 return 0;
1985 }
1986
1987 static int output_aliases_bin(struct depmod *depmod, FILE *out)
1988 {
1989 struct index_node *idx;
1990 size_t i;
1991
1992 if (out == stdout)
1993 return 0;
1994
1995 idx = index_create();
1996 if (idx == NULL)
1997 return -ENOMEM;
1998
1999 for (i = 0; i < depmod->modules.count; i++) {
2000 const struct mod *mod = depmod->modules.array[i];
2001 struct kmod_list *l;
2002
2003 kmod_list_foreach(l, mod->info_list) {
2004 const char *key = kmod_module_info_get_key(l);
2005 const char *value = kmod_module_info_get_value(l);
2006 char buf[PATH_MAX];
2007 const char *alias;
2008 int duplicate;
2009
2010 if (!streq(key, "alias"))
2011 continue;
2012
2013 if (alias_normalize(value, buf, NULL) < 0) {
2014 WRN("Unmatched bracket in %s\n", value);
2015 continue;
2016 }
2017 alias = buf;
2018
2019 duplicate = index_insert(idx, alias, mod->modname,
2020 mod->idx);
2021 if (duplicate && depmod->cfg->warn_dups)
2022 WRN("duplicate module alias:\n%s %s\n",
2023 alias, mod->modname);
2024 }
2025 }
2026
2027 index_write(idx, out);
2028 index_destroy(idx);
2029
2030 return 0;
2031 }
2032
2033 static int output_softdeps(struct depmod *depmod, FILE *out)
2034 {
2035 size_t i;
2036
2037 fputs("# Soft dependencies extracted from modules themselves.\n", out);
2038
2039 for (i = 0; i < depmod->modules.count; i++) {
2040 const struct mod *mod = depmod->modules.array[i];
2041 struct kmod_list *l;
2042
2043 kmod_list_foreach(l, mod->info_list) {
2044 const char *key = kmod_module_info_get_key(l);
2045 const char *value = kmod_module_info_get_value(l);
2046
2047 if (!streq(key, "softdep"))
2048 continue;
2049
2050 fprintf(out, "softdep %s %s\n", mod->modname, value);
2051 }
2052 }
2053
2054 return 0;
2055 }
2056
2057 static int output_symbols(struct depmod *depmod, FILE *out)
2058 {
2059 struct hash_iter iter;
2060 const void *v;
2061
2062 fputs("# Aliases for symbols, used by symbol_request().\n", out);
2063
2064 hash_iter_init(depmod->symbols, &iter);
2065
2066 while (hash_iter_next(&iter, NULL, &v)) {
2067 const struct symbol *sym = v;
2068 if (sym->owner == NULL)
2069 continue;
2070
2071 fprintf(out, "alias symbol:%s %s\n",
2072 sym->name, sym->owner->modname);
2073 }
2074
2075 return 0;
2076 }
2077
2078 static int output_symbols_bin(struct depmod *depmod, FILE *out)
2079 {
2080 struct index_node *idx;
2081 char alias[1024];
2082 struct scratchbuf salias = SCRATCHBUF_INITIALIZER(alias);
2083 size_t baselen = sizeof("symbol:") - 1;
2084 struct hash_iter iter;
2085 const void *v;
2086 int ret = 0;
2087
2088 if (out == stdout) {
2089 scratchbuf_release(&salias);
2090 return 0;
2091 }
2092
2093 idx = index_create();
2094 if (idx == NULL) {
2095 scratchbuf_release(&salias);
2096 return -ENOMEM;
2097 }
2098
2099 memcpy(alias, "symbol:", baselen);
2100
2101 hash_iter_init(depmod->symbols, &iter);
2102
2103 while (hash_iter_next(&iter, NULL, &v)) {
2104 int duplicate;
2105 const struct symbol *sym = v;
2106 size_t len;
2107
2108 if (sym->owner == NULL)
2109 continue;
2110
2111 len = strlen(sym->name);
2112
2113 if (scratchbuf_alloc(&salias, baselen + len + 1) < 0) {
2114 ret = -ENOMEM;
2115 goto err_scratchbuf;
2116 }
2117 memcpy(scratchbuf_str(&salias) + baselen, sym->name, len + 1);
2118 duplicate = index_insert(idx, alias, sym->owner->modname,
2119 sym->owner->idx);
2120
2121 if (duplicate && depmod->cfg->warn_dups)
2122 WRN("duplicate module syms:\n%s %s\n",
2123 alias, sym->owner->modname);
2124 }
2125
2126 index_write(idx, out);
2127
2128 err_scratchbuf:
2129 index_destroy(idx);
2130
2131 if (ret < 0)
2132 ERR("output symbols: %s\n", strerror(-ret));
2133 scratchbuf_release(&salias);
2134 return ret;
2135 }
2136
2137 static int output_builtin_bin(struct depmod *depmod, FILE *out)
2138 {
2139 FILE *in;
2140 struct index_node *idx;
2141 char infile[PATH_MAX], line[PATH_MAX], modname[PATH_MAX];
2142
2143 if (out == stdout)
2144 return 0;
2145
2146 snprintf(infile, sizeof(infile), "%s/modules.builtin",
2147 depmod->cfg->dirname);
2148 in = fopen(infile, "r");
2149 if (in == NULL) {
2150 WRN("could not open %s: %m\n", infile);
2151 return 0;
2152 }
2153
2154 idx = index_create();
2155 if (idx == NULL) {
2156 fclose(in);
2157 return -ENOMEM;
2158 }
2159
2160 while (fgets(line, sizeof(line), in) != NULL) {
2161 if (!isalpha(line[0])) {
2162 ERR("Invalid modules.builtin line: %s\n", line);
2163 continue;
2164 }
2165
2166 path_to_modname(line, modname, NULL);
2167 index_insert(idx, modname, "", 0);
2168 }
2169
2170 index_write(idx, out);
2171 index_destroy(idx);
2172 fclose(in);
2173
2174 return 0;
2175 }
2176
2177 static int output_devname(struct depmod *depmod, FILE *out)
2178 {
2179 size_t i;
2180 bool empty = true;
2181
2182 for (i = 0; i < depmod->modules.count; i++) {
2183 const struct mod *mod = depmod->modules.array[i];
2184 struct kmod_list *l;
2185 const char *devname = NULL;
2186 char type = '\0';
2187 unsigned int major = 0, minor = 0;
2188
2189 kmod_list_foreach(l, mod->info_list) {
2190 const char *key = kmod_module_info_get_key(l);
2191 const char *value = kmod_module_info_get_value(l);
2192 unsigned int maj, min;
2193
2194 if (!streq(key, "alias"))
2195 continue;
2196
2197 if (strstartswith(value, "devname:"))
2198 devname = value + sizeof("devname:") - 1;
2199 else if (sscanf(value, "char-major-%u-%u",
2200 &maj, &min) == 2) {
2201 type = 'c';
2202 major = maj;
2203 minor = min;
2204 } else if (sscanf(value, "block-major-%u-%u",
2205 &maj, &min) == 2) {
2206 type = 'b';
2207 major = maj;
2208 minor = min;
2209 }
2210
2211 if (type != '\0' && devname != NULL)
2212 break;
2213 }
2214
2215 if (devname != NULL) {
2216 if (type != '\0') {
2217 if (empty) {
2218 fputs("# Device nodes to trigger on-demand module loading.\n",
2219 out);
2220 empty = false;
2221 }
2222 fprintf(out, "%s %s %c%u:%u\n", mod->modname,
2223 devname, type, major, minor);
2224 } else
2225 ERR("Module '%s' has devname (%s) but "
2226 "lacks major and minor information. "
2227 "Ignoring.\n", mod->modname, devname);
2228 }
2229 }
2230
2231 return 0;
2232 }
2233
2234 static int depmod_output(struct depmod *depmod, FILE *out)
2235 {
2236 static const struct depfile {
2237 const char *name;
2238 int (*cb)(struct depmod *depmod, FILE *out);
2239 } *itr, depfiles[] = {
2240 { "modules.dep", output_deps },
2241 { "modules.dep.bin", output_deps_bin },
2242 { "modules.alias", output_aliases },
2243 { "modules.alias.bin", output_aliases_bin },
2244 { "modules.softdep", output_softdeps },
2245 { "modules.symbols", output_symbols },
2246 { "modules.symbols.bin", output_symbols_bin },
2247 { "modules.builtin.bin", output_builtin_bin },
2248 { "modules.devname", output_devname },
2249 { }
2250 };
2251 const char *dname = depmod->cfg->dirname;
2252 int dfd, err = 0;
2253
2254 if (out != NULL)
2255 dfd = -1;
2256 else {
2257 dfd = open(dname, O_RDONLY);
2258 if (dfd < 0) {
2259 err = -errno;
2260 CRIT("could not open directory %s: %m\n", dname);
2261 return err;
2262 }
2263 }
2264
2265 for (itr = depfiles; itr->name != NULL; itr++) {
2266 FILE *fp = out;
2267 char tmp[NAME_MAX] = "";
2268 int r, ferr;
2269
2270 if (fp == NULL) {
2271 int flags = O_CREAT | O_TRUNC | O_WRONLY;
2272 int mode = 0644;
2273 int fd;
2274
2275 snprintf(tmp, sizeof(tmp), "%s.tmp", itr->name);
2276 fd = openat(dfd, tmp, flags, mode);
2277 if (fd < 0) {
2278 ERR("openat(%s, %s, %o, %o): %m\n",
2279 dname, tmp, flags, mode);
2280 continue;
2281 }
2282 fp = fdopen(fd, "wb");
2283 if (fp == NULL) {
2284 ERR("fdopen(%d=%s/%s): %m\n", fd, dname, tmp);
2285 close(fd);
2286 continue;
2287 }
2288 }
2289
2290 r = itr->cb(depmod, fp);
2291 if (fp == out)
2292 continue;
2293
2294 ferr = ferror(fp) | fclose(fp);
2295
2296 if (r < 0) {
2297 if (unlinkat(dfd, tmp, 0) != 0)
2298 ERR("unlinkat(%s, %s): %m\n", dname, tmp);
2299
2300 ERR("Could not write index '%s': %s\n", itr->name,
2301 strerror(-r));
2302 err = -errno;
2303 break;
2304 }
2305
2306 unlinkat(dfd, itr->name, 0);
2307 if (renameat(dfd, tmp, dfd, itr->name) != 0) {
2308 err = -errno;
2309 CRIT("renameat(%s, %s, %s, %s): %m\n",
2310 dname, tmp, dname, itr->name);
2311 break;
2312 }
2313
2314 if (ferr) {
2315 err = -ENOSPC;
2316 ERR("Could not create index '%s'. Output is truncated: %s\n",
2317 itr->name, strerror(-err));
2318 break;
2319 }
2320 }
2321
2322 if (dfd >= 0)
2323 close(dfd);
2324
2325 return err;
2326 }
2327
2328 static void depmod_add_fake_syms(struct depmod *depmod)
2329 {
2330 /* __this_module is magic inserted by kernel loader. */
2331 depmod_symbol_add(depmod, "__this_module", true, 0, NULL);
2332 /* On S390, this is faked up too */
2333 depmod_symbol_add(depmod, "_GLOBAL_OFFSET_TABLE_", true, 0, NULL);
2334 /* On PowerPC64 ABIv2, .TOC. is more or less _GLOBAL_OFFSET_TABLE_ */
2335 depmod_symbol_add(depmod, "TOC.", true, 0, NULL);
2336 }
2337
2338 static int depmod_load_symvers(struct depmod *depmod, const char *filename)
2339 {
2340 char line[10240];
2341 FILE *fp;
2342 unsigned int linenum = 0;
2343
2344 fp = fopen(filename, "r");
2345 if (fp == NULL) {
2346 int err = -errno;
2347 DBG("load symvers: %s: %m\n", filename);
2348 return err;
2349 }
2350 DBG("load symvers: %s\n", filename);
2351
2352 /* eg. "0xb352177e\tfind_first_bit\tvmlinux\tEXPORT_SYMBOL" */
2353 while (fgets(line, sizeof(line), fp) != NULL) {
2354 const char *ver, *sym, *where;
2355 char *verend;
2356 uint64_t crc;
2357
2358 linenum++;
2359
2360 ver = strtok(line, " \t");
2361 sym = strtok(NULL, " \t");
2362 where = strtok(NULL, " \t");
2363 if (!ver || !sym || !where)
2364 continue;
2365
2366 if (!streq(where, "vmlinux"))
2367 continue;
2368
2369 crc = strtoull(ver, &verend, 16);
2370 if (verend[0] != '\0') {
2371 ERR("%s:%u Invalid symbol version %s: %m\n",
2372 filename, linenum, ver);
2373 continue;
2374 }
2375
2376 depmod_symbol_add(depmod, sym, false, crc, NULL);
2377 }
2378 depmod_add_fake_syms(depmod);
2379
2380 DBG("loaded symvers: %s\n", filename);
2381
2382 fclose(fp);
2383 return 0;
2384 }
2385
2386 static int depmod_load_system_map(struct depmod *depmod, const char *filename)
2387 {
2388 const char ksymstr[] = "__ksymtab_";
2389 const size_t ksymstr_len = sizeof(ksymstr) - 1;
2390 char line[10240];
2391 FILE *fp;
2392 unsigned int linenum = 0;
2393
2394 fp = fopen(filename, "r");
2395 if (fp == NULL) {
2396 int err = -errno;
2397 DBG("load System.map: %s: %m\n", filename);
2398 return err;
2399 }
2400 DBG("load System.map: %s\n", filename);
2401
2402 /* eg. c0294200 R __ksymtab_devfs_alloc_devnum */
2403 while (fgets(line, sizeof(line), fp) != NULL) {
2404 char *p, *end;
2405
2406 linenum++;
2407
2408 p = strchr(line, ' ');
2409 if (p == NULL)
2410 goto invalid_syntax;
2411 p++;
2412 p = strchr(p, ' ');
2413 if (p == NULL)
2414 goto invalid_syntax;
2415 p++;
2416
2417 /* skip prefix */
2418 if (p[0] == depmod->cfg->sym_prefix)
2419 p++;
2420
2421 /* Covers gpl-only and normal symbols. */
2422 if (strncmp(p, ksymstr, ksymstr_len) != 0)
2423 continue;
2424
2425 end = strchr(p, '\n');
2426 if (end != NULL)
2427 *end = '\0';
2428
2429 depmod_symbol_add(depmod, p + ksymstr_len, true, 0, NULL);
2430 continue;
2431
2432 invalid_syntax:
2433 ERR("%s:%u: invalid line: %s\n", filename, linenum, line);
2434 }
2435 depmod_add_fake_syms(depmod);
2436
2437 DBG("loaded System.map: %s\n", filename);
2438
2439 fclose(fp);
2440 return 0;
2441 }
2442
2443
2444 static int depfile_up_to_date_dir(DIR *d, time_t mtime, size_t baselen, char *path)
2445 {
2446 struct dirent *de;
2447 int err = 1, dfd = dirfd(d);
2448
2449 while ((de = readdir(d)) != NULL) {
2450 const char *name = de->d_name;
2451 size_t namelen;
2452 struct stat st;
2453
2454 if (name[0] == '.' && (name[1] == '\0' ||
2455 (name[1] == '.' && name[2] == '\0')))
2456 continue;
2457 if (streq(name, "build") || streq(name, "source"))
2458 continue;
2459 namelen = strlen(name);
2460 if (baselen + namelen + 2 >= PATH_MAX) {
2461 path[baselen] = '\0';
2462 ERR("path is too long %s%s\n", path, name);
2463 continue;
2464 }
2465
2466 if (fstatat(dfd, name, &st, 0) < 0) {
2467 ERR("fstatat(%d, %s): %m\n", dfd, name);
2468 continue;
2469 }
2470
2471 if (S_ISDIR(st.st_mode)) {
2472 int fd;
2473 DIR *subdir;
2474 memcpy(path + baselen, name, namelen + 1);
2475 if (baselen + namelen + 2 + NAME_MAX >= PATH_MAX) {
2476 ERR("directory path is too long %s\n", path);
2477 continue;
2478 }
2479 fd = openat(dfd, name, O_RDONLY);
2480 if (fd < 0) {
2481 ERR("openat(%d, %s, O_RDONLY): %m\n",
2482 dfd, name);
2483 continue;
2484 }
2485 subdir = fdopendir(fd);
2486 if (subdir == NULL) {
2487 ERR("fdopendir(%d): %m\n", fd);
2488 close(fd);
2489 continue;
2490 }
2491 path[baselen + namelen] = '/';
2492 path[baselen + namelen + 1] = '\0';
2493 err = depfile_up_to_date_dir(subdir, mtime,
2494 baselen + namelen + 1,
2495 path);
2496 closedir(subdir);
2497 } else if (S_ISREG(st.st_mode)) {
2498 if (!path_ends_with_kmod_ext(name, namelen))
2499 continue;
2500
2501 memcpy(path + baselen, name, namelen + 1);
2502 err = st.st_mtime <= mtime;
2503 if (err == 0) {
2504 DBG("%s %"PRIu64" is newer than %"PRIu64"\n",
2505 path, (uint64_t)st.st_mtime,
2506 (uint64_t)mtime);
2507 }
2508 } else {
2509 ERR("unsupported file type %s: %o\n",
2510 path, st.st_mode & S_IFMT);
2511 continue;
2512 }
2513
2514 if (err == 0)
2515 break; /* outdated! */
2516 else if (err < 0) {
2517 path[baselen + namelen] = '\0';
2518 ERR("failed %s: %s\n", path, strerror(-err));
2519 err = 1; /* ignore errors */
2520 }
2521 }
2522
2523 return err;
2524 }
2525
2526 /* uptodate: 1, outdated: 0, errors < 0 */
2527 static int depfile_up_to_date(const char *dirname)
2528 {
2529 char path[PATH_MAX];
2530 DIR *d = opendir(dirname);
2531 struct stat st;
2532 size_t baselen;
2533 int err;
2534 if (d == NULL) {
2535 err = -errno;
2536 ERR("could not open directory %s: %m\n", dirname);
2537 return err;
2538 }
2539
2540 if (fstatat(dirfd(d), "modules.dep", &st, 0) != 0) {
2541 err = -errno;
2542 ERR("could not fstatat(%s, modules.dep): %m\n", dirname);
2543 closedir(d);
2544 return err;
2545 }
2546
2547 baselen = strlen(dirname);
2548 memcpy(path, dirname, baselen);
2549 path[baselen] = '/';
2550 baselen++;
2551 path[baselen] = '\0';
2552
2553 err = depfile_up_to_date_dir(d, st.st_mtime, baselen, path);
2554 closedir(d);
2555 return err;
2556 }
2557
2558 static int is_version_number(const char *version)
2559 {
2560 unsigned int d1, d2;
2561 return (sscanf(version, "%u.%u", &d1, &d2) == 2);
2562 }
2563
2564 static int do_depmod(int argc, char *argv[])
2565 {
2566 FILE *out = NULL;
2567 int err = 0, all = 0, maybe_all = 0, n_config_paths = 0;
2568 char *root = NULL;
2569 const char **config_paths = NULL;
2570 const char *system_map = NULL;
2571 const char *module_symvers = NULL;
2572 const char *null_kmod_config = NULL;
2573 struct utsname un;
2574 struct kmod_ctx *ctx = NULL;
2575 struct cfg cfg;
2576 struct depmod depmod;
2577
2578 memset(&cfg, 0, sizeof(cfg));
2579 memset(&depmod, 0, sizeof(depmod));
2580
2581 for (;;) {
2582 int c, idx = 0;
2583 c = getopt_long(argc, argv, cmdopts_s, cmdopts, &idx);
2584 if (c == -1)
2585 break;
2586 switch (c) {
2587 case 'a':
2588 all = 1;
2589 break;
2590 case 'A':
2591 maybe_all = 1;
2592 break;
2593 case 'b':
2594 if (root)
2595 free(root);
2596 root = path_make_absolute_cwd(optarg);
2597 break;
2598 case 'C': {
2599 size_t bytes = sizeof(char *) * (n_config_paths + 2);
2600 void *tmp = realloc(config_paths, bytes);
2601 if (!tmp) {
2602 fputs("Error: out-of-memory\n", stderr);
2603 goto cmdline_failed;
2604 }
2605 config_paths = tmp;
2606 config_paths[n_config_paths] = optarg;
2607 n_config_paths++;
2608 config_paths[n_config_paths] = NULL;
2609 break;
2610 }
2611 case 'E':
2612 module_symvers = optarg;
2613 cfg.check_symvers = 1;
2614 break;
2615 case 'F':
2616 system_map = optarg;
2617 break;
2618 case 'e':
2619 cfg.print_unknown = 1;
2620 break;
2621 case 'v':
2622 verbose++;
2623 break;
2624 case 'n':
2625 out = stdout;
2626 break;
2627 case 'P':
2628 if (optarg[1] != '\0') {
2629 CRIT("-P only takes a single char\n");
2630 goto cmdline_failed;
2631 }
2632 cfg.sym_prefix = optarg[0];
2633 break;
2634 case 'w':
2635 cfg.warn_dups = 1;
2636 break;
2637 case 'u':
2638 case 'q':
2639 case 'r':
2640 case 'm':
2641 if (idx > 0)
2642 WRN("Ignored deprecated option --%s\n",
2643 cmdopts[idx].name);
2644 else
2645 WRN("Ignored deprecated option -%c\n", c);
2646
2647 break;
2648 case 'h':
2649 help();
2650 if (root)
2651 free(root);
2652 if (config_paths)
2653 free(config_paths);
2654 return EXIT_SUCCESS;
2655 case 'V':
2656 puts("kmod version " VERSION);
2657 puts(KMOD_FEATURES);
2658 if (root)
2659 free(root);
2660 if (config_paths)
2661 free(config_paths);
2662 return EXIT_SUCCESS;
2663 case '?':
2664 goto cmdline_failed;
2665 default:
2666 ERR("unexpected getopt_long() value '%c'.\n", c);
2667 goto cmdline_failed;
2668 }
2669 }
2670
2671 if (optind < argc) {
2672 if (!is_version_number(argv[optind])) {
2673 ERR("Bad version passed %s\n", argv[optind]);
2674 goto cmdline_failed;
2675 }
2676 cfg.kversion = argv[optind];
2677 optind++;
2678 } else {
2679 if (uname(&un) < 0) {
2680 CRIT("uname() failed: %s\n", strerror(errno));
2681 goto cmdline_failed;
2682 }
2683 cfg.kversion = un.release;
2684 }
2685
2686 cfg.dirnamelen = snprintf(cfg.dirname, PATH_MAX,
2687 "%s/lib/modules/%s",
2688 root == NULL ? "" : root, cfg.kversion);
2689
2690 if (optind == argc)
2691 all = 1;
2692
2693 if (maybe_all) {
2694 if (out == stdout)
2695 goto done;
2696 /* ignore up-to-date errors (< 0) */
2697 if (depfile_up_to_date(cfg.dirname) == 1)
2698 goto done;
2699 all = 1;
2700 }
2701
2702 ctx = kmod_new(cfg.dirname, &null_kmod_config);
2703 if (ctx == NULL) {
2704 CRIT("kmod_new(\"%s\", {NULL}) failed: %m\n", cfg.dirname);
2705 goto cmdline_failed;
2706 }
2707
2708 log_setup_kmod_log(ctx, verbose);
2709
2710 err = depmod_init(&depmod, &cfg, ctx);
2711 if (err < 0) {
2712 CRIT("depmod_init: %s\n", strerror(-err));
2713 goto depmod_init_failed;
2714 }
2715 ctx = NULL; /* owned by depmod */
2716
2717 if (module_symvers != NULL) {
2718 err = depmod_load_symvers(&depmod, module_symvers);
2719 if (err < 0) {
2720 CRIT("could not load %s: %s\n", module_symvers,
2721 strerror(-err));
2722 goto cmdline_failed;
2723 }
2724 } else if (system_map != NULL) {
2725 err = depmod_load_system_map(&depmod, system_map);
2726 if (err < 0) {
2727 CRIT("could not load %s: %s\n", system_map,
2728 strerror(-err));
2729 goto cmdline_failed;
2730 }
2731 } else if (cfg.print_unknown) {
2732 WRN("-e needs -E or -F\n");
2733 cfg.print_unknown = 0;
2734 }
2735
2736 if (all) {
2737 err = cfg_load(&cfg, config_paths);
2738 if (err < 0) {
2739 CRIT("could not load configuration files\n");
2740 goto cmdline_modules_failed;
2741 }
2742 err = depmod_modules_search(&depmod);
2743 if (err < 0) {
2744 CRIT("could not search modules: %s\n", strerror(-err));
2745 goto cmdline_modules_failed;
2746 }
2747 } else {
2748 int i;
2749
2750 for (i = optind; i < argc; i++) {
2751 const char *path = argv[i];
2752 struct kmod_module *mod;
2753
2754 if (path[0] != '/') {
2755 CRIT("%s: not absolute path.\n", path);
2756 goto cmdline_modules_failed;
2757 }
2758
2759 err = kmod_module_new_from_path(depmod.ctx, path, &mod);
2760 if (err < 0) {
2761 CRIT("could not create module %s: %s\n",
2762 path, strerror(-err));
2763 goto cmdline_modules_failed;
2764 }
2765
2766 err = depmod_module_add(&depmod, mod);
2767 if (err < 0) {
2768 CRIT("could not add module %s: %s\n",
2769 path, strerror(-err));
2770 kmod_module_unref(mod);
2771 goto cmdline_modules_failed;
2772 }
2773 }
2774 }
2775
2776 err = depmod_modules_build_array(&depmod);
2777 if (err < 0) {
2778 CRIT("could not build module array: %s\n",
2779 strerror(-err));
2780 goto cmdline_modules_failed;
2781 }
2782
2783 depmod_modules_sort(&depmod);
2784 err = depmod_load(&depmod);
2785 if (err < 0)
2786 goto cmdline_modules_failed;
2787
2788 err = depmod_output(&depmod, out);
2789
2790 done:
2791 depmod_shutdown(&depmod);
2792 cfg_free(&cfg);
2793 if (root)
2794 free(root);
2795 if (config_paths)
2796 free(config_paths);
2797 return err >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
2798
2799 cmdline_modules_failed:
2800 depmod_shutdown(&depmod);
2801 depmod_init_failed:
2802 if (ctx != NULL)
2803 kmod_unref(ctx);
2804 cmdline_failed:
2805 cfg_free(&cfg);
2806 if (root)
2807 free(root);
2808 return EXIT_FAILURE;
2809 }
2810
2811 const struct kmod_cmd kmod_cmd_compat_depmod = {
2812 .name = "depmod",
2813 .cmd = do_depmod,
2814 .help = "compat depmod command",
2815 };
File src/tools/insmod.c added (mode: 100644) (index 0000000..fb9e061)
1 /*
2 * kmod-insmod - insert modules into linux kernel using libkmod.
3 *
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <errno.h>
21 #include <getopt.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <limits.h>
26 #include <syslog.h>
27
28 #include "config.h"
29
30 #include "libkmod.h"
31 #include "shared/macro.h"
32 #include "shared/util.h"
33 #define TOOLS_INSMOD_C
34 #include "kmod.h"
35 #undef TOOLS_INSMOD_C
36 #include "log.h"
37
38 static const char cmdopts_s[] = "psfVh";
39 static const struct option cmdopts[] = {
40 {"version", no_argument, 0, 'V'},
41 {"help", no_argument, 0, 'h'},
42 {NULL, 0, 0, 0}
43 };
44
45 static void help(void)
46 {
47 printf("Usage:\n"
48 "\t%s [options] filename [args]\n"
49 "Options:\n"
50 "\t-V, --version show version\n"
51 "\t-h, --help show this help\n",
52 program_invocation_short_name);
53 }
54
55 static const char *mod_strerror(int err)
56 {
57 switch (err) {
58 case ENOEXEC:
59 return "Invalid module format";
60 case ENOENT:
61 return "Unknown symbol in module";
62 case ESRCH:
63 return "Module has wrong symbol version";
64 case EINVAL:
65 return "Invalid parameters";
66 default:
67 return strerror(err);
68 }
69 }
70
71 static int do_insmod(int argc, char *argv[])
72 {
73 struct kmod_ctx *ctx;
74 struct kmod_module *mod;
75 const char *filename;
76 char *opts = NULL;
77 size_t optslen = 0;
78 int i, err;
79 const char *null_config = NULL;
80 unsigned int flags = 0;
81
82 for (;;) {
83 int c, idx = 0;
84 c = getopt_long(argc, argv, cmdopts_s, cmdopts, &idx);
85 if (c == -1)
86 break;
87 switch (c) {
88 case 'p':
89 case 's':
90 /* ignored, for compatibility only */
91 break;
92 case 'f':
93 flags |= KMOD_PROBE_FORCE_MODVERSION;
94 flags |= KMOD_PROBE_FORCE_VERMAGIC;
95 break;
96 case 'h':
97 help();
98 return EXIT_SUCCESS;
99 case 'V':
100 puts("kmod version " VERSION);
101 puts(KMOD_FEATURES);
102 return EXIT_SUCCESS;
103 case '?':
104 return EXIT_FAILURE;
105 default:
106 ERR("unexpected getopt_long() value '%c'.\n",
107 c);
108 return EXIT_FAILURE;
109 }
110 }
111
112 if (optind >= argc) {
113 ERR("missing filename.\n");
114 return EXIT_FAILURE;
115 }
116
117 filename = argv[optind];
118 if (streq(filename, "-")) {
119 ERR("this tool does not support loading from stdin!\n");
120 return EXIT_FAILURE;
121 }
122
123 for (i = optind + 1; i < argc; i++) {
124 size_t len = strlen(argv[i]);
125 void *tmp = realloc(opts, optslen + len + 2);
126 if (tmp == NULL) {
127 ERR("out of memory\n");
128 free(opts);
129 return EXIT_FAILURE;
130 }
131 opts = tmp;
132 if (optslen > 0) {
133 opts[optslen] = ' ';
134 optslen++;
135 }
136 memcpy(opts + optslen, argv[i], len);
137 optslen += len;
138 opts[optslen] = '\0';
139 }
140
141 ctx = kmod_new(NULL, &null_config);
142 if (!ctx) {
143 ERR("kmod_new() failed!\n");
144 free(opts);
145 return EXIT_FAILURE;
146 }
147
148 err = kmod_module_new_from_path(ctx, filename, &mod);
149 if (err < 0) {
150 ERR("could not load module %s: %s\n", filename,
151 strerror(-err));
152 goto end;
153 }
154
155 err = kmod_module_insert_module(mod, flags, opts);
156 if (err < 0) {
157 ERR("could not insert module %s: %s\n", filename,
158 mod_strerror(-err));
159 }
160 kmod_module_unref(mod);
161
162 end:
163 kmod_unref(ctx);
164 free(opts);
165 return err >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
166 }
167
168 const struct kmod_cmd kmod_cmd_compat_insmod = {
169 .name = "insmod",
170 .cmd = do_insmod,
171 .help = "compat insmod command",
172 };
File src/tools/kmod.c added (mode: 100644) (index 0000000..388c78f)
1 /*
2 * kmod - one tool to rule them all
3 *
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <errno.h>
21 #include <getopt.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <limits.h>
26 #include <libgen.h>
27
28 #include "config.h"
29
30 #include "libkmod.h"
31 #include "shared/macro.h"
32 #include "shared/util.h"
33 #define TOOLS_KMOD_C
34 #include "kmod.h"
35 #undef TOOLS_KMOD_C
36 #include "log.h"
37
38 static const char options_s[] = "+hV";
39 static const struct option options[] = {
40 { "help", no_argument, NULL, 'h' },
41 { "version", no_argument, NULL, 'V' },
42 {}
43 };
44
45 static const struct kmod_cmd kmod_cmd_help;
46
47 static const struct kmod_cmd *kmod_cmds[] = {
48 &kmod_cmd_help,
49 &kmod_cmd_list,
50 &kmod_cmd_static_nodes,
51
52 #ifdef ENABLE_EXPERIMENTAL
53 &kmod_cmd_insert,
54 &kmod_cmd_remove,
55 #endif
56 };
57
58 static const struct kmod_cmd *kmod_compat_cmds[] = {
59 &kmod_cmd_compat_lsmod,
60 &kmod_cmd_compat_rmmod,
61 &kmod_cmd_compat_insmod,
62 &kmod_cmd_compat_modinfo,
63 &kmod_cmd_compat_modprobe,
64 &kmod_cmd_compat_depmod,
65 };
66
67 static int kmod_help(int argc, char *argv[])
68 {
69 size_t i;
70 char *arg0_cpy = strdup(argv[0]);
71 if (!arg0_cpy)
72 return EXIT_FAILURE;
73
74 printf("kmod - Manage kernel modules: list, load, unload, etc\n"
75 "Usage:\n"
76 "\t%s [options] command [command_options]\n\n"
77 "Options:\n"
78 "\t-V, --version show version\n"
79 "\t-h, --help show this help\n\n"
80 "Commands:\n", basename(arg0_cpy));
81 free(arg0_cpy);
82
83 for (i = 0; i < ARRAY_SIZE(kmod_cmds); i++) {
84 if (kmod_cmds[i]->help != NULL) {
85 printf(" %-12s %s\n", kmod_cmds[i]->name,
86 kmod_cmds[i]->help);
87 }
88 }
89
90 puts("\nkmod also handles gracefully if called from following symlinks:");
91
92 for (i = 0; i < ARRAY_SIZE(kmod_compat_cmds); i++) {
93 if (kmod_compat_cmds[i]->help != NULL) {
94 printf(" %-12s %s\n", kmod_compat_cmds[i]->name,
95 kmod_compat_cmds[i]->help);
96 }
97 }
98
99 return EXIT_SUCCESS;
100 }
101
102 static const struct kmod_cmd kmod_cmd_help = {
103 .name = "help",
104 .cmd = kmod_help,
105 .help = "Show help message",
106 };
107
108 static int handle_kmod_commands(int argc, char *argv[])
109 {
110 const char *cmd;
111 int err = 0;
112 size_t i;
113
114 for (;;) {
115 int c;
116
117 c = getopt_long(argc, argv, options_s, options, NULL);
118 if (c == -1)
119 break;
120
121 switch (c) {
122 case 'h':
123 kmod_help(argc, argv);
124 return EXIT_SUCCESS;
125 case 'V':
126 puts("kmod version " VERSION);
127 puts(KMOD_FEATURES);
128 return EXIT_SUCCESS;
129 case '?':
130 return EXIT_FAILURE;
131 default:
132 fprintf(stderr, "Error: unexpected getopt_long() value '%c'.\n", c);
133 return EXIT_FAILURE;
134 }
135 }
136
137 if (optind >= argc) {
138 fputs("missing command\n", stderr);
139 goto fail;
140 }
141
142 cmd = argv[optind];
143
144 for (i = 0, err = -EINVAL; i < ARRAY_SIZE(kmod_cmds); i++) {
145 if (streq(kmod_cmds[i]->name, cmd)) {
146 err = kmod_cmds[i]->cmd(--argc, ++argv);
147 break;
148 }
149 }
150
151 if (err < 0) {
152 fprintf(stderr, "invalid command '%s'\n", cmd);
153 goto fail;
154 }
155
156 return err;
157
158 fail:
159 kmod_help(argc, argv);
160 return EXIT_FAILURE;
161 }
162
163
164 static int handle_kmod_compat_commands(int argc, char *argv[])
165 {
166 const char *cmd;
167 size_t i;
168 char *arg0_cpy = strdup(argv[0]);
169
170 if (!arg0_cpy)
171 return -ENOENT;
172
173 cmd = basename(arg0_cpy);
174
175 for (i = 0; i < ARRAY_SIZE(kmod_compat_cmds); i++) {
176 if (streq(kmod_compat_cmds[i]->name, cmd)) {
177 free(arg0_cpy);
178 return kmod_compat_cmds[i]->cmd(argc, argv);
179 }
180 }
181 free(arg0_cpy);
182 return -ENOENT;
183 }
184
185 int main(int argc, char *argv[])
186 {
187 int err;
188 char *argv0_cpy = strdup(argv[0]);
189
190 program_invocation_short_name = basename(argv0_cpy);
191
192 if (streq(program_invocation_short_name, "kmod"))
193 err = handle_kmod_commands(argc, argv);
194 else
195 err = handle_kmod_compat_commands(argc, argv);
196
197 return err;
198 }
File src/tools/kmod.h added (mode: 100644) (index 0000000..adac9cf)
1 #ifndef KMOD_H
2 #define KMOD_H
3 /*
4 * kmod - one tool to rule them all
5 *
6 * Copyright (C) 2011-2013 ProFUSION embedded systems
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22
23 #ifdef TOOLS_KMOD_C
24 #define EXTERN_KMOD
25 #else
26 #define EXTERN_KMOD extern
27 #endif
28
29 #ifdef TOOLS_LSMOD_C
30 #define EXTERN_LSMOD
31 #else
32 #define EXTERN_LSMOD extern
33 #endif
34
35 #ifdef TOOLS_RMMOD_C
36 #define EXTERN_RMMOD
37 #else
38 #define EXTERN_RMMOD extern
39 #endif
40
41 #ifdef TOOLS_INSMOD_C
42 #define EXTERN_INSMOD
43 #else
44 #define EXTERN_INSMOD extern
45 #endif
46
47 #ifdef TOOLS_MODINFO_C
48 #define EXTERN_MODINFO
49 #else
50 #define EXTERN_MODINFO extern
51 #endif
52
53 #ifdef TOOLS_MODPROBE_C
54 #define EXTERN_MODPROBE
55 #else
56 #define EXTERN_MODPROBE extern
57 #endif
58
59 #ifdef TOOLS_DEPMOD_C
60 #define EXTERN_DEPMOD
61 #else
62 #define EXTERN_DEPMOD extern
63 #endif
64
65 #ifdef TOOLS_STATIC_NODES_C
66 #define EXTERN_STATIC_NODES
67 #else
68 #define EXTERN_STATIC_NODES extern
69 #endif
70
71
72 EXTERN_KMOD char *program_invocation_short_name;
73
74 struct kmod_cmd {
75 const char *name;
76 int (*cmd)(int argc, char *argv[]);
77 const char *help;
78 };
79
80 EXTERN_LSMOD const struct kmod_cmd kmod_cmd_compat_lsmod;
81 EXTERN_RMMOD const struct kmod_cmd kmod_cmd_compat_rmmod;
82 EXTERN_INSMOD const struct kmod_cmd kmod_cmd_compat_insmod;
83 EXTERN_MODINFO const struct kmod_cmd kmod_cmd_compat_modinfo;
84 EXTERN_MODPROBE const struct kmod_cmd kmod_cmd_compat_modprobe;
85 EXTERN_DEPMOD const struct kmod_cmd kmod_cmd_compat_depmod;
86
87 EXTERN_LSMOD const struct kmod_cmd kmod_cmd_list;
88 EXTERN_STATIC_NODES const struct kmod_cmd kmod_cmd_static_nodes;
89
90 #undef EXTERN_KMOD
91 #undef EXTERN_LSMOD
92 #undef EXTERN_RMMOD
93 #undef EXTERN_INSMOD
94 #undef EXTERN_MODINFO
95 #undef EXTERN_MODPROBE
96 #undef EXTERN_DEPMOD
97 #undef EXTERN_STATIC_NODES
98 #endif
File src/tools/log.c added (mode: 100644) (index 0000000..ec6de54)
1 /*
2 * kmod - log infrastructure
3 *
4 * Copyright (C) 2012-2013 ProFUSION embedded systems
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <errno.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <syslog.h>
24 #include <stdbool.h>
25 #include <limits.h>
26
27 #include "config.h"
28
29 #include "libkmod.h"
30 #include "shared/macro.h"
31 #include "shared/util.h"
32 #include "kmod.h"
33 #define TOOLS_LOG_C
34 #include "log.h"
35 #undef TOOLS_LOG_C
36
37 #define PRIO_MAX_SIZE 32
38
39 static bool log_use_syslog;
40 static int log_priority = LOG_WARNING;
41
42 static const char *prio_to_str(char buf[static PRIO_MAX_SIZE], int prio)
43 {
44 const char *prioname;
45
46 switch (prio) {
47 case LOG_CRIT:
48 prioname = "FATAL";
49 break;
50 case LOG_ERR:
51 prioname = "ERROR";
52 break;
53 case LOG_WARNING:
54 prioname = "WARNING";
55 break;
56 case LOG_NOTICE:
57 prioname = "NOTICE";
58 break;
59 case LOG_INFO:
60 prioname = "INFO";
61 break;
62 case LOG_DEBUG:
63 prioname = "DEBUG";
64 break;
65 default:
66 snprintf(buf, PRIO_MAX_SIZE, "LOG-%03d", prio);
67 prioname = buf;
68 }
69
70 return prioname;
71 }
72
73 static void log_kmod(void *data, int priority, const char *file, int line,
74 const char *fn, const char *format, va_list args)
75 {
76 char buf[PRIO_MAX_SIZE];
77 const char *prioname;
78 char *str;
79
80 prioname = prio_to_str(buf, priority);
81
82 if (vasprintf(&str, format, args) < 0)
83 return;
84
85 if (log_use_syslog) {
86 #ifdef ENABLE_DEBUG
87 syslog(priority, "%s: %s:%d %s() %s", prioname, file, line,
88 fn, str);
89 #else
90 syslog(priority, "%s: %s", prioname, str);
91 #endif
92 } else {
93 #ifdef ENABLE_DEBUG
94 fprintf(stderr, "%s: %s: %s:%d %s() %s",
95 program_invocation_short_name, prioname, file, line,
96 fn, str);
97 #else
98 fprintf(stderr, "%s: %s: %s", program_invocation_short_name,
99 prioname, str);
100 #endif
101 }
102
103 free(str);
104 (void)data;
105 }
106 void log_open(bool use_syslog)
107 {
108 log_use_syslog = use_syslog;
109
110 if (log_use_syslog)
111 openlog(program_invocation_short_name, LOG_CONS, LOG_DAEMON);
112 }
113
114 void log_close(void)
115 {
116 if (log_use_syslog)
117 closelog();
118 }
119
120 void log_printf(int prio, const char *fmt, ...)
121 {
122 char buf[PRIO_MAX_SIZE];
123 const char *prioname;
124 char *msg;
125 va_list args;
126
127 if (prio > log_priority)
128 return;
129
130 va_start(args, fmt);
131 if (vasprintf(&msg, fmt, args) < 0)
132 msg = NULL;
133 va_end(args);
134 if (msg == NULL)
135 return;
136
137 prioname = prio_to_str(buf, prio);
138
139 if (log_use_syslog)
140 syslog(prio, "%s: %s", prioname, msg);
141 else
142 fprintf(stderr, "%s: %s: %s", program_invocation_short_name,
143 prioname, msg);
144 free(msg);
145
146 if (prio <= LOG_CRIT)
147 exit(EXIT_FAILURE);
148 }
149
150 void log_setup_kmod_log(struct kmod_ctx *ctx, int priority)
151 {
152 log_priority = priority;
153
154 kmod_set_log_priority(ctx, log_priority);
155 kmod_set_log_fn(ctx, log_kmod, NULL);
156 }
File src/tools/log.h added (mode: 100644) (index 0000000..ec9c2d8)
1 #ifndef TOOLS_LOG_H
2 #define TOOLS_LOG_H
3 /*
4 * kmod - log infrastructure
5 *
6 * Copyright (C) 2012-2013 ProFUSION embedded systems
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #ifdef TOOLS_LOG_C
23 #define EXTERN
24 #else
25 #define EXTERN extern
26 #endif
27
28 EXTERN void log_open(bool use_syslog);
29 EXTERN void log_close(void);
30 EXTERN void log_printf(int prio, const char *fmt, ...);
31 #define CRIT(...) log_printf(LOG_CRIT, __VA_ARGS__)
32 #define ERR(...) log_printf(LOG_ERR, __VA_ARGS__)
33 #define WRN(...) log_printf(LOG_WARNING, __VA_ARGS__)
34 #define INF(...) log_printf(LOG_INFO, __VA_ARGS__)
35 #define DBG(...) log_printf(LOG_DEBUG, __VA_ARGS__)
36
37 struct kmod_ctx;
38 EXTERN void log_setup_kmod_log(struct kmod_ctx *ctx, int priority);
39 #endif
File src/tools/lsmod.c added (mode: 100644) (index 0000000..5be23ba)
1 /*
2 * kmod-lsmod - list modules from linux kernel using libkmod.
3 *
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <errno.h>
21 #include <stddef.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include "config.h"
28
29 #include "libkmod.h"
30 #define TOOLS_LSMOD_C
31 #include "kmod.h"
32 #undef TOOLS_LSMOD_C
33
34 static int do_lsmod(int argc, char *argv[])
35 {
36 struct kmod_ctx *ctx;
37 const char *null_config = NULL;
38 struct kmod_list *list, *itr;
39 int err;
40
41 if (argc != 1) {
42 fprintf(stderr, "Usage: %s\n", argv[0]);
43 return EXIT_FAILURE;
44 }
45
46 ctx = kmod_new(NULL, &null_config);
47 if (ctx == NULL) {
48 fputs("Error: kmod_new() failed!\n", stderr);
49 return EXIT_FAILURE;
50 }
51
52 err = kmod_module_new_from_loaded(ctx, &list);
53 if (err < 0) {
54 fprintf(stderr, "Error: could not get list of modules: %s\n",
55 strerror(-err));
56 kmod_unref(ctx);
57 return EXIT_FAILURE;
58 }
59
60 puts("Module Size Used by");
61
62 kmod_list_foreach(itr, list) {
63 struct kmod_module *mod = kmod_module_get_module(itr);
64 const char *name = kmod_module_get_name(mod);
65 int use_count = kmod_module_get_refcnt(mod);
66 long size = kmod_module_get_size(mod);
67 struct kmod_list *holders, *hitr;
68 int first = 1;
69
70 printf("%-19s %8ld %d", name, size, use_count);
71 holders = kmod_module_get_holders(mod);
72 kmod_list_foreach(hitr, holders) {
73 struct kmod_module *hm = kmod_module_get_module(hitr);
74
75 if (!first) {
76 putchar(',');
77 } else {
78 putchar(' ');
79 first = 0;
80 }
81
82 fputs(kmod_module_get_name(hm), stdout);
83 kmod_module_unref(hm);
84 }
85 putchar('\n');
86 kmod_module_unref_list(holders);
87 kmod_module_unref(mod);
88 }
89 kmod_module_unref_list(list);
90 kmod_unref(ctx);
91
92 return EXIT_SUCCESS;
93 }
94
95 const struct kmod_cmd kmod_cmd_compat_lsmod = {
96 .name = "lsmod",
97 .cmd = do_lsmod,
98 .help = "compat lsmod command",
99 };
100
101 const struct kmod_cmd kmod_cmd_list = {
102 .name = "list",
103 .cmd = do_lsmod,
104 .help = "list currently loaded modules",
105 };
File src/tools/modinfo.c added (mode: 100644) (index 0000000..925f2e6)
1 /*
2 * kmod-modinfo - query kernel module information using libkmod.
3 *
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <errno.h>
21 #include <getopt.h>
22 #include <limits.h>
23 #include <stdbool.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <limits.h>
28 #include <syslog.h>
29 #include <sys/stat.h>
30 #include <sys/utsname.h>
31
32 #include "config.h"
33
34 #include "libkmod.h"
35 #include "shared/macro.h"
36 #include "shared/util.h"
37 #define TOOLS_MODINFO_C
38 #include "kmod.h"
39 #undef TOOLS_MODINFO_C
40 #include "log.h"
41
42 static char separator = '\n';
43 static const char *field = NULL;
44
45 struct param {
46 struct param *next;
47 const char *name;
48 const char *param;
49 const char *type;
50 int namelen;
51 int paramlen;
52 int typelen;
53 };
54
55 static struct param *add_param(const char *name, int namelen, const char *param, int paramlen, const char *type, int typelen, struct param **list)
56 {
57 struct param *it;
58
59 for (it = *list; it != NULL; it = it->next) {
60 if (it->namelen == namelen &&
61 memcmp(it->name, name, namelen) == 0)
62 break;
63 }
64
65 if (it == NULL) {
66 it = malloc(sizeof(struct param));
67 if (it == NULL)
68 return NULL;
69 it->next = *list;
70 *list = it;
71 it->name = name;
72 it->namelen = namelen;
73 it->param = NULL;
74 it->type = NULL;
75 it->paramlen = 0;
76 it->typelen = 0;
77 }
78
79 if (param != NULL) {
80 it->param = param;
81 it->paramlen = paramlen;
82 }
83
84 if (type != NULL) {
85 it->type = type;
86 it->typelen = typelen;
87 }
88
89 return it;
90 }
91
92 static int process_parm(const char *key, const char *value, struct param **params)
93 {
94 const char *name, *param, *type;
95 int namelen, paramlen, typelen;
96 struct param *it;
97 const char *colon = strchr(value, ':');
98 if (colon == NULL) {
99 ERR("Found invalid \"%s=%s\": missing ':'\n",
100 key, value);
101 return 0;
102 }
103
104 name = value;
105 namelen = colon - value;
106 if (streq(key, "parm")) {
107 param = colon + 1;
108 paramlen = strlen(param);
109 type = NULL;
110 typelen = 0;
111 } else {
112 param = NULL;
113 paramlen = 0;
114 type = colon + 1;
115 typelen = strlen(type);
116 }
117
118 it = add_param(name, namelen, param, paramlen, type, typelen, params);
119 if (it == NULL) {
120 ERR("Out of memory!\n");
121 return -ENOMEM;
122 }
123
124 return 0;
125 }
126
127 static int modinfo_params_do(const struct kmod_list *list)
128 {
129 const struct kmod_list *l;
130 struct param *params = NULL;
131 int err = 0;
132
133 kmod_list_foreach(l, list) {
134 const char *key = kmod_module_info_get_key(l);
135 const char *value = kmod_module_info_get_value(l);
136 if (!streq(key, "parm") && !streq(key, "parmtype"))
137 continue;
138
139 err = process_parm(key, value, &params);
140 if (err < 0)
141 goto end;
142 }
143
144 while (params != NULL) {
145 struct param *p = params;
146 params = p->next;
147
148 if (p->param == NULL)
149 printf("%.*s: (%.*s)%c",
150 p->namelen, p->name, p->typelen, p->type,
151 separator);
152 else if (p->type != NULL)
153 printf("%.*s:%.*s (%.*s)%c",
154 p->namelen, p->name,
155 p->paramlen, p->param,
156 p->typelen, p->type,
157 separator);
158 else
159 printf("%.*s:%.*s%c",
160 p->namelen, p->name,
161 p->paramlen, p->param,
162 separator);
163
164 free(p);
165 }
166
167 end:
168 while (params != NULL) {
169 void *tmp = params;
170 params = params->next;
171 free(tmp);
172 }
173
174 return err;
175 }
176
177 static int modinfo_do(struct kmod_module *mod)
178 {
179 struct kmod_list *l, *list = NULL;
180 struct param *params = NULL;
181 int err;
182
183 if (field != NULL && streq(field, "filename")) {
184 printf("%s%c", kmod_module_get_path(mod), separator);
185 return 0;
186 } else if (field == NULL) {
187 printf("%-16s%s%c", "filename:",
188 kmod_module_get_path(mod), separator);
189 }
190
191 err = kmod_module_get_info(mod, &list);
192 if (err < 0) {
193 ERR("could not get modinfo from '%s': %s\n",
194 kmod_module_get_name(mod), strerror(-err));
195 return err;
196 }
197
198 if (field != NULL && streq(field, "parm")) {
199 err = modinfo_params_do(list);
200 goto end;
201 }
202
203 kmod_list_foreach(l, list) {
204 const char *key = kmod_module_info_get_key(l);
205 const char *value = kmod_module_info_get_value(l);
206 int keylen;
207
208 if (field != NULL) {
209 if (!streq(field, key))
210 continue;
211 /* filtered output contains no key, just value */
212 printf("%s%c", value, separator);
213 continue;
214 }
215
216 if (streq(key, "parm") || streq(key, "parmtype")) {
217 err = process_parm(key, value, &params);
218 if (err < 0)
219 goto end;
220 continue;
221 }
222
223 if (separator == '\0') {
224 printf("%s=%s%c", key, value, separator);
225 continue;
226 }
227
228 keylen = strlen(key);
229 printf("%s:%-*s%s%c", key, 15 - keylen, "", value, separator);
230 }
231
232 if (field != NULL)
233 goto end;
234
235 while (params != NULL) {
236 struct param *p = params;
237 params = p->next;
238
239 if (p->param == NULL)
240 printf("%-16s%.*s:%.*s%c", "parm:",
241 p->namelen, p->name, p->typelen, p->type,
242 separator);
243 else if (p->type != NULL)
244 printf("%-16s%.*s:%.*s (%.*s)%c", "parm:",
245 p->namelen, p->name,
246 p->paramlen, p->param,
247 p->typelen, p->type,
248 separator);
249 else
250 printf("%-16s%.*s:%.*s%c",
251 "parm:",
252 p->namelen, p->name,
253 p->paramlen, p->param,
254 separator);
255
256 free(p);
257 }
258
259 end:
260 while (params != NULL) {
261 void *tmp = params;
262 params = params->next;
263 free(tmp);
264 }
265 kmod_module_info_free_list(list);
266
267 return err;
268 }
269
270 static int modinfo_path_do(struct kmod_ctx *ctx, const char *path)
271 {
272 struct kmod_module *mod;
273 int err = kmod_module_new_from_path(ctx, path, &mod);
274 if (err < 0) {
275 ERR("Module file %s not found.\n", path);
276 return err;
277 }
278 err = modinfo_do(mod);
279 kmod_module_unref(mod);
280 return err;
281 }
282
283 static int modinfo_alias_do(struct kmod_ctx *ctx, const char *alias)
284 {
285 struct kmod_list *l, *filtered, *list = NULL;
286 int err = kmod_module_new_from_lookup(ctx, alias, &list);
287 if (err < 0) {
288 ERR("Module alias %s not found.\n", alias);
289 return err;
290 }
291
292 if (list == NULL) {
293 ERR("Module %s not found.\n", alias);
294 return -ENOENT;
295 }
296
297 err = kmod_module_apply_filter(ctx, KMOD_FILTER_BUILTIN, list, &filtered);
298 kmod_module_unref_list(list);
299 if (err < 0) {
300 ERR("Failed to filter list: %m\n");
301 return err;
302 }
303
304 if (filtered == NULL) {
305 ERR("Module %s not found.\n", alias);
306 return -ENOENT;
307 }
308
309 kmod_list_foreach(l, filtered) {
310 struct kmod_module *mod = kmod_module_get_module(l);
311 int r = modinfo_do(mod);
312 kmod_module_unref(mod);
313 if (r < 0)
314 err = r;
315 }
316 kmod_module_unref_list(filtered);
317 return err;
318 }
319
320 static const char cmdopts_s[] = "adlpn0F:k:b:Vh";
321 static const struct option cmdopts[] = {
322 {"author", no_argument, 0, 'a'},
323 {"description", no_argument, 0, 'd'},
324 {"license", no_argument, 0, 'l'},
325 {"parameters", no_argument, 0, 'p'},
326 {"filename", no_argument, 0, 'n'},
327 {"null", no_argument, 0, '0'},
328 {"field", required_argument, 0, 'F'},
329 {"set-version", required_argument, 0, 'k'},
330 {"basedir", required_argument, 0, 'b'},
331 {"version", no_argument, 0, 'V'},
332 {"help", no_argument, 0, 'h'},
333 {NULL, 0, 0, 0}
334 };
335
336 static void help(void)
337 {
338 printf("Usage:\n"
339 "\t%s [options] filename [args]\n"
340 "Options:\n"
341 "\t-a, --author Print only 'author'\n"
342 "\t-d, --description Print only 'description'\n"
343 "\t-l, --license Print only 'license'\n"
344 "\t-p, --parameters Print only 'parm'\n"
345 "\t-n, --filename Print only 'filename'\n"
346 "\t-0, --null Use \\0 instead of \\n\n"
347 "\t-F, --field=FIELD Print only provided FIELD\n"
348 "\t-k, --set-version=VERSION Use VERSION instead of `uname -r`\n"
349 "\t-b, --basedir=DIR Use DIR as filesystem root for /lib/modules\n"
350 "\t-V, --version Show version\n"
351 "\t-h, --help Show this help\n",
352 program_invocation_short_name);
353 }
354
355 static bool is_module_filename(const char *name)
356 {
357 struct stat st;
358
359 if (stat(name, &st) == 0 && S_ISREG(st.st_mode) &&
360 path_ends_with_kmod_ext(name, strlen(name)))
361 return true;
362
363 return false;
364 }
365
366 static int do_modinfo(int argc, char *argv[])
367 {
368 struct kmod_ctx *ctx;
369 char dirname_buf[PATH_MAX];
370 const char *dirname = NULL;
371 const char *kversion = NULL;
372 const char *root = NULL;
373 const char *null_config = NULL;
374 int i, err;
375
376 for (;;) {
377 int c, idx = 0;
378 c = getopt_long(argc, argv, cmdopts_s, cmdopts, &idx);
379 if (c == -1)
380 break;
381 switch (c) {
382 case 'a':
383 field = "author";
384 break;
385 case 'd':
386 field = "description";
387 break;
388 case 'l':
389 field = "license";
390 break;
391 case 'p':
392 field = "parm";
393 break;
394 case 'n':
395 field = "filename";
396 break;
397 case '0':
398 separator = '\0';
399 break;
400 case 'F':
401 field = optarg;
402 break;
403 case 'k':
404 kversion = optarg;
405 break;
406 case 'b':
407 root = optarg;
408 break;
409 case 'h':
410 help();
411 return EXIT_SUCCESS;
412 case 'V':
413 puts("kmod version " VERSION);
414 puts(KMOD_FEATURES);
415 return EXIT_SUCCESS;
416 case '?':
417 return EXIT_FAILURE;
418 default:
419 ERR("unexpected getopt_long() value '%c'.\n", c);
420 return EXIT_FAILURE;
421 }
422 }
423
424 if (optind >= argc) {
425 ERR("missing module or filename.\n");
426 return EXIT_FAILURE;
427 }
428
429 if (root != NULL || kversion != NULL) {
430 struct utsname u;
431 if (root == NULL)
432 root = "";
433 if (kversion == NULL) {
434 if (uname(&u) < 0) {
435 ERR("uname() failed: %m\n");
436 return EXIT_FAILURE;
437 }
438 kversion = u.release;
439 }
440 snprintf(dirname_buf, sizeof(dirname_buf), "%s/lib/modules/%s",
441 root, kversion);
442 dirname = dirname_buf;
443 }
444
445 ctx = kmod_new(dirname, &null_config);
446 if (!ctx) {
447 ERR("kmod_new() failed!\n");
448 return EXIT_FAILURE;
449 }
450
451 err = 0;
452 for (i = optind; i < argc; i++) {
453 const char *name = argv[i];
454 int r;
455
456 if (is_module_filename(name))
457 r = modinfo_path_do(ctx, name);
458 else
459 r = modinfo_alias_do(ctx, name);
460
461 if (r < 0)
462 err = r;
463 }
464
465 kmod_unref(ctx);
466 return err >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
467 }
468
469 const struct kmod_cmd kmod_cmd_compat_modinfo = {
470 .name = "modinfo",
471 .cmd = do_modinfo,
472 .help = "compat modinfo command",
473 };
File src/tools/modprobe.c added (mode: 100644) (index 0000000..34eae75)
1 /*
2 * kmod-modprobe - manage linux kernel modules using libkmod.
3 *
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <assert.h>
21 #include <errno.h>
22 #include <getopt.h>
23 #include <limits.h>
24 #include <stdbool.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <limits.h>
30 #include <syslog.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
33 #include <sys/utsname.h>
34 #include <sys/wait.h>
35
36 #include "config.h"
37
38 #include "libkmod.h"
39 #include "shared/array.h"
40 #include "shared/macro.h"
41 #include "shared/util.h"
42 #define TOOLS_MODPROBE_C
43 #include "kmod.h"
44 #undef TOOLS_MODPROBE_C
45 #include "log.h"
46
47 static int log_priority = LOG_CRIT;
48 static int use_syslog = 0;
49 #define LOG(...) log_printf(log_priority, __VA_ARGS__)
50
51 #define DEFAULT_VERBOSE LOG_WARNING
52 static int verbose = DEFAULT_VERBOSE;
53 static int do_show = 0;
54 static int dry_run = 0;
55 static int ignore_loaded = 0;
56 static int lookup_only = 0;
57 static int first_time = 0;
58 static int ignore_commands = 0;
59 static int use_blacklist = 0;
60 static int force = 0;
61 static int strip_modversion = 0;
62 static int strip_vermagic = 0;
63 static int remove_dependencies = 0;
64 static int quiet_inuse = 0;
65
66 static const char cmdopts_s[] = "arRibfDcnC:d:S:sqvVh";
67 static const struct option cmdopts[] = {
68 {"all", no_argument, 0, 'a'},
69 {"remove", no_argument, 0, 'r'},
70 {"remove-dependencies", no_argument, 0, 5},
71 {"resolve-alias", no_argument, 0, 'R'},
72 {"first-time", no_argument, 0, 3},
73 {"ignore-install", no_argument, 0, 'i'},
74 {"ignore-remove", no_argument, 0, 'i'},
75 {"use-blacklist", no_argument, 0, 'b'},
76 {"force", no_argument, 0, 'f'},
77 {"force-modversion", no_argument, 0, 2},
78 {"force-vermagic", no_argument, 0, 1},
79
80 {"show-depends", no_argument, 0, 'D'},
81 {"showconfig", no_argument, 0, 'c'},
82 {"show-config", no_argument, 0, 'c'},
83 {"show-modversions", no_argument, 0, 4},
84 {"dump-modversions", no_argument, 0, 4},
85
86 {"dry-run", no_argument, 0, 'n'},
87 {"show", no_argument, 0, 'n'},
88
89 {"config", required_argument, 0, 'C'},
90 {"dirname", required_argument, 0, 'd'},
91 {"set-version", required_argument, 0, 'S'},
92
93 {"syslog", no_argument, 0, 's'},
94 {"quiet", no_argument, 0, 'q'},
95 {"verbose", no_argument, 0, 'v'},
96 {"version", no_argument, 0, 'V'},
97 {"help", no_argument, 0, 'h'},
98 {NULL, 0, 0, 0}
99 };
100
101 static void help(void)
102 {
103 printf("Usage:\n"
104 "\t%s [options] [-i] [-b] modulename\n"
105 "\t%s [options] -a [-i] [-b] modulename [modulename...]\n"
106 "\t%s [options] -r [-i] modulename\n"
107 "\t%s [options] -r -a [-i] modulename [modulename...]\n"
108 "\t%s [options] -c\n"
109 "\t%s [options] --dump-modversions filename\n"
110 "Management Options:\n"
111 "\t-a, --all Consider every non-argument to\n"
112 "\t be a module name to be inserted\n"
113 "\t or removed (-r)\n"
114 "\t-r, --remove Remove modules instead of inserting\n"
115 "\t --remove-dependencies Also remove modules depending on it\n"
116 "\t-R, --resolve-alias Only lookup and print alias and exit\n"
117 "\t --first-time Fail if module already inserted or removed\n"
118 "\t-i, --ignore-install Ignore install commands\n"
119 "\t-i, --ignore-remove Ignore remove commands\n"
120 "\t-b, --use-blacklist Apply blacklist to resolved alias.\n"
121 "\t-f, --force Force module insertion or removal.\n"
122 "\t implies --force-modversions and\n"
123 "\t --force-vermagic\n"
124 "\t --force-modversion Ignore module's version\n"
125 "\t --force-vermagic Ignore module's version magic\n"
126 "\n"
127 "Query Options:\n"
128 "\t-D, --show-depends Only print module dependencies and exit\n"
129 "\t-c, --showconfig Print out known configuration and exit\n"
130 "\t-c, --show-config Same as --showconfig\n"
131 "\t --show-modversions Dump module symbol version and exit\n"
132 "\t --dump-modversions Same as --show-modversions\n"
133 "\n"
134 "General Options:\n"
135 "\t-n, --dry-run Do not execute operations, just print out\n"
136 "\t-n, --show Same as --dry-run\n"
137
138 "\t-C, --config=FILE Use FILE instead of default search paths\n"
139 "\t-d, --dirname=DIR Use DIR as filesystem root for /lib/modules\n"
140 "\t-S, --set-version=VERSION Use VERSION instead of `uname -r`\n"
141
142 "\t-s, --syslog print to syslog, not stderr\n"
143 "\t-q, --quiet disable messages\n"
144 "\t-v, --verbose enables more messages\n"
145 "\t-V, --version show version\n"
146 "\t-h, --help show this help\n",
147 program_invocation_short_name, program_invocation_short_name,
148 program_invocation_short_name, program_invocation_short_name,
149 program_invocation_short_name, program_invocation_short_name);
150 }
151
152 static inline void _show(const char *fmt, ...)
153 {
154 va_list args;
155
156 if (!do_show && verbose <= DEFAULT_VERBOSE)
157 return;
158
159 va_start(args, fmt);
160 vfprintf(stdout, fmt, args);
161 fflush(stdout);
162 va_end(args);
163 }
164 #define SHOW(...) _show(__VA_ARGS__)
165
166 static int show_config(struct kmod_ctx *ctx)
167 {
168 struct config_iterators {
169 const char *name;
170 struct kmod_config_iter *(*get_iter)(const struct kmod_ctx *ctx);
171 } ci[] = {
172 { "blacklist", kmod_config_get_blacklists },
173 { "install", kmod_config_get_install_commands },
174 { "remove", kmod_config_get_remove_commands },
175 { "alias", kmod_config_get_aliases },
176 { "options", kmod_config_get_options },
177 { "softdep", kmod_config_get_softdeps },
178 };
179 size_t i;
180
181 for (i = 0; i < ARRAY_SIZE(ci); i++) {
182 struct kmod_config_iter *iter = ci[i].get_iter(ctx);
183
184 if (iter == NULL)
185 continue;
186
187 while (kmod_config_iter_next(iter)) {
188 const char *val;
189
190 printf("%s %s", ci[i].name,
191 kmod_config_iter_get_key(iter));
192 val = kmod_config_iter_get_value(iter);
193 if (val != NULL) {
194 putchar(' ');
195 puts(val);
196 } else
197 putchar('\n');
198 }
199
200 kmod_config_iter_free_iter(iter);
201 }
202
203 puts("\n# End of configuration files. Dumping indexes now:\n");
204 fflush(stdout);
205
206 kmod_dump_index(ctx, KMOD_INDEX_MODULES_ALIAS, STDOUT_FILENO);
207 kmod_dump_index(ctx, KMOD_INDEX_MODULES_SYMBOL, STDOUT_FILENO);
208
209 return 0;
210 }
211
212 static int show_modversions(struct kmod_ctx *ctx, const char *filename)
213 {
214 struct kmod_list *l, *list = NULL;
215 struct kmod_module *mod;
216 int err = kmod_module_new_from_path(ctx, filename, &mod);
217 if (err < 0) {
218 LOG("Module %s not found.\n", filename);
219 return err;
220 }
221
222 err = kmod_module_get_versions(mod, &list);
223 if (err < 0) {
224 LOG("could not get modversions of %s: %s\n",
225 filename, strerror(-err));
226 kmod_module_unref(mod);
227 return err;
228 }
229
230 kmod_list_foreach(l, list) {
231 const char *symbol = kmod_module_version_get_symbol(l);
232 uint64_t crc = kmod_module_version_get_crc(l);
233 printf("0x%08"PRIx64"\t%s\n", crc, symbol);
234 }
235 kmod_module_versions_free_list(list);
236 kmod_module_unref(mod);
237 return 0;
238 }
239
240 static int command_do(struct kmod_module *module, const char *type,
241 const char *command, const char *cmdline_opts)
242 {
243 const char *modname = kmod_module_get_name(module);
244 char *p, *cmd = NULL;
245 size_t cmdlen, cmdline_opts_len, varlen;
246 int ret = 0;
247
248 if (cmdline_opts == NULL)
249 cmdline_opts = "";
250 cmdline_opts_len = strlen(cmdline_opts);
251
252 cmd = strdup(command);
253 if (cmd == NULL)
254 return -ENOMEM;
255 cmdlen = strlen(cmd);
256 varlen = sizeof("$CMDLINE_OPTS") - 1;
257 while ((p = strstr(cmd, "$CMDLINE_OPTS")) != NULL) {
258 size_t prefixlen = p - cmd;
259 size_t suffixlen = cmdlen - prefixlen - varlen;
260 size_t slen = cmdlen - varlen + cmdline_opts_len;
261 char *suffix = p + varlen;
262 char *s = malloc(slen + 1);
263 if (s == NULL) {
264 free(cmd);
265 return -ENOMEM;
266 }
267 memcpy(s, cmd, p - cmd);
268 memcpy(s + prefixlen, cmdline_opts, cmdline_opts_len);
269 memcpy(s + prefixlen + cmdline_opts_len, suffix, suffixlen);
270 s[slen] = '\0';
271
272 free(cmd);
273 cmd = s;
274 cmdlen = slen;
275 }
276
277 SHOW("%s %s\n", type, cmd);
278 if (dry_run)
279 goto end;
280
281 setenv("MODPROBE_MODULE", modname, 1);
282 ret = system(cmd);
283 unsetenv("MODPROBE_MODULE");
284 if (ret == -1 || WEXITSTATUS(ret)) {
285 LOG("Error running %s command for %s\n", type, modname);
286 if (ret != -1)
287 ret = -WEXITSTATUS(ret);
288 }
289
290 end:
291 free(cmd);
292 return ret;
293 }
294
295 static int rmmod_do_remove_module(struct kmod_module *mod)
296 {
297 const char *modname = kmod_module_get_name(mod);
298 struct kmod_list *deps, *itr;
299 int flags = 0, err;
300
301 SHOW("rmmod %s\n", kmod_module_get_name(mod));
302
303 if (dry_run)
304 return 0;
305
306 if (force)
307 flags |= KMOD_REMOVE_FORCE;
308
309 err = kmod_module_remove_module(mod, flags);
310 if (err == -EEXIST) {
311 if (!first_time)
312 err = 0;
313 else
314 LOG("Module %s is not in kernel.\n", modname);
315 }
316
317 deps = kmod_module_get_dependencies(mod);
318 if (deps != NULL) {
319 kmod_list_foreach(itr, deps) {
320 struct kmod_module *dep = kmod_module_get_module(itr);
321 if (kmod_module_get_refcnt(dep) == 0)
322 rmmod_do_remove_module(dep);
323 kmod_module_unref(dep);
324 }
325 kmod_module_unref_list(deps);
326 }
327
328 return err;
329 }
330
331 static int rmmod_do_module(struct kmod_module *mod, bool do_dependencies);
332
333 static int rmmod_do_deps_list(struct kmod_list *list, bool stop_on_errors)
334 {
335 struct kmod_list *l;
336
337 kmod_list_foreach_reverse(l, list) {
338 struct kmod_module *m = kmod_module_get_module(l);
339 int r = rmmod_do_module(m, false);
340 kmod_module_unref(m);
341
342 if (r < 0 && stop_on_errors)
343 return r;
344 }
345
346 return 0;
347 }
348
349 static int rmmod_do_module(struct kmod_module *mod, bool do_dependencies)
350 {
351 const char *modname = kmod_module_get_name(mod);
352 struct kmod_list *pre = NULL, *post = NULL;
353 const char *cmd = NULL;
354 int err;
355
356 if (!ignore_commands) {
357 err = kmod_module_get_softdeps(mod, &pre, &post);
358 if (err < 0) {
359 WRN("could not get softdeps of '%s': %s\n",
360 modname, strerror(-err));
361 return err;
362 }
363
364 cmd = kmod_module_get_remove_commands(mod);
365 }
366
367 if (cmd == NULL && !ignore_loaded) {
368 int state = kmod_module_get_initstate(mod);
369
370 if (state < 0) {
371 if (first_time) {
372 LOG("Module %s is not in kernel.\n", modname);
373 err = -ENOENT;
374 } else {
375 err = 0;
376 }
377 goto error;
378 } else if (state == KMOD_MODULE_BUILTIN) {
379 LOG("Module %s is builtin.\n", modname);
380 err = -ENOENT;
381 goto error;
382 }
383 }
384
385 rmmod_do_deps_list(post, false);
386
387 if (do_dependencies && remove_dependencies) {
388 struct kmod_list *deps = kmod_module_get_dependencies(mod);
389
390 err = rmmod_do_deps_list(deps, true);
391 if (err < 0)
392 goto error;
393 }
394
395 if (!ignore_loaded && !cmd) {
396 int usage = kmod_module_get_refcnt(mod);
397
398 if (usage > 0) {
399 if (!quiet_inuse)
400 LOG("Module %s is in use.\n", modname);
401
402 err = -EBUSY;
403 goto error;
404 }
405 }
406
407 if (cmd == NULL)
408 err = rmmod_do_remove_module(mod);
409 else
410 err = command_do(mod, "remove", cmd, NULL);
411
412 if (err < 0)
413 goto error;
414
415 rmmod_do_deps_list(pre, false);
416
417 error:
418 kmod_module_unref_list(pre);
419 kmod_module_unref_list(post);
420
421 return err;
422 }
423
424 static int rmmod(struct kmod_ctx *ctx, const char *alias)
425 {
426 struct kmod_list *l, *list = NULL;
427 int err;
428
429 err = kmod_module_new_from_lookup(ctx, alias, &list);
430 if (err < 0)
431 return err;
432
433 if (list == NULL) {
434 LOG("Module %s not found.\n", alias);
435 err = -ENOENT;
436 }
437
438 kmod_list_foreach(l, list) {
439 struct kmod_module *mod = kmod_module_get_module(l);
440 err = rmmod_do_module(mod, true);
441 kmod_module_unref(mod);
442 if (err < 0)
443 break;
444 }
445
446 kmod_module_unref_list(list);
447 return err;
448 }
449
450 static int rmmod_all(struct kmod_ctx *ctx, char **args, int nargs)
451 {
452 int i, err = 0;
453
454 for (i = 0; i < nargs; i++) {
455 int r = rmmod(ctx, args[i]);
456 if (r < 0)
457 err = r;
458 }
459
460 return err;
461 }
462
463 static void print_action(struct kmod_module *m, bool install,
464 const char *options)
465 {
466 const char *path;
467
468 if (install) {
469 printf("install %s %s\n", kmod_module_get_install_commands(m),
470 options);
471 return;
472 }
473
474 path = kmod_module_get_path(m);
475
476 if (path == NULL) {
477 /*
478 * Either a builtin module, or an alias, print only for
479 * builtin
480 */
481 if (kmod_module_get_initstate(m) == KMOD_MODULE_BUILTIN)
482 printf("builtin %s\n", kmod_module_get_name(m));
483 } else
484 printf("insmod %s %s\n", kmod_module_get_path(m), options);
485 }
486
487 static int insmod(struct kmod_ctx *ctx, const char *alias,
488 const char *extra_options)
489 {
490 struct kmod_list *l, *list = NULL;
491 int err, flags = 0;
492
493 void (*show)(struct kmod_module *m, bool install,
494 const char *options) = NULL;
495
496 err = kmod_module_new_from_lookup(ctx, alias, &list);
497
498 if (list == NULL || err < 0) {
499 LOG("Module %s not found in directory %s\n", alias,
500 ctx ? kmod_get_dirname(ctx) : "(missing)");
501 return -ENOENT;
502 }
503
504 if (strip_modversion || force)
505 flags |= KMOD_PROBE_FORCE_MODVERSION;
506 if (strip_vermagic || force)
507 flags |= KMOD_PROBE_FORCE_VERMAGIC;
508 if (ignore_commands)
509 flags |= KMOD_PROBE_IGNORE_COMMAND;
510 if (ignore_loaded)
511 flags |= KMOD_PROBE_IGNORE_LOADED;
512 if (dry_run)
513 flags |= KMOD_PROBE_DRY_RUN;
514 if (do_show || verbose > DEFAULT_VERBOSE)
515 show = &print_action;
516
517 flags |= KMOD_PROBE_APPLY_BLACKLIST_ALIAS_ONLY;
518
519 if (use_blacklist)
520 flags |= KMOD_PROBE_APPLY_BLACKLIST;
521 if (first_time)
522 flags |= KMOD_PROBE_FAIL_ON_LOADED;
523
524 kmod_list_foreach(l, list) {
525 struct kmod_module *mod = kmod_module_get_module(l);
526
527 if (lookup_only)
528 printf("%s\n", kmod_module_get_name(mod));
529 else {
530 err = kmod_module_probe_insert_module(mod, flags,
531 extra_options, NULL, NULL, show);
532 }
533
534 if (err >= 0)
535 /* ignore flag return values such as a mod being blacklisted */
536 err = 0;
537 else {
538 switch (err) {
539 case -EEXIST:
540 ERR("could not insert '%s': Module already in kernel\n",
541 kmod_module_get_name(mod));
542 break;
543 case -ENOENT:
544 ERR("could not insert '%s': Unknown symbol in module, "
545 "or unknown parameter (see dmesg)\n",
546 kmod_module_get_name(mod));
547 break;
548 default:
549 ERR("could not insert '%s': %s\n",
550 kmod_module_get_name(mod),
551 strerror(-err));
552 break;
553 }
554 }
555
556 kmod_module_unref(mod);
557 }
558
559 kmod_module_unref_list(list);
560 return err;
561 }
562
563 static int insmod_all(struct kmod_ctx *ctx, char **args, int nargs)
564 {
565 int i, err = 0;
566
567 for (i = 0; i < nargs; i++) {
568 int r = insmod(ctx, args[i], NULL);
569 if (r < 0)
570 err = r;
571 }
572
573 return err;
574 }
575
576 static void env_modprobe_options_append(const char *value)
577 {
578 const char *old = getenv("MODPROBE_OPTIONS");
579 char *env;
580
581 if (old == NULL) {
582 setenv("MODPROBE_OPTIONS", value, 1);
583 return;
584 }
585
586 if (asprintf(&env, "%s %s", old, value) < 0) {
587 ERR("could not append value to $MODPROBE_OPTIONS\n");
588 return;
589 }
590
591 if (setenv("MODPROBE_OPTIONS", env, 1) < 0)
592 ERR("could not setenv(MODPROBE_OPTIONS, \"%s\")\n", env);
593 free(env);
594 }
595
596 static int options_from_array(char **args, int nargs, char **output)
597 {
598 char *opts = NULL;
599 size_t optslen = 0;
600 int i, err = 0;
601
602 for (i = 1; i < nargs; i++) {
603 size_t len = strlen(args[i]);
604 size_t qlen = 0;
605 const char *value;
606 void *tmp;
607
608 value = strchr(args[i], '=');
609 if (value) {
610 value++;
611 if (*value != '"' && *value != '\'') {
612 if (strchr(value, ' '))
613 qlen = 2;
614 }
615 }
616
617 tmp = realloc(opts, optslen + len + qlen + 2);
618 if (!tmp) {
619 err = -errno;
620 free(opts);
621 opts = NULL;
622 ERR("could not gather module options: out-of-memory\n");
623 break;
624 }
625 opts = tmp;
626 if (optslen > 0) {
627 opts[optslen] = ' ';
628 optslen++;
629 }
630 if (qlen == 0) {
631 memcpy(opts + optslen, args[i], len + 1);
632 optslen += len;
633 } else {
634 size_t keylen = value - args[i];
635 size_t valuelen = len - keylen;
636 memcpy(opts + optslen, args[i], keylen);
637 optslen += keylen;
638 opts[optslen] = '"';
639 optslen++;
640 memcpy(opts + optslen, value, valuelen);
641 optslen += valuelen;
642 opts[optslen] = '"';
643 optslen++;
644 opts[optslen] = '\0';
645 }
646 }
647
648 *output = opts;
649 return err;
650 }
651
652 static char **prepend_options_from_env(int *p_argc, char **orig_argv)
653 {
654 const char *p, *env = getenv("MODPROBE_OPTIONS");
655 char **new_argv, *str_start, *str_end, *str, *s, *quote;
656 int i, argc = *p_argc;
657 size_t envlen, space_count = 0;
658
659 if (env == NULL)
660 return orig_argv;
661
662 for (p = env; *p != '\0'; p++) {
663 if (*p == ' ')
664 space_count++;
665 }
666
667 envlen = p - env;
668 new_argv = malloc(sizeof(char *) * (argc + space_count + 3 + envlen));
669 if (new_argv == NULL)
670 return NULL;
671
672 new_argv[0] = orig_argv[0];
673 str_start = str = (char *) (new_argv + argc + space_count + 3);
674 memcpy(str, env, envlen + 1);
675
676 str_end = str_start + envlen;
677
678 quote = NULL;
679 for (i = 1, s = str; *s != '\0'; s++) {
680 if (quote == NULL) {
681 if (*s == ' ') {
682 new_argv[i] = str;
683 i++;
684 *s = '\0';
685 str = s + 1;
686 } else if (*s == '"' || *s == '\'')
687 quote = s;
688 } else {
689 if (*s == *quote) {
690 if (quote == str) {
691 new_argv[i] = str + 1;
692 i++;
693 *s = '\0';
694 str = s + 1;
695 } else {
696 char *it;
697 for (it = quote; it < s - 1; it++)
698 it[0] = it[1];
699 for (it = s - 1; it < str_end - 2; it++)
700 it[0] = it[2];
701 str_end -= 2;
702 *str_end = '\0';
703 s -= 2;
704 }
705 quote = NULL;
706 }
707 }
708 }
709 if (str < s) {
710 new_argv[i] = str;
711 i++;
712 }
713
714 memcpy(new_argv + i, orig_argv + 1, sizeof(char *) * (argc - 1));
715 new_argv[i + argc] = NULL;
716 *p_argc = i + argc - 1;
717
718 return new_argv;
719 }
720
721 static int do_modprobe(int argc, char **orig_argv)
722 {
723 struct kmod_ctx *ctx;
724 char **args = NULL, **argv;
725 const char **config_paths = NULL;
726 int nargs = 0, n_config_paths = 0;
727 char dirname_buf[PATH_MAX];
728 const char *dirname = NULL;
729 const char *root = NULL;
730 const char *kversion = NULL;
731 int use_all = 0;
732 int do_remove = 0;
733 int do_show_config = 0;
734 int do_show_modversions = 0;
735 int err;
736
737 argv = prepend_options_from_env(&argc, orig_argv);
738 if (argv == NULL) {
739 ERR("Could not prepend options from command line\n");
740 return EXIT_FAILURE;
741 }
742
743 for (;;) {
744 int c, idx = 0;
745 c = getopt_long(argc, argv, cmdopts_s, cmdopts, &idx);
746 if (c == -1)
747 break;
748 switch (c) {
749 case 'a':
750 log_priority = LOG_WARNING;
751 use_all = 1;
752 break;
753 case 'r':
754 do_remove = 1;
755 break;
756 case 5:
757 remove_dependencies = 1;
758 break;
759 case 'R':
760 lookup_only = 1;
761 break;
762 case 3:
763 first_time = 1;
764 break;
765 case 'i':
766 ignore_commands = 1;
767 break;
768 case 'b':
769 use_blacklist = 1;
770 break;
771 case 'f':
772 force = 1;
773 break;
774 case 2:
775 strip_modversion = 1;
776 break;
777 case 1:
778 strip_vermagic = 1;
779 break;
780 case 'D':
781 ignore_loaded = 1;
782 dry_run = 1;
783 do_show = 1;
784 break;
785 case 'c':
786 do_show_config = 1;
787 break;
788 case 4:
789 do_show_modversions = 1;
790 break;
791 case 'n':
792 dry_run = 1;
793 break;
794 case 'C': {
795 size_t bytes = sizeof(char *) * (n_config_paths + 2);
796 void *tmp = realloc(config_paths, bytes);
797 if (!tmp) {
798 ERR("out-of-memory\n");
799 err = -1;
800 goto done;
801 }
802 config_paths = tmp;
803 config_paths[n_config_paths] = optarg;
804 n_config_paths++;
805 config_paths[n_config_paths] = NULL;
806
807 env_modprobe_options_append("-C");
808 env_modprobe_options_append(optarg);
809 break;
810 }
811 case 'd':
812 root = optarg;
813 break;
814 case 'S':
815 kversion = optarg;
816 break;
817 case 's':
818 env_modprobe_options_append("-s");
819 use_syslog = 1;
820 break;
821 case 'q':
822 env_modprobe_options_append("-q");
823 verbose = LOG_EMERG;
824 break;
825 case 'v':
826 env_modprobe_options_append("-v");
827 verbose++;
828 break;
829 case 'V':
830 puts("kmod version " VERSION);
831 puts(KMOD_FEATURES);
832 err = 0;
833 goto done;
834 case 'h':
835 help();
836 err = 0;
837 goto done;
838 case '?':
839 err = -1;
840 goto done;
841 default:
842 ERR("unexpected getopt_long() value '%c'.\n", c);
843 err = -1;
844 goto done;
845 }
846 }
847
848 args = argv + optind;
849 nargs = argc - optind;
850
851 log_open(use_syslog);
852
853 if (!do_show_config) {
854 if (nargs == 0) {
855 ERR("missing parameters. See -h.\n");
856 err = -1;
857 goto done;
858 }
859 }
860
861 if (root != NULL || kversion != NULL) {
862 struct utsname u;
863 if (root == NULL)
864 root = "";
865 if (kversion == NULL) {
866 if (uname(&u) < 0) {
867 ERR("uname() failed: %m\n");
868 err = -1;
869 goto done;
870 }
871 kversion = u.release;
872 }
873 snprintf(dirname_buf, sizeof(dirname_buf),
874 "%s/lib/modules/%s", root,
875 kversion);
876 dirname = dirname_buf;
877 }
878
879 ctx = kmod_new(dirname, config_paths);
880 if (!ctx) {
881 ERR("kmod_new() failed!\n");
882 err = -1;
883 goto done;
884 }
885
886 log_setup_kmod_log(ctx, verbose);
887
888 kmod_load_resources(ctx);
889
890 if (do_show_config)
891 err = show_config(ctx);
892 else if (do_show_modversions)
893 err = show_modversions(ctx, args[0]);
894 else if (do_remove)
895 err = rmmod_all(ctx, args, nargs);
896 else if (use_all)
897 err = insmod_all(ctx, args, nargs);
898 else {
899 char *opts;
900 err = options_from_array(args, nargs, &opts);
901 if (err == 0) {
902 err = insmod(ctx, args[0], opts);
903 free(opts);
904 }
905 }
906
907 kmod_unref(ctx);
908
909 done:
910 log_close();
911
912 if (argv != orig_argv)
913 free(argv);
914
915 free(config_paths);
916
917 return err >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
918 }
919
920 const struct kmod_cmd kmod_cmd_compat_modprobe = {
921 .name = "modprobe",
922 .cmd = do_modprobe,
923 .help = "compat modprobe command",
924 };
File src/tools/rmmod.c added (mode: 100644) (index 0000000..35e44e4)
1 /*
2 * kmod-rmmod - remove modules from linux kernel using libkmod.
3 *
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <errno.h>
21 #include <getopt.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <syslog.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29
30 #include "config.h"
31
32 #include "libkmod.h"
33 #include "shared/macro.h"
34 #define TOOLS_RMMOD_C
35 #include "kmod.h"
36 #undef TOOLS_RMMOD_C
37 #include "log.h"
38
39 #define DEFAULT_VERBOSE LOG_ERR
40 static int verbose = DEFAULT_VERBOSE;
41 static int use_syslog;
42
43 static const char cmdopts_s[] = "fsvVwh";
44 static const struct option cmdopts[] = {
45 {"force", no_argument, 0, 'f'},
46 {"syslog", no_argument, 0, 's'},
47 {"verbose", no_argument, 0, 'v'},
48 {"version", no_argument, 0, 'V'},
49 {"help", no_argument, 0, 'h'},
50 {NULL, 0, 0, 0}
51 };
52
53 static void help(void)
54 {
55 printf("Usage:\n"
56 "\t%s [options] modulename ...\n"
57 "Options:\n"
58 "\t-f, --force forces a module unload and may crash your\n"
59 "\t machine. This requires Forced Module Removal\n"
60 "\t option in your kernel. DANGEROUS\n"
61 "\t-s, --syslog print to syslog, not stderr\n"
62 "\t-v, --verbose enables more messages\n"
63 "\t-V, --version show version\n"
64 "\t-h, --help show this help\n",
65 program_invocation_short_name);
66 }
67
68 static int check_module_inuse(struct kmod_module *mod) {
69 struct kmod_list *holders;
70 int state;
71
72 state = kmod_module_get_initstate(mod);
73
74 if (state == KMOD_MODULE_BUILTIN) {
75 ERR("Module %s is builtin.\n", kmod_module_get_name(mod));
76 return -ENOENT;
77 } else if (state < 0) {
78 ERR("Module %s is not currently loaded\n",
79 kmod_module_get_name(mod));
80 return -ENOENT;
81 }
82
83 holders = kmod_module_get_holders(mod);
84 if (holders != NULL) {
85 struct kmod_list *itr;
86
87 ERR("Module %s is in use by:", kmod_module_get_name(mod));
88
89 kmod_list_foreach(itr, holders) {
90 struct kmod_module *hm = kmod_module_get_module(itr);
91 fprintf(stderr, " %s", kmod_module_get_name(hm));
92 kmod_module_unref(hm);
93 }
94 fputc('\n', stderr);
95
96 kmod_module_unref_list(holders);
97 return -EBUSY;
98 }
99
100 if (kmod_module_get_refcnt(mod) != 0) {
101 ERR("Module %s is in use\n", kmod_module_get_name(mod));
102 return -EBUSY;
103 }
104
105 return 0;
106 }
107
108 static int do_rmmod(int argc, char *argv[])
109 {
110 struct kmod_ctx *ctx;
111 const char *null_config = NULL;
112 int flags = 0;
113 int i, err, r = 0;
114
115 for (;;) {
116 int c, idx = 0;
117 c = getopt_long(argc, argv, cmdopts_s, cmdopts, &idx);
118 if (c == -1)
119 break;
120 switch (c) {
121 case 'f':
122 flags |= KMOD_REMOVE_FORCE;
123 break;
124 case 's':
125 use_syslog = 1;
126 break;
127 case 'v':
128 verbose++;
129 break;
130 case 'h':
131 help();
132 return EXIT_SUCCESS;
133 case 'V':
134 puts("kmod version " VERSION);
135 puts(KMOD_FEATURES);
136 return EXIT_SUCCESS;
137 case '?':
138 return EXIT_FAILURE;
139 default:
140 ERR("unexpected getopt_long() value '%c'.\n", c);
141 return EXIT_FAILURE;
142 }
143 }
144
145 log_open(use_syslog);
146
147 if (optind >= argc) {
148 ERR("missing module name.\n");
149 r = EXIT_FAILURE;
150 goto done;
151 }
152
153 ctx = kmod_new(NULL, &null_config);
154 if (!ctx) {
155 ERR("kmod_new() failed!\n");
156 r = EXIT_FAILURE;
157 goto done;
158 }
159
160 log_setup_kmod_log(ctx, verbose);
161
162 for (i = optind; i < argc; i++) {
163 struct kmod_module *mod;
164 const char *arg = argv[i];
165 struct stat st;
166 if (stat(arg, &st) == 0)
167 err = kmod_module_new_from_path(ctx, arg, &mod);
168 else
169 err = kmod_module_new_from_name(ctx, arg, &mod);
170
171 if (err < 0) {
172 ERR("could not use module %s: %s\n", arg,
173 strerror(-err));
174 break;
175 }
176
177 if (!(flags & KMOD_REMOVE_FORCE) && check_module_inuse(mod) < 0) {
178 r++;
179 goto next;
180 }
181
182 err = kmod_module_remove_module(mod, flags);
183 if (err < 0) {
184 ERR("could not remove module %s: %s\n", arg,
185 strerror(-err));
186 r++;
187 }
188 next:
189 kmod_module_unref(mod);
190 }
191
192 kmod_unref(ctx);
193
194 done:
195 log_close();
196
197 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
198 }
199
200 const struct kmod_cmd kmod_cmd_compat_rmmod = {
201 .name = "rmmod",
202 .cmd = do_rmmod,
203 .help = "compat rmmod command",
204 };
File src/tools/static-nodes.c added (mode: 100644) (index 0000000..e10fb40)
1 /*
2 * kmod-static-nodes - manage modules.devname
3 *
4 * Copyright (C) 2004-2012 Kay Sievers <kay@vrfy.org>
5 * Copyright (C) 2011-2013 ProFUSION embedded systems
6 * Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <errno.h>
23 #include <getopt.h>
24 #include <limits.h>
25 #include <stddef.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stddef.h>
30 #include <unistd.h>
31 #include <stdbool.h>
32 #include <stdint.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <sys/utsname.h>
36
37 #include "config.h"
38
39 #include "shared/macro.h"
40 #include "shared/util.h"
41
42 #define TOOLS_STATIC_NODES_C
43 #include "kmod.h"
44 #undef TOOLS_STATIC_NODES_C
45 #include "log.h"
46
47 struct static_nodes_format {
48 const char *name;
49 int (*write)(FILE *, char[], char[], char, unsigned int, unsigned int);
50 const char *description;
51 };
52
53 static const struct static_nodes_format static_nodes_format_human;
54 static const struct static_nodes_format static_nodes_format_tmpfiles;
55 static const struct static_nodes_format static_nodes_format_devname;
56
57 static const struct static_nodes_format *static_nodes_formats[] = {
58 &static_nodes_format_human,
59 &static_nodes_format_tmpfiles,
60 &static_nodes_format_devname,
61 };
62
63 static const char cmdopts_s[] = "o:f:h";
64 static const struct option cmdopts[] = {
65 { "output", required_argument, 0, 'o'},
66 { "format", required_argument, 0, 'f'},
67 { "help", no_argument, 0, 'h'},
68 { },
69 };
70
71 static int write_human(FILE *out, char modname[], char devname[], char type, unsigned int maj, unsigned int min)
72 {
73 int ret;
74
75 ret = fprintf(out,
76 "Module: %s\n"
77 "\tDevice node: /dev/%s\n"
78 "\t\tType: %s device\n"
79 "\t\tMajor: %u\n"
80 "\t\tMinor: %u\n",
81 modname, devname,
82 (type == 'c') ? "character" : "block", maj, min);
83 if (ret >= 0)
84 return EXIT_SUCCESS;
85 else
86 return EXIT_FAILURE;
87 }
88
89 static const struct static_nodes_format static_nodes_format_human = {
90 .name = "human",
91 .write = write_human,
92 .description = "(default) a human readable format. Do not parse.",
93 };
94
95 static int write_tmpfiles(FILE *out, char modname[], char devname[], char type, unsigned int maj, unsigned int min)
96 {
97 const char *dir;
98 int ret;
99
100 dir = strrchr(devname, '/');
101 if (dir) {
102 ret = fprintf(out, "d /dev/%.*s 0755 - - -\n",
103 (int)(dir - devname), devname);
104 if (ret < 0)
105 return EXIT_FAILURE;
106 }
107
108 ret = fprintf(out, "%c! /dev/%s 0600 - - - %u:%u\n",
109 type, devname, maj, min);
110 if (ret < 0)
111 return EXIT_FAILURE;
112
113 return EXIT_SUCCESS;
114 }
115
116 static const struct static_nodes_format static_nodes_format_tmpfiles = {
117 .name = "tmpfiles",
118 .write = write_tmpfiles,
119 .description = "the tmpfiles.d(5) format used by systemd-tmpfiles.",
120 };
121
122 static int write_devname(FILE *out, char modname[], char devname[], char type, unsigned int maj, unsigned int min)
123 {
124 int ret;
125
126 ret = fprintf(out, "%s %s %c%u:%u\n", modname, devname, type, maj, min);
127 if (ret >= 0)
128 return EXIT_SUCCESS;
129 else
130 return EXIT_FAILURE;
131 }
132
133 static const struct static_nodes_format static_nodes_format_devname = {
134 .name = "devname",
135 .write = write_devname,
136 .description = "the modules.devname format.",
137 };
138
139 static void help(void)
140 {
141 size_t i;
142
143 printf("Usage:\n"
144 "\t%s static-nodes [options]\n"
145 "\n"
146 "kmod static-nodes outputs the static-node information of the currently running kernel.\n"
147 "\n"
148 "Options:\n"
149 "\t-f, --format=FORMAT choose format to use: see \"Formats\"\n"
150 "\t-o, --output=FILE write output to file\n"
151 "\t-h, --help show this help\n"
152 "\n"
153 "Formats:\n",
154 program_invocation_short_name);
155
156 for (i = 0; i < ARRAY_SIZE(static_nodes_formats); i++) {
157 if (static_nodes_formats[i]->description != NULL) {
158 printf("\t%-12s %s\n", static_nodes_formats[i]->name,
159 static_nodes_formats[i]->description);
160 }
161 }
162 }
163
164 static int do_static_nodes(int argc, char *argv[])
165 {
166 struct utsname kernel;
167 char modules[PATH_MAX], buf[4096];
168 const char *output = "/dev/stdout";
169 FILE *in = NULL, *out = NULL;
170 const struct static_nodes_format *format = &static_nodes_format_human;
171 int r, ret = EXIT_SUCCESS;
172
173 for (;;) {
174 int c, idx = 0, valid;
175 size_t i;
176
177 c = getopt_long(argc, argv, cmdopts_s, cmdopts, &idx);
178 if (c == -1) {
179 break;
180 }
181 switch (c) {
182 case 'o':
183 output = optarg;
184 break;
185 case 'f':
186 valid = 0;
187
188 for (i = 0; i < ARRAY_SIZE(static_nodes_formats); i++) {
189 if (streq(static_nodes_formats[i]->name, optarg)) {
190 format = static_nodes_formats[i];
191 valid = 1;
192 }
193 }
194
195 if (!valid) {
196 fprintf(stderr, "Unknown format: '%s'.\n",
197 optarg);
198 help();
199 ret = EXIT_FAILURE;
200 goto finish;
201 }
202 break;
203 case 'h':
204 help();
205 goto finish;
206 case '?':
207 ret = EXIT_FAILURE;
208 goto finish;
209 default:
210 fprintf(stderr, "Unexpected commandline option '%c'.\n",
211 c);
212 help();
213 ret = EXIT_FAILURE;
214 goto finish;
215 }
216 }
217
218 if (uname(&kernel) < 0) {
219 fputs("Error: uname failed!\n", stderr);
220 ret = EXIT_FAILURE;
221 goto finish;
222 }
223
224 snprintf(modules, sizeof(modules), "/lib/modules/%s/modules.devname", kernel.release);
225 in = fopen(modules, "re");
226 if (in == NULL) {
227 if (errno == ENOENT) {
228 fprintf(stderr, "Warning: /lib/modules/%s/modules.devname not found - ignoring\n",
229 kernel.release);
230 ret = EXIT_SUCCESS;
231 } else {
232 fprintf(stderr, "Error: could not open /lib/modules/%s/modules.devname - %m\n",
233 kernel.release);
234 ret = EXIT_FAILURE;
235 }
236 goto finish;
237 }
238
239 r = mkdir_parents(output, 0755);
240 if (r < 0) {
241 fprintf(stderr, "Error: could not create parent directory for %s - %m.\n", output);
242 ret = EXIT_FAILURE;
243 goto finish;
244 }
245
246 out = fopen(output, "we");
247 if (out == NULL) {
248 fprintf(stderr, "Error: could not create %s - %m\n", output);
249 ret = EXIT_FAILURE;
250 goto finish;
251 }
252
253 while (fgets(buf, sizeof(buf), in) != NULL) {
254 char modname[PATH_MAX];
255 char devname[PATH_MAX];
256 char type;
257 unsigned int maj, min;
258 int matches;
259
260 if (buf[0] == '#')
261 continue;
262
263 matches = sscanf(buf, "%s %s %c%u:%u", modname, devname,
264 &type, &maj, &min);
265 if (matches != 5 || (type != 'c' && type != 'b')) {
266 fprintf(stderr, "Error: invalid devname entry: %s", buf);
267 ret = EXIT_FAILURE;
268 continue;
269 }
270
271 format->write(out, modname, devname, type, maj, min);
272 }
273
274 finish:
275 if (in)
276 fclose(in);
277 if (out)
278 fclose(out);
279 return ret;
280 }
281
282 const struct kmod_cmd kmod_cmd_static_nodes = {
283 .name = "static-nodes",
284 .cmd = do_static_nodes,
285 .help = "outputs the static-node information installed with the currently running kernel",
286 };
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/sylware/nyankmod

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/sylware/nyankmod

Clone this repository using git:
git clone git://git.rocketgit.com/user/sylware/nyankmod

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main