]> git.ipfire.org Git - thirdparty/kmod.git/blob - libkmod/libkmod-util.c
libkmod-util: split function for usec conversion
[thirdparty/kmod.git] / libkmod / libkmod-util.c
1 /*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011-2012 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, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <assert.h>
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);
49
50 if (buf == NULL)
51 return NULL;
52
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 }
92
93 inline int alias_normalize(const char *alias, char buf[PATH_MAX], size_t *len)
94 {
95 size_t s;
96
97 for (s = 0; s < PATH_MAX - 1; s++) {
98 const char c = alias[s];
99 switch (c) {
100 case '-':
101 buf[s] = '_';
102 break;
103 case ']':
104 return -EINVAL;
105 case '[':
106 while (alias[s] != ']' && alias[s] != '\0') {
107 buf[s] = alias[s];
108 s++;
109 }
110
111 if (alias[s] != ']')
112 return -EINVAL;
113
114 buf[s] = alias[s];
115 break;
116 case '\0':
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
132 inline char *modname_normalize(const char *modname, char buf[PATH_MAX],
133 size_t *len)
134 {
135 size_t s;
136
137 for (s = 0; s < PATH_MAX - 1; s++) {
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
155 char *path_to_modname(const char *path, char buf[PATH_MAX], size_t *len)
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
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 }
175
176 ssize_t read_str_safe(int fd, char *buf, size_t buflen)
177 {
178 size_t todo = buflen - 1;
179 size_t done = 0;
180
181 do {
182 ssize_t r = read(fd, buf + done, todo);
183
184 if (r == 0)
185 break;
186 else if (r > 0) {
187 todo -= r;
188 done += r;
189 } else {
190 if (errno == EAGAIN || errno == EWOULDBLOCK ||
191 errno == EINTR)
192 continue;
193 else
194 return -errno;
195 }
196 } while (todo > 0);
197
198 buf[done] = '\0';
199 return done;
200 }
201
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
227 int read_str_long(int fd, long *value, int base)
228 {
229 char buf[32], *end;
230 long v;
231 int err;
232
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;
241
242 *value = v;
243 return 0;
244 }
245
246 int read_str_ulong(int fd, unsigned long *value, int base)
247 {
248 char buf[32], *end;
249 long v;
250 int err;
251
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 }
263
264 char *strchr_replace(char *s, int c, char r)
265 {
266 char *p;
267
268 for (p = s; *p != '\0'; p++)
269 if (*p == c)
270 *p = r;
271
272 return s;
273 }
274
275 bool path_is_absolute(const char *p)
276 {
277 assert(p != NULL);
278
279 return p[0] == '/';
280 }
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
305 r[cwdlen] = '/';
306 memcpy(&r[cwdlen + 1], p, plen + 1);
307
308 return r;
309 }
310
311 #define USEC_PER_SEC 1000000ULL
312 #define NSEC_PER_USEC 1000ULL
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
319 unsigned long long stat_mstamp(const struct stat *st)
320 {
321 #ifdef HAVE_STRUCT_STAT_ST_MTIM
322 return ts_usec(&st->st_mtim);
323 #else
324 return (unsigned long long) st->st_mtime;
325 #endif
326 }