blob: f6ce61d1e5ad7f8a25ce63dd5e258865fbf6003c [file] [log] [blame]
Lucas De Marchi96573a02014-10-03 00:01:35 -03001/*
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, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#include <assert.h>
Lucas De Marchic2e42862014-10-03 01:41:42 -030024#include <ctype.h>
25#include <errno.h>
26#include <stdarg.h>
27#include <stddef.h>
Lucas De Marchi96573a02014-10-03 00:01:35 -030028#include <stdio.h>
29#include <stdlib.h>
Lucas De Marchi96573a02014-10-03 00:01:35 -030030#include <string.h>
Lucas De Marchic2e42862014-10-03 01:41:42 -030031#include <unistd.h>
Lucas De Marchi96573a02014-10-03 00:01:35 -030032
33#include <shared/util.h>
34
35#define USEC_PER_SEC 1000000ULL
36#define NSEC_PER_USEC 1000ULL
37
38/* string handling functions and memory allocations */
39/* ************************************************************************ */
40
41void *memdup(const void *p, size_t n)
42{
43 void *r = malloc(n);
44
45 if (r == NULL)
46 return NULL;
47
48 return memcpy(r, p, n);
49}
50
51char *strchr_replace(char *s, int c, char r)
52{
53 char *p;
54
55 for (p = s; *p != '\0'; p++) {
56 if (*p == c)
57 *p = r;
58 }
59
60 return s;
61}
62
Lucas De Marchi2b0104f2014-10-09 00:43:01 -030063/* module-related functions */
64/* ************************************************************************ */
65int alias_normalize(const char *alias, char buf[static PATH_MAX], size_t *len)
66{
67 size_t i;
68
69 for (i = 0; i < PATH_MAX - 1; i++) {
70 const char c = alias[i];
71 switch (c) {
72 case '-':
73 buf[i] = '_';
74 break;
75 case ']':
76 return -EINVAL;
77 case '[':
78 while (alias[i] != ']' && alias[i] != '\0') {
79 buf[i] = alias[i];
80 i++;
81 }
82
83 if (alias[i] != ']')
84 return -EINVAL;
85
86 buf[i] = alias[i];
87 break;
88 case '\0':
89 goto finish;
90 default:
91 buf[i] = c;
92 }
93 }
94
95finish:
96 buf[i] = '\0';
97 if (len)
98 *len = i;
99
100 return 0;
101}
102
Lucas De Marchi96573a02014-10-03 00:01:35 -0300103/* read-like and fread-like functions */
104/* ************************************************************************ */
105ssize_t read_str_safe(int fd, char *buf, size_t buflen)
106{
107 size_t todo = buflen - 1;
108 size_t done = 0;
109
110 do {
111 ssize_t r = read(fd, buf + done, todo);
112
113 if (r == 0)
114 break;
115 else if (r > 0) {
116 todo -= r;
117 done += r;
118 } else {
119 if (errno == EAGAIN || errno == EWOULDBLOCK ||
120 errno == EINTR)
121 continue;
122 else
123 return -errno;
124 }
125 } while (todo > 0);
126
127 buf[done] = '\0';
128 return done;
129}
130
131ssize_t write_str_safe(int fd, const char *buf, size_t buflen)
132{
133 size_t todo = buflen;
134 size_t done = 0;
135
136 do {
137 ssize_t r = write(fd, buf + done, todo);
138
139 if (r == 0)
140 break;
141 else if (r > 0) {
142 todo -= r;
143 done += r;
144 } else {
145 if (errno == EAGAIN || errno == EWOULDBLOCK ||
146 errno == EINTR)
147 continue;
148 else
149 return -errno;
150 }
151 } while (todo > 0);
152
153 return done;
154}
155
156int read_str_long(int fd, long *value, int base)
157{
158 char buf[32], *end;
159 long v;
160 int err;
161
162 *value = 0;
163 err = read_str_safe(fd, buf, sizeof(buf));
164 if (err < 0)
165 return err;
166 errno = 0;
167 v = strtol(buf, &end, base);
168 if (end == buf || !isspace(*end))
169 return -EINVAL;
170
171 *value = v;
172 return 0;
173}
174
175int read_str_ulong(int fd, unsigned long *value, int base)
176{
177 char buf[32], *end;
178 long v;
179 int err;
180
181 *value = 0;
182 err = read_str_safe(fd, buf, sizeof(buf));
183 if (err < 0)
184 return err;
185 errno = 0;
186 v = strtoul(buf, &end, base);
187 if (end == buf || !isspace(*end))
188 return -EINVAL;
189 *value = v;
190 return 0;
191}
192
193/*
194 * Read one logical line from a configuration file.
195 *
196 * Line endings may be escaped with backslashes, to form one logical line from
197 * several physical lines. No end of line character(s) are included in the
198 * result.
199 *
200 * If linenum is not NULL, it is incremented by the number of physical lines
201 * which have been read.
202 */
Lucas De Marchiaafd3832014-10-03 03:25:06 -0300203char *freadline_wrapped(FILE *fp, unsigned int *linenum)
Lucas De Marchi96573a02014-10-03 00:01:35 -0300204{
205 int size = 256;
206 int i = 0, n = 0;
207 _cleanup_free_ char *buf = malloc(size);
208
209 if (buf == NULL)
210 return NULL;
211
212 for(;;) {
213 int ch = getc_unlocked(fp);
214
215 switch(ch) {
216 case EOF:
217 if (i == 0)
218 return NULL;
219 /* else fall through */
220
221 case '\n':
222 n++;
223
224 {
225 char *ret;
226 if (i == size) {
227 ret = realloc(buf, size + 1);
228 if (!ret)
229 return NULL;
230 } else
231 ret = buf;
232 ret[i] = '\0';
233 buf = NULL;
234 if (linenum)
235 *linenum += n;
236 return ret;
237 }
238
239 case '\\':
240 ch = getc_unlocked(fp);
241
242 if (ch == '\n') {
243 n++;
244 continue;
245 }
246 /* else fall through */
247
248 default:
249 buf[i++] = ch;
250
251 if (i == size) {
252 char *tmp;
253 size *= 2;
254 tmp = realloc(buf, size);
255 if (!tmp)
256 return NULL;
257 buf = tmp;
258 }
259 }
260 }
261}
262
263/* path handling functions */
264/* ************************************************************************ */
265
266bool path_is_absolute(const char *p)
267{
268 assert(p != NULL);
269
270 return p[0] == '/';
271}
272
273char *path_make_absolute_cwd(const char *p)
274{
275 _cleanup_free_ char *cwd = NULL;
276 size_t plen, cwdlen;
277 char *r;
278
279 if (path_is_absolute(p))
280 return strdup(p);
281
282 cwd = get_current_dir_name();
283 if (!cwd)
284 return NULL;
285
286 plen = strlen(p);
287 cwdlen = strlen(cwd);
288
289 /* cwd + '/' + p + '\0' */
290 r = realloc(cwd, cwdlen + 1 + plen + 1);
291 if (r == NULL)
292 return NULL;
293
294 cwd = NULL;
295 r[cwdlen] = '/';
296 memcpy(&r[cwdlen + 1], p, plen + 1);
297
298 return r;
299}
300
301static inline int is_dir(const char *path)
302{
303 struct stat st;
304
305 if (stat(path, &st) >= 0)
306 return S_ISDIR(st.st_mode);
307
308 return -errno;
309}
310
311int mkdir_p(const char *path, int len, mode_t mode)
312{
313 char *start, *end;
314
315 start = strndupa(path, len);
316 end = start + len;
317
318 /*
319 * scan backwards, replacing '/' with '\0' while the component doesn't
320 * exist
321 */
322 for (;;) {
323 int r = is_dir(start);
324 if (r > 0) {
325 end += strlen(end);
326
327 if (end == start + len)
328 return 0;
329
330 /* end != start, since it would be caught on the first
331 * iteration */
332 *end = '/';
333 break;
334 } else if (r == 0)
335 return -ENOTDIR;
336
337 if (end == start)
338 break;
339
340 *end = '\0';
341
342 /* Find the next component, backwards, discarding extra '/'*/
343 while (end > start && *end != '/')
344 end--;
345
346 while (end > start && *(end - 1) == '/')
347 end--;
348 }
349
350 for (; end < start + len;) {
351 if (mkdir(start, mode) < 0 && errno != EEXIST)
352 return -errno;
353
354 end += strlen(end);
355 *end = '/';
356 }
357
358 return 0;
359}
360
361int mkdir_parents(const char *path, mode_t mode)
362{
363 char *end = strrchr(path, '/');
364
365 /* no parent directories */
366 if (end == NULL)
367 return 0;
368
369 return mkdir_p(path, end - path, mode);
370}
371
372unsigned long long ts_usec(const struct timespec *ts)
373{
374 return (unsigned long long) ts->tv_sec * USEC_PER_SEC +
375 (unsigned long long) ts->tv_nsec / NSEC_PER_USEC;
376}
377
378unsigned long long stat_mstamp(const struct stat *st)
379{
380#ifdef HAVE_STRUCT_STAT_ST_MTIM
381 return ts_usec(&st->st_mtim);
382#else
383 return (unsigned long long) st->st_mtime;
384#endif
385}