]>
Commit | Line | Data |
---|---|---|
ecd40ee4 | 1 | /* |
586fc304 LDM |
2 | * libkmod - interface to kernel module operations |
3 | * | |
4 | * Copyright (C) 2011 ProFUSION embedded systems | |
586fc304 LDM |
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 version 2.1. | |
9 | * | |
10 | * This library is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | * Lesser General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU Lesser General Public | |
16 | * License along with this library; if not, write to the Free Software | |
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
18 | */ | |
ecd40ee4 LDM |
19 | |
20 | #include <stdio.h> | |
21 | #include <stdlib.h> | |
22 | #include <stddef.h> | |
23 | #include <stdarg.h> | |
24 | #include <unistd.h> | |
25 | #include <errno.h> | |
7f3eb0cc | 26 | #include <fnmatch.h> |
ecd40ee4 LDM |
27 | #include <string.h> |
28 | #include <ctype.h> | |
221631d5 | 29 | #include <sys/utsname.h> |
ecd40ee4 | 30 | |
586fc304 LDM |
31 | #include "libkmod.h" |
32 | #include "libkmod-private.h" | |
ecd40ee4 LDM |
33 | |
34 | /** | |
586fc304 LDM |
35 | * SECTION:libkmod |
36 | * @short_description: libkmod context | |
ecd40ee4 LDM |
37 | * |
38 | * The context contains the default values for the library user, | |
39 | * and is passed to all library operations. | |
40 | */ | |
41 | ||
42 | /** | |
586fc304 | 43 | * kmod_ctx: |
ecd40ee4 LDM |
44 | * |
45 | * Opaque object representing the library context. | |
46 | */ | |
586fc304 | 47 | struct kmod_ctx { |
ecd40ee4 | 48 | int refcount; |
586fc304 | 49 | void (*log_fn)(struct kmod_ctx *ctx, |
e4351b05 LDM |
50 | int priority, const char *file, int line, |
51 | const char *fn, const char *format, va_list args); | |
ecd40ee4 | 52 | void *userdata; |
221631d5 | 53 | const char *dirname; |
ecd40ee4 | 54 | int log_priority; |
7c2ab358 | 55 | struct kmod_config config; |
ecd40ee4 LDM |
56 | }; |
57 | ||
586fc304 | 58 | void kmod_log(struct kmod_ctx *ctx, |
e4351b05 LDM |
59 | int priority, const char *file, int line, const char *fn, |
60 | const char *format, ...) | |
ecd40ee4 LDM |
61 | { |
62 | va_list args; | |
63 | ||
64 | va_start(args, format); | |
65 | ctx->log_fn(ctx, priority, file, line, fn, format, args); | |
66 | va_end(args); | |
67 | } | |
68 | ||
586fc304 | 69 | static void log_stderr(struct kmod_ctx *ctx, |
e4351b05 LDM |
70 | int priority, const char *file, int line, |
71 | const char *fn, const char *format, va_list args) | |
ecd40ee4 | 72 | { |
586fc304 | 73 | fprintf(stderr, "libkmod: %s: ", fn); |
ecd40ee4 LDM |
74 | vfprintf(stderr, format, args); |
75 | } | |
76 | ||
221631d5 LDM |
77 | const char *kmod_get_dirname(struct kmod_ctx *ctx) |
78 | { | |
79 | return ctx->dirname; | |
80 | } | |
81 | ||
ecd40ee4 | 82 | /** |
586fc304 LDM |
83 | * kmod_get_userdata: |
84 | * @ctx: kmod library context | |
ecd40ee4 LDM |
85 | * |
86 | * Retrieve stored data pointer from library context. This might be useful | |
87 | * to access from callbacks like a custom logging function. | |
88 | * | |
89 | * Returns: stored userdata | |
90 | **/ | |
6d177553 | 91 | KMOD_EXPORT void *kmod_get_userdata(const struct kmod_ctx *ctx) |
ecd40ee4 LDM |
92 | { |
93 | if (ctx == NULL) | |
94 | return NULL; | |
95 | return ctx->userdata; | |
96 | } | |
97 | ||
98 | /** | |
586fc304 LDM |
99 | * kmod_set_userdata: |
100 | * @ctx: kmod library context | |
ecd40ee4 LDM |
101 | * @userdata: data pointer |
102 | * | |
103 | * Store custom @userdata in the library context. | |
104 | **/ | |
586fc304 | 105 | KMOD_EXPORT void kmod_set_userdata(struct kmod_ctx *ctx, void *userdata) |
ecd40ee4 LDM |
106 | { |
107 | if (ctx == NULL) | |
108 | return; | |
109 | ctx->userdata = userdata; | |
110 | } | |
111 | ||
112 | static int log_priority(const char *priority) | |
113 | { | |
114 | char *endptr; | |
115 | int prio; | |
116 | ||
117 | prio = strtol(priority, &endptr, 10); | |
118 | if (endptr[0] == '\0' || isspace(endptr[0])) | |
119 | return prio; | |
120 | if (strncmp(priority, "err", 3) == 0) | |
121 | return LOG_ERR; | |
122 | if (strncmp(priority, "info", 4) == 0) | |
123 | return LOG_INFO; | |
124 | if (strncmp(priority, "debug", 5) == 0) | |
125 | return LOG_DEBUG; | |
126 | return 0; | |
127 | } | |
128 | ||
221631d5 LDM |
129 | static const char *get_kernel_release(void) |
130 | { | |
131 | struct utsname u; | |
132 | ||
133 | if (uname(&u) < 0) | |
134 | return NULL; | |
135 | ||
136 | return strdup(u.release); | |
137 | } | |
138 | ||
ecd40ee4 | 139 | /** |
586fc304 | 140 | * kmod_new: |
ecd40ee4 | 141 | * |
586fc304 | 142 | * Create kmod library context. This reads the kmod configuration |
ecd40ee4 LDM |
143 | * and fills in the default values. |
144 | * | |
145 | * The initial refcount is 1, and needs to be decremented to | |
586fc304 | 146 | * release the resources of the kmod library context. |
ecd40ee4 | 147 | * |
586fc304 | 148 | * Returns: a new kmod library context |
ecd40ee4 | 149 | **/ |
221631d5 | 150 | KMOD_EXPORT struct kmod_ctx *kmod_new(const char *dirname) |
ecd40ee4 LDM |
151 | { |
152 | const char *env; | |
52a7704f | 153 | struct kmod_ctx *ctx; |
ecd40ee4 | 154 | |
52a7704f LDM |
155 | ctx = calloc(1, sizeof(struct kmod_ctx)); |
156 | if (!ctx) | |
157 | return NULL; | |
ecd40ee4 | 158 | |
52a7704f LDM |
159 | ctx->refcount = 1; |
160 | ctx->log_fn = log_stderr; | |
161 | ctx->log_priority = LOG_ERR; | |
ecd40ee4 | 162 | |
221631d5 LDM |
163 | if (dirname != NULL) |
164 | ctx->dirname = strdup(dirname); | |
165 | else | |
166 | ctx->dirname = get_kernel_release(); | |
167 | ||
ecd40ee4 | 168 | /* environment overwrites config */ |
586fc304 | 169 | env = getenv("KMOD_LOG"); |
ecd40ee4 | 170 | if (env != NULL) |
52a7704f | 171 | kmod_set_log_priority(ctx, log_priority(env)); |
ecd40ee4 | 172 | |
7c2ab358 LDM |
173 | kmod_parse_config(ctx, &ctx->config); |
174 | ||
ae6df84a LDM |
175 | INFO(ctx, "ctx %p created\n", ctx); |
176 | DBG(ctx, "log_priority=%d\n", ctx->log_priority); | |
52a7704f LDM |
177 | |
178 | return ctx; | |
ecd40ee4 LDM |
179 | } |
180 | ||
181 | /** | |
586fc304 LDM |
182 | * kmod_ref: |
183 | * @ctx: kmod library context | |
ecd40ee4 | 184 | * |
586fc304 | 185 | * Take a reference of the kmod library context. |
ecd40ee4 | 186 | * |
586fc304 | 187 | * Returns: the passed kmod library context |
ecd40ee4 | 188 | **/ |
586fc304 | 189 | KMOD_EXPORT struct kmod_ctx *kmod_ref(struct kmod_ctx *ctx) |
ecd40ee4 LDM |
190 | { |
191 | if (ctx == NULL) | |
192 | return NULL; | |
193 | ctx->refcount++; | |
194 | return ctx; | |
195 | } | |
196 | ||
197 | /** | |
586fc304 LDM |
198 | * kmod_unref: |
199 | * @ctx: kmod library context | |
ecd40ee4 | 200 | * |
586fc304 | 201 | * Drop a reference of the kmod library context. If the refcount |
ecd40ee4 LDM |
202 | * reaches zero, the resources of the context will be released. |
203 | * | |
204 | **/ | |
586fc304 | 205 | KMOD_EXPORT struct kmod_ctx *kmod_unref(struct kmod_ctx *ctx) |
ecd40ee4 LDM |
206 | { |
207 | if (ctx == NULL) | |
208 | return NULL; | |
4d1e689a LDM |
209 | |
210 | if (--ctx->refcount > 0) | |
ecd40ee4 | 211 | return ctx; |
ae6df84a | 212 | INFO(ctx, "context %p released\n", ctx); |
221631d5 | 213 | free((char *)ctx->dirname); |
7c2ab358 | 214 | kmod_free_config(ctx, &ctx->config); |
ecd40ee4 LDM |
215 | free(ctx); |
216 | return NULL; | |
217 | } | |
218 | ||
219 | /** | |
586fc304 LDM |
220 | * kmod_set_log_fn: |
221 | * @ctx: kmod library context | |
ecd40ee4 LDM |
222 | * @log_fn: function to be called for logging messages |
223 | * | |
224 | * The built-in logging writes to stderr. It can be | |
225 | * overridden by a custom function, to plug log messages | |
226 | * into the user's logging functionality. | |
227 | * | |
228 | **/ | |
586fc304 | 229 | KMOD_EXPORT void kmod_set_log_fn(struct kmod_ctx *ctx, |
e4351b05 LDM |
230 | void (*log_fn)(struct kmod_ctx *ctx, |
231 | int priority, const char *file, | |
232 | int line, const char *fn, | |
233 | const char *format, va_list args)) | |
ecd40ee4 LDM |
234 | { |
235 | ctx->log_fn = log_fn; | |
ae6df84a | 236 | INFO(ctx, "custom logging function %p registered\n", log_fn); |
ecd40ee4 LDM |
237 | } |
238 | ||
239 | /** | |
586fc304 LDM |
240 | * kmod_get_log_priority: |
241 | * @ctx: kmod library context | |
ecd40ee4 LDM |
242 | * |
243 | * Returns: the current logging priority | |
244 | **/ | |
6d177553 | 245 | KMOD_EXPORT int kmod_get_log_priority(const struct kmod_ctx *ctx) |
ecd40ee4 LDM |
246 | { |
247 | return ctx->log_priority; | |
248 | } | |
249 | ||
250 | /** | |
586fc304 LDM |
251 | * kmod_set_log_priority: |
252 | * @ctx: kmod library context | |
ecd40ee4 LDM |
253 | * @priority: the new logging priority |
254 | * | |
255 | * Set the current logging priority. The value controls which messages | |
256 | * are logged. | |
257 | **/ | |
586fc304 | 258 | KMOD_EXPORT void kmod_set_log_priority(struct kmod_ctx *ctx, int priority) |
ecd40ee4 LDM |
259 | { |
260 | ctx->log_priority = priority; | |
261 | } | |
7f3eb0cc LDM |
262 | |
263 | int kmod_lookup_alias_from_config(struct kmod_ctx *ctx, const char *name, | |
264 | struct kmod_list **list) | |
265 | { | |
266 | struct kmod_config *config = &ctx->config; | |
267 | struct kmod_list *l; | |
268 | int err; | |
269 | ||
270 | kmod_list_foreach(l, config->aliases) { | |
271 | const char *aliasname = kmod_alias_get_name(l); | |
272 | const char *modname = kmod_alias_get_modname(l); | |
273 | ||
274 | if (fnmatch(aliasname, name, 0) == 0) { | |
275 | struct kmod_module *mod; | |
276 | ||
277 | err = kmod_module_new_from_name(ctx, modname, &mod); | |
278 | if (err < 0) { | |
279 | ERR(ctx, "%s", strerror(-err)); | |
280 | return err; | |
281 | } | |
282 | ||
283 | *list = kmod_list_append(*list, mod); | |
284 | } | |
285 | } | |
286 | ||
287 | return 0; | |
288 | } |