]>
Commit | Line | Data |
---|---|---|
ecd40ee4 | 1 | /* |
586fc304 LDM |
2 | * libkmod - interface to kernel module operations |
3 | * | |
4 | * Copyright (C) 2011 ProFUSION embedded systems | |
5 | * Copyright (C) 2011 Lucas De Marchi <lucas.de.marchi@gmail.com> | |
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 version 2.1. | |
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, write to the Free Software | |
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
19 | */ | |
ecd40ee4 LDM |
20 | |
21 | #include <stdio.h> | |
22 | #include <stdlib.h> | |
23 | #include <stddef.h> | |
24 | #include <stdarg.h> | |
25 | #include <unistd.h> | |
26 | #include <errno.h> | |
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 LDM |
54 | int log_priority; |
55 | }; | |
56 | ||
586fc304 | 57 | void kmod_log(struct kmod_ctx *ctx, |
e4351b05 LDM |
58 | int priority, const char *file, int line, const char *fn, |
59 | const char *format, ...) | |
ecd40ee4 LDM |
60 | { |
61 | va_list args; | |
62 | ||
63 | va_start(args, format); | |
64 | ctx->log_fn(ctx, priority, file, line, fn, format, args); | |
65 | va_end(args); | |
66 | } | |
67 | ||
586fc304 | 68 | static void log_stderr(struct kmod_ctx *ctx, |
e4351b05 LDM |
69 | int priority, const char *file, int line, |
70 | const char *fn, const char *format, va_list args) | |
ecd40ee4 | 71 | { |
586fc304 | 72 | fprintf(stderr, "libkmod: %s: ", fn); |
ecd40ee4 LDM |
73 | vfprintf(stderr, format, args); |
74 | } | |
75 | ||
221631d5 LDM |
76 | const char *kmod_get_dirname(struct kmod_ctx *ctx) |
77 | { | |
78 | return ctx->dirname; | |
79 | } | |
80 | ||
ecd40ee4 | 81 | /** |
586fc304 LDM |
82 | * kmod_get_userdata: |
83 | * @ctx: kmod library context | |
ecd40ee4 LDM |
84 | * |
85 | * Retrieve stored data pointer from library context. This might be useful | |
86 | * to access from callbacks like a custom logging function. | |
87 | * | |
88 | * Returns: stored userdata | |
89 | **/ | |
6d177553 | 90 | KMOD_EXPORT void *kmod_get_userdata(const struct kmod_ctx *ctx) |
ecd40ee4 LDM |
91 | { |
92 | if (ctx == NULL) | |
93 | return NULL; | |
94 | return ctx->userdata; | |
95 | } | |
96 | ||
97 | /** | |
586fc304 LDM |
98 | * kmod_set_userdata: |
99 | * @ctx: kmod library context | |
ecd40ee4 LDM |
100 | * @userdata: data pointer |
101 | * | |
102 | * Store custom @userdata in the library context. | |
103 | **/ | |
586fc304 | 104 | KMOD_EXPORT void kmod_set_userdata(struct kmod_ctx *ctx, void *userdata) |
ecd40ee4 LDM |
105 | { |
106 | if (ctx == NULL) | |
107 | return; | |
108 | ctx->userdata = userdata; | |
109 | } | |
110 | ||
111 | static int log_priority(const char *priority) | |
112 | { | |
113 | char *endptr; | |
114 | int prio; | |
115 | ||
116 | prio = strtol(priority, &endptr, 10); | |
117 | if (endptr[0] == '\0' || isspace(endptr[0])) | |
118 | return prio; | |
119 | if (strncmp(priority, "err", 3) == 0) | |
120 | return LOG_ERR; | |
121 | if (strncmp(priority, "info", 4) == 0) | |
122 | return LOG_INFO; | |
123 | if (strncmp(priority, "debug", 5) == 0) | |
124 | return LOG_DEBUG; | |
125 | return 0; | |
126 | } | |
127 | ||
221631d5 LDM |
128 | static const char *get_kernel_release(void) |
129 | { | |
130 | struct utsname u; | |
131 | ||
132 | if (uname(&u) < 0) | |
133 | return NULL; | |
134 | ||
135 | return strdup(u.release); | |
136 | } | |
137 | ||
ecd40ee4 | 138 | /** |
586fc304 | 139 | * kmod_new: |
ecd40ee4 | 140 | * |
586fc304 | 141 | * Create kmod library context. This reads the kmod configuration |
ecd40ee4 LDM |
142 | * and fills in the default values. |
143 | * | |
144 | * The initial refcount is 1, and needs to be decremented to | |
586fc304 | 145 | * release the resources of the kmod library context. |
ecd40ee4 | 146 | * |
586fc304 | 147 | * Returns: a new kmod library context |
ecd40ee4 | 148 | **/ |
221631d5 | 149 | KMOD_EXPORT struct kmod_ctx *kmod_new(const char *dirname) |
ecd40ee4 LDM |
150 | { |
151 | const char *env; | |
52a7704f | 152 | struct kmod_ctx *ctx; |
ecd40ee4 | 153 | |
52a7704f LDM |
154 | ctx = calloc(1, sizeof(struct kmod_ctx)); |
155 | if (!ctx) | |
156 | return NULL; | |
ecd40ee4 | 157 | |
52a7704f LDM |
158 | ctx->refcount = 1; |
159 | ctx->log_fn = log_stderr; | |
160 | ctx->log_priority = LOG_ERR; | |
ecd40ee4 | 161 | |
221631d5 LDM |
162 | if (dirname != NULL) |
163 | ctx->dirname = strdup(dirname); | |
164 | else | |
165 | ctx->dirname = get_kernel_release(); | |
166 | ||
ecd40ee4 | 167 | /* environment overwrites config */ |
586fc304 | 168 | env = getenv("KMOD_LOG"); |
ecd40ee4 | 169 | if (env != NULL) |
52a7704f | 170 | kmod_set_log_priority(ctx, log_priority(env)); |
ecd40ee4 | 171 | |
52a7704f LDM |
172 | info(ctx, "ctx %p created\n", ctx); |
173 | dbg(ctx, "log_priority=%d\n", ctx->log_priority); | |
174 | ||
175 | return ctx; | |
ecd40ee4 LDM |
176 | } |
177 | ||
178 | /** | |
586fc304 LDM |
179 | * kmod_ref: |
180 | * @ctx: kmod library context | |
ecd40ee4 | 181 | * |
586fc304 | 182 | * Take a reference of the kmod library context. |
ecd40ee4 | 183 | * |
586fc304 | 184 | * Returns: the passed kmod library context |
ecd40ee4 | 185 | **/ |
586fc304 | 186 | KMOD_EXPORT struct kmod_ctx *kmod_ref(struct kmod_ctx *ctx) |
ecd40ee4 LDM |
187 | { |
188 | if (ctx == NULL) | |
189 | return NULL; | |
190 | ctx->refcount++; | |
191 | return ctx; | |
192 | } | |
193 | ||
194 | /** | |
586fc304 LDM |
195 | * kmod_unref: |
196 | * @ctx: kmod library context | |
ecd40ee4 | 197 | * |
586fc304 | 198 | * Drop a reference of the kmod library context. If the refcount |
ecd40ee4 LDM |
199 | * reaches zero, the resources of the context will be released. |
200 | * | |
201 | **/ | |
586fc304 | 202 | KMOD_EXPORT struct kmod_ctx *kmod_unref(struct kmod_ctx *ctx) |
ecd40ee4 LDM |
203 | { |
204 | if (ctx == NULL) | |
205 | return NULL; | |
4d1e689a LDM |
206 | |
207 | if (--ctx->refcount > 0) | |
ecd40ee4 LDM |
208 | return ctx; |
209 | info(ctx, "context %p released\n", ctx); | |
221631d5 | 210 | free((char *)ctx->dirname); |
ecd40ee4 LDM |
211 | free(ctx); |
212 | return NULL; | |
213 | } | |
214 | ||
215 | /** | |
586fc304 LDM |
216 | * kmod_set_log_fn: |
217 | * @ctx: kmod library context | |
ecd40ee4 LDM |
218 | * @log_fn: function to be called for logging messages |
219 | * | |
220 | * The built-in logging writes to stderr. It can be | |
221 | * overridden by a custom function, to plug log messages | |
222 | * into the user's logging functionality. | |
223 | * | |
224 | **/ | |
586fc304 | 225 | KMOD_EXPORT void kmod_set_log_fn(struct kmod_ctx *ctx, |
e4351b05 LDM |
226 | void (*log_fn)(struct kmod_ctx *ctx, |
227 | int priority, const char *file, | |
228 | int line, const char *fn, | |
229 | const char *format, va_list args)) | |
ecd40ee4 LDM |
230 | { |
231 | ctx->log_fn = log_fn; | |
232 | info(ctx, "custom logging function %p registered\n", log_fn); | |
233 | } | |
234 | ||
235 | /** | |
586fc304 LDM |
236 | * kmod_get_log_priority: |
237 | * @ctx: kmod library context | |
ecd40ee4 LDM |
238 | * |
239 | * Returns: the current logging priority | |
240 | **/ | |
6d177553 | 241 | KMOD_EXPORT int kmod_get_log_priority(const struct kmod_ctx *ctx) |
ecd40ee4 LDM |
242 | { |
243 | return ctx->log_priority; | |
244 | } | |
245 | ||
246 | /** | |
586fc304 LDM |
247 | * kmod_set_log_priority: |
248 | * @ctx: kmod library context | |
ecd40ee4 LDM |
249 | * @priority: the new logging priority |
250 | * | |
251 | * Set the current logging priority. The value controls which messages | |
252 | * are logged. | |
253 | **/ | |
586fc304 | 254 | KMOD_EXPORT void kmod_set_log_priority(struct kmod_ctx *ctx, int priority) |
ecd40ee4 LDM |
255 | { |
256 | ctx->log_priority = priority; | |
257 | } |