]>
Commit | Line | Data |
---|---|---|
4462c4ac LDM |
1 | /* |
2 | * libkmod - interface to kernel module operations | |
3 | * | |
a66a6a99 | 4 | * Copyright (C) 2011-2012 ProFUSION embedded systems |
4462c4ac 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 | |
cb451f35 LDM |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2.1 of the License, or (at your option) any later version. | |
4462c4ac LDM |
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 | */ | |
20 | ||
7e317da3 | 21 | #include <assert.h> |
4462c4ac LDM |
22 | #include <stdio.h> |
23 | #include <stdlib.h> | |
24 | #include <stddef.h> | |
25 | #include <stdarg.h> | |
26 | #include <unistd.h> | |
27 | #include <errno.h> | |
28 | #include <string.h> | |
29 | #include <ctype.h> | |
30 | ||
31 | #include "libkmod.h" | |
32 | #include "libkmod-private.h" | |
33 | ||
34 | /* | |
35 | * Read one logical line from a configuration file. | |
36 | * | |
37 | * Line endings may be escaped with backslashes, to form one logical line from | |
38 | * several physical lines. No end of line character(s) are included in the | |
39 | * result. | |
40 | * | |
41 | * If linenum is not NULL, it is incremented by the number of physical lines | |
42 | * which have been read. | |
43 | */ | |
44 | char *getline_wrapped(FILE *fp, unsigned int *linenum) | |
45 | { | |
46 | int size = 256; | |
47 | int i = 0; | |
48 | char *buf = malloc(size); | |
28c175ed | 49 | |
16984562 LP |
50 | if (buf == NULL) |
51 | return NULL; | |
52 | ||
4462c4ac LDM |
53 | for(;;) { |
54 | int ch = getc_unlocked(fp); | |
55 | ||
56 | switch(ch) { | |
57 | case EOF: | |
58 | if (i == 0) { | |
59 | free(buf); | |
60 | return NULL; | |
61 | } | |
62 | /* else fall through */ | |
63 | ||
64 | case '\n': | |
65 | if (linenum) | |
66 | (*linenum)++; | |
67 | if (i == size) | |
68 | buf = realloc(buf, size + 1); | |
69 | buf[i] = '\0'; | |
70 | return buf; | |
71 | ||
72 | case '\\': | |
73 | ch = getc_unlocked(fp); | |
74 | ||
75 | if (ch == '\n') { | |
76 | if (linenum) | |
77 | (*linenum)++; | |
78 | continue; | |
79 | } | |
80 | /* else fall through */ | |
81 | ||
82 | default: | |
83 | buf[i++] = ch; | |
84 | ||
85 | if (i == size) { | |
86 | size *= 2; | |
87 | buf = realloc(buf, size); | |
88 | } | |
89 | } | |
90 | } | |
91 | } | |
8185fc91 | 92 | |
6daceb2f | 93 | inline int alias_normalize(const char *alias, char buf[PATH_MAX], size_t *len) |
b148b860 LDM |
94 | { |
95 | size_t s; | |
96 | ||
6daceb2f | 97 | for (s = 0; s < PATH_MAX - 1; s++) { |
b148b860 LDM |
98 | const char c = alias[s]; |
99 | switch (c) { | |
100 | case '-': | |
101 | buf[s] = '_'; | |
102 | break; | |
103 | case ']': | |
104 | return -EINVAL; | |
105 | case '[': | |
9901cfe2 | 106 | while (alias[s] != ']' && alias[s] != '\0') { |
647200fb | 107 | buf[s] = alias[s]; |
b148b860 | 108 | s++; |
647200fb | 109 | } |
b148b860 LDM |
110 | |
111 | if (alias[s] != ']') | |
112 | return -EINVAL; | |
113 | ||
647200fb | 114 | buf[s] = alias[s]; |
b148b860 LDM |
115 | break; |
116 | case '\0': | |
b148b860 LDM |
117 | goto finish; |
118 | default: | |
119 | buf[s] = c; | |
120 | } | |
121 | } | |
122 | ||
123 | finish: | |
124 | buf[s] = '\0'; | |
125 | ||
126 | if (len) | |
127 | *len = s; | |
128 | ||
129 | return 0; | |
130 | } | |
131 | ||
6daceb2f | 132 | inline char *modname_normalize(const char *modname, char buf[PATH_MAX], |
a4848e24 LDM |
133 | size_t *len) |
134 | { | |
135 | size_t s; | |
136 | ||
6daceb2f | 137 | for (s = 0; s < PATH_MAX - 1; s++) { |
a4848e24 LDM |
138 | const char c = modname[s]; |
139 | if (c == '-') | |
140 | buf[s] = '_'; | |
141 | else if (c == '\0' || c == '.') | |
142 | break; | |
143 | else | |
144 | buf[s] = c; | |
145 | } | |
146 | ||
147 | buf[s] = '\0'; | |
148 | ||
149 | if (len) | |
150 | *len = s; | |
151 | ||
152 | return buf; | |
153 | } | |
154 | ||
6daceb2f | 155 | char *path_to_modname(const char *path, char buf[PATH_MAX], size_t *len) |
a4848e24 LDM |
156 | { |
157 | char *modname; | |
158 | ||
159 | modname = basename(path); | |
160 | if (modname == NULL || modname[0] == '\0') | |
161 | return NULL; | |
162 | ||
163 | return modname_normalize(modname, buf, len); | |
164 | } | |
165 | ||
e22c85f3 LDM |
166 | inline void *memdup(const void *p, size_t n) |
167 | { | |
168 | void *r = malloc(n); | |
169 | ||
170 | if (r == NULL) | |
171 | return NULL; | |
172 | ||
173 | return memcpy(r, p, n); | |
174 | } | |
f12ae3c4 | 175 | |
7a973b0c LDM |
176 | ssize_t read_str_safe(int fd, char *buf, size_t buflen) |
177 | { | |
67179941 GSB |
178 | size_t todo = buflen - 1; |
179 | size_t done = 0; | |
28c175ed | 180 | |
f12ae3c4 | 181 | do { |
67179941 | 182 | ssize_t r = read(fd, buf + done, todo); |
28c175ed | 183 | |
f12ae3c4 GSB |
184 | if (r == 0) |
185 | break; | |
67179941 | 186 | else if (r > 0) { |
f12ae3c4 | 187 | todo -= r; |
67179941 GSB |
188 | done += r; |
189 | } else { | |
f12ae3c4 | 190 | if (errno == EAGAIN || errno == EWOULDBLOCK || |
7a973b0c | 191 | errno == EINTR) |
f12ae3c4 GSB |
192 | continue; |
193 | else | |
194 | return -errno; | |
195 | } | |
196 | } while (todo > 0); | |
28c175ed | 197 | |
67179941 | 198 | buf[done] = '\0'; |
f12ae3c4 GSB |
199 | return done; |
200 | } | |
201 | ||
f1cbf3cf LDM |
202 | ssize_t write_str_safe(int fd, const char *buf, size_t buflen) |
203 | { | |
204 | size_t todo = buflen; | |
205 | size_t done = 0; | |
206 | ||
207 | do { | |
208 | ssize_t r = write(fd, buf + done, todo); | |
209 | ||
210 | if (r == 0) | |
211 | break; | |
212 | else if (r > 0) { | |
213 | todo -= r; | |
214 | done += r; | |
215 | } else { | |
216 | if (errno == EAGAIN || errno == EWOULDBLOCK || | |
217 | errno == EINTR) | |
218 | continue; | |
219 | else | |
220 | return -errno; | |
221 | } | |
222 | } while (todo > 0); | |
223 | ||
224 | return done; | |
225 | } | |
226 | ||
7a973b0c LDM |
227 | int read_str_long(int fd, long *value, int base) |
228 | { | |
f12ae3c4 GSB |
229 | char buf[32], *end; |
230 | long v; | |
231 | int err; | |
28c175ed | 232 | |
f12ae3c4 GSB |
233 | *value = 0; |
234 | err = read_str_safe(fd, buf, sizeof(buf)); | |
235 | if (err < 0) | |
236 | return err; | |
237 | errno = 0; | |
238 | v = strtol(buf, &end, base); | |
239 | if (end == buf || !isspace(*end)) | |
240 | return -EINVAL; | |
28c175ed | 241 | |
f12ae3c4 GSB |
242 | *value = v; |
243 | return 0; | |
244 | } | |
245 | ||
7a973b0c LDM |
246 | int read_str_ulong(int fd, unsigned long *value, int base) |
247 | { | |
f12ae3c4 GSB |
248 | char buf[32], *end; |
249 | long v; | |
250 | int err; | |
28c175ed | 251 | |
f12ae3c4 GSB |
252 | *value = 0; |
253 | err = read_str_safe(fd, buf, sizeof(buf)); | |
254 | if (err < 0) | |
255 | return err; | |
256 | errno = 0; | |
257 | v = strtoul(buf, &end, base); | |
258 | if (end == buf || !isspace(*end)) | |
259 | return -EINVAL; | |
260 | *value = v; | |
261 | return 0; | |
262 | } | |
afca7801 LDM |
263 | |
264 | char *strchr_replace(char *s, int c, char r) | |
265 | { | |
266 | char *p; | |
28c175ed | 267 | |
bf8cf148 GSB |
268 | for (p = s; *p != '\0'; p++) |
269 | if (*p == c) | |
270 | *p = r; | |
28c175ed | 271 | |
afca7801 LDM |
272 | return s; |
273 | } | |
3a468809 LDM |
274 | |
275 | bool path_is_absolute(const char *p) | |
276 | { | |
277 | assert(p != NULL); | |
278 | ||
279 | return p[0] == '/'; | |
280 | } | |
06363cc1 LDM |
281 | |
282 | char *path_make_absolute_cwd(const char *p) | |
283 | { | |
284 | char *cwd, *r; | |
285 | size_t plen; | |
286 | size_t cwdlen; | |
287 | ||
288 | if (path_is_absolute(p)) | |
289 | return strdup(p); | |
290 | ||
291 | cwd = get_current_dir_name(); | |
292 | if (cwd == NULL) | |
293 | return NULL; | |
294 | ||
295 | plen = strlen(p); | |
296 | cwdlen = strlen(cwd); | |
297 | ||
298 | /* cwd + '/' + p + '\0' */ | |
299 | r = realloc(cwd, cwdlen + 1 + plen + 1); | |
300 | if (r == NULL) { | |
301 | free(cwd); | |
302 | return NULL; | |
303 | } | |
304 | ||
4eb2c0fc LDM |
305 | r[cwdlen] = '/'; |
306 | memcpy(&r[cwdlen + 1], p, plen + 1); | |
06363cc1 LDM |
307 | |
308 | return r; | |
309 | } | |
0b29ef6f LDM |
310 | |
311 | #define USEC_PER_SEC 1000000ULL | |
312 | #define NSEC_PER_USEC 1000ULL | |
535c541e LDM |
313 | unsigned long long ts_usec(const struct timespec *ts) |
314 | { | |
315 | return (unsigned long long) ts->tv_sec * USEC_PER_SEC + | |
316 | (unsigned long long) ts->tv_nsec / NSEC_PER_USEC; | |
317 | } | |
318 | ||
6068aaae | 319 | unsigned long long stat_mstamp(const struct stat *st) |
0b29ef6f | 320 | { |
6068aaae | 321 | #ifdef HAVE_STRUCT_STAT_ST_MTIM |
535c541e | 322 | return ts_usec(&st->st_mtim); |
6068aaae LDM |
323 | #else |
324 | return (unsigned long long) st->st_mtime; | |
325 | #endif | |
0b29ef6f | 326 | } |